Skip to content

Commit 3674c6f

Browse files
feat: Add missing tags field to announcements (#213)
Co-authored-by: mostafaNazari702 <nazarimostafa2006@gmail.com>
1 parent fc5ddab commit 3674c6f

10 files changed

Lines changed: 358 additions & 73 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CREATE TABLE `announcement_tags` (
2+
`announcement_id` integer NOT NULL,
3+
`tag_id` integer NOT NULL,
4+
PRIMARY KEY(`announcement_id`, `tag_id`),
5+
FOREIGN KEY (`announcement_id`) REFERENCES `announcements`(`id`) ON UPDATE no action ON DELETE cascade,
6+
FOREIGN KEY (`tag_id`) REFERENCES `tags`(`id`) ON UPDATE no action ON DELETE cascade
7+
);
8+
--> statement-breakpoint
9+
CREATE TABLE `tags` (
10+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
11+
`name` text NOT NULL
12+
);
13+
--> statement-breakpoint
14+
CREATE UNIQUE INDEX `tags_name_unique` ON `tags` (`name`);
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
{
2+
"version": "6",
3+
"dialect": "sqlite",
4+
"id": "7d6e4138-b731-4824-828d-3a9def6e38cb",
5+
"prevId": "00000000-0000-0000-0000-000000000000",
6+
"tables": {
7+
"announcement_tags": {
8+
"name": "announcement_tags",
9+
"columns": {
10+
"announcement_id": {
11+
"name": "announcement_id",
12+
"type": "integer",
13+
"primaryKey": false,
14+
"notNull": true,
15+
"autoincrement": false
16+
},
17+
"tag_id": {
18+
"name": "tag_id",
19+
"type": "integer",
20+
"primaryKey": false,
21+
"notNull": true,
22+
"autoincrement": false
23+
}
24+
},
25+
"indexes": {},
26+
"foreignKeys": {
27+
"announcement_tags_announcement_id_announcements_id_fk": {
28+
"name": "announcement_tags_announcement_id_announcements_id_fk",
29+
"tableFrom": "announcement_tags",
30+
"tableTo": "announcements",
31+
"columnsFrom": [
32+
"announcement_id"
33+
],
34+
"columnsTo": [
35+
"id"
36+
],
37+
"onDelete": "cascade",
38+
"onUpdate": "no action"
39+
},
40+
"announcement_tags_tag_id_tags_id_fk": {
41+
"name": "announcement_tags_tag_id_tags_id_fk",
42+
"tableFrom": "announcement_tags",
43+
"tableTo": "tags",
44+
"columnsFrom": [
45+
"tag_id"
46+
],
47+
"columnsTo": [
48+
"id"
49+
],
50+
"onDelete": "cascade",
51+
"onUpdate": "no action"
52+
}
53+
},
54+
"compositePrimaryKeys": {
55+
"announcement_tags_announcement_id_tag_id_pk": {
56+
"columns": [
57+
"announcement_id",
58+
"tag_id"
59+
],
60+
"name": "announcement_tags_announcement_id_tag_id_pk"
61+
}
62+
},
63+
"uniqueConstraints": {},
64+
"checkConstraints": {}
65+
},
66+
"announcements": {
67+
"name": "announcements",
68+
"columns": {
69+
"id": {
70+
"name": "id",
71+
"type": "integer",
72+
"primaryKey": true,
73+
"notNull": true,
74+
"autoincrement": true
75+
},
76+
"author": {
77+
"name": "author",
78+
"type": "text",
79+
"primaryKey": false,
80+
"notNull": false,
81+
"autoincrement": false
82+
},
83+
"title": {
84+
"name": "title",
85+
"type": "text",
86+
"primaryKey": false,
87+
"notNull": true,
88+
"autoincrement": false
89+
},
90+
"content": {
91+
"name": "content",
92+
"type": "text",
93+
"primaryKey": false,
94+
"notNull": false,
95+
"autoincrement": false
96+
},
97+
"created_at": {
98+
"name": "created_at",
99+
"type": "text",
100+
"primaryKey": false,
101+
"notNull": true,
102+
"autoincrement": false
103+
},
104+
"archived_at": {
105+
"name": "archived_at",
106+
"type": "text",
107+
"primaryKey": false,
108+
"notNull": false,
109+
"autoincrement": false
110+
},
111+
"level": {
112+
"name": "level",
113+
"type": "integer",
114+
"primaryKey": false,
115+
"notNull": true,
116+
"autoincrement": false,
117+
"default": 0
118+
}
119+
},
120+
"indexes": {},
121+
"foreignKeys": {},
122+
"compositePrimaryKeys": {},
123+
"uniqueConstraints": {},
124+
"checkConstraints": {}
125+
},
126+
"tags": {
127+
"name": "tags",
128+
"columns": {
129+
"id": {
130+
"name": "id",
131+
"type": "integer",
132+
"primaryKey": true,
133+
"notNull": true,
134+
"autoincrement": true
135+
},
136+
"name": {
137+
"name": "name",
138+
"type": "text",
139+
"primaryKey": false,
140+
"notNull": true,
141+
"autoincrement": false
142+
}
143+
},
144+
"indexes": {
145+
"tags_name_unique": {
146+
"name": "tags_name_unique",
147+
"columns": [
148+
"name"
149+
],
150+
"isUnique": true
151+
}
152+
},
153+
"foreignKeys": {},
154+
"compositePrimaryKeys": {},
155+
"uniqueConstraints": {},
156+
"checkConstraints": {}
157+
}
158+
},
159+
"views": {},
160+
"enums": {},
161+
"_meta": {
162+
"schemas": {},
163+
"tables": {},
164+
"columns": {}
165+
},
166+
"internal": {
167+
"indexes": {}
168+
}
169+
}

drizzle/migrations/meta/_journal.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88
"when": 1740700800000,
99
"tag": "0000_initial",
1010
"breakpoints": true
11+
},
12+
{
13+
"idx": 1,
14+
"version": "6",
15+
"when": 1773076587551,
16+
"tag": "0001_announcement_tags",
17+
"breakpoints": true
1118
}
1219
]
13-
}
20+
}

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@
2525
"zod": "^4.3.6"
2626
},
2727
"devDependencies": {
28-
"@cloudflare/workers-types": "^4.20260305.1",
28+
"@cloudflare/workers-types": "^4.20260307.1",
2929
"@kilianpaquier/semantic-release-backmerge": "^1.7.1",
3030
"@semantic-release/changelog": "^6.0.3",
3131
"@semantic-release/git": "^10.0.1",
3232
"@semantic-release/npm": "^13.1.5",
33-
"@types/node": "^25.3.3",
33+
"@types/node": "^25.3.5",
3434
"drizzle-kit": "^0.31.9",
3535
"semantic-release": "^25.0.3",
36-
"typescript": "^5.7.0",
37-
"wrangler": "^4.70.0"
36+
"typescript": "^5.9.3",
37+
"wrangler": "^4.71.0"
3838
}
3939
}

src/db/schema.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
1+
import { sqliteTable, integer, text, primaryKey } from "drizzle-orm/sqlite-core";
22

33
export const announcements = sqliteTable("announcements", {
44
id: integer("id").primaryKey({ autoIncrement: true }),
@@ -11,3 +11,23 @@ export const announcements = sqliteTable("announcements", {
1111
archivedAt: text("archived_at"),
1212
level: integer("level").notNull().default(0),
1313
});
14+
15+
export const tags = sqliteTable("tags", {
16+
id: integer("id").primaryKey({ autoIncrement: true }),
17+
name: text("name").notNull().unique(),
18+
});
19+
20+
export const announcementTags = sqliteTable(
21+
"announcement_tags",
22+
{
23+
announcementId: integer("announcement_id")
24+
.notNull()
25+
.references(() => announcements.id, { onDelete: "cascade" }),
26+
tagId: integer("tag_id")
27+
.notNull()
28+
.references(() => tags.id, { onDelete: "cascade" }),
29+
},
30+
(table) => ({
31+
pk: primaryKey({ columns: [table.announcementId, table.tagId] }),
32+
}),
33+
);

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { swaggerUI } from "@hono/swagger-ui";
33
import type { Env } from "./types";
44
import { cacheControl, CacheDuration } from "./cache";
55
import { getConfig } from "./config";
6-
76
import packageJson from "../package.json";
87
import patchesApp from "./routes/patches";
98
import managerApp from "./routes/manager";

src/schemas/announcements.ts

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ export const AnnouncementResponseSchema = z
1717
author: z.string().nullable().openapi({ example: "ReVanced" }),
1818
title: z.string().openapi({ example: "Welcome" }),
1919
content: z.string().nullable().openapi({ example: "Some content" }),
20-
created_at: z
21-
.string()
20+
tags: z.array(z.string()).openapi({ example: ["Important"] }),
21+
created_at: z.iso
2222
.datetime()
23-
.openapi({ example: "2024-01-01T00:00:00.000Z" }),
24-
archived_at: z.string().datetime().nullable().openapi({ example: null }),
23+
.openapi({ example: "1970-01-01T00:00:00.000Z" }),
24+
archived_at: z.iso.datetime().nullable().openapi({ example: null }),
2525
level: z.number().int().openapi({ example: 0 }),
2626
})
2727
.openapi("Announcement");
@@ -33,17 +33,12 @@ export const CreateAnnouncementBodySchema = z
3333
author: z.string().optional().openapi({ example: "ReVanced" }),
3434
title: z.string().openapi({ example: "Welcome" }),
3535
content: z.string().optional().openapi({ example: "Some content" }),
36-
created_at: z
37-
.string()
38-
.datetime()
39-
.nullable()
40-
.optional()
41-
.openapi({
42-
example: "2024-01-01T00:00:00.000Z",
43-
description: "UTC timestamp. Defaults to current time if omitted.",
44-
}),
45-
archived_at: z
46-
.string()
36+
tags: z.array(z.string()).openapi({ example: ["Important"] }),
37+
created_at: z.string().datetime().nullable().optional().openapi({
38+
example: "1970-01-01T00:00:00.000Z",
39+
description: "UTC timestamp. Defaults to current time if omitted.",
40+
}),
41+
archived_at: z.iso
4742
.datetime()
4843
.nullable()
4944
.optional()
@@ -57,17 +52,12 @@ export const UpdateAnnouncementBodySchema = z
5752
author: z.string().optional().openapi({ example: "ReVanced" }),
5853
title: z.string().openapi({ example: "Welcome" }),
5954
content: z.string().optional().openapi({ example: "Some content" }),
60-
created_at: z
61-
.string()
62-
.datetime()
63-
.nullable()
64-
.optional()
65-
.openapi({
66-
example: "2024-01-01T00:00:00.000Z",
67-
description: "UTC timestamp.",
68-
}),
69-
archived_at: z
70-
.string()
55+
tags: z.array(z.string()).openapi({ example: ["Important"] }),
56+
created_at: z.iso.datetime().nullable().optional().openapi({
57+
example: "1970-01-01T00:00:00.000Z",
58+
description: "UTC timestamp.",
59+
}),
60+
archived_at: z.iso
7161
.datetime()
7262
.nullable()
7363
.optional()

src/schemas/contributors.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { z } from "@hono/zod-openapi";
22

33
export const ContributorSchema = z.object({
44
name: z.string().openapi({ example: "oSumAtrIX" }),
5-
avatar_url: z.string().url().openapi({ example: "https://avatars.githubusercontent.com/u/..." }),
6-
url: z.string().url().openapi({ example: "https://github.com/oSumAtrIX" }),
5+
avatar_url: z.url().openapi({ example: "https://avatars.githubusercontent.com/u/..." }),
6+
url: z.url().openapi({ example: "https://github.com/oSumAtrIX" }),
77
contributions: z.number().int().openapi({ example: 542 }),
88
});
99

1010
export const ContributableSchema = z
1111
.object({
1212
name: z.string().openapi({ example: "ReVanced Patches" }),
13-
url: z.string().url().openapi({ example: "https://github.com/revanced/revanced-patches" }),
13+
url: z.url().openapi({ example: "https://github.com/revanced/revanced-patches" }),
1414
contributors: z.array(ContributorSchema),
1515
})
1616
.openapi("Contributable");
@@ -20,15 +20,15 @@ export const ContributorsResponseSchema = z.array(ContributableSchema);
2020
export const GpgKeySchema = z
2121
.object({
2222
id: z.string().openapi({ example: "ABC123DEF456" }),
23-
url: z.string().url().openapi({ example: "https://github.com/oSumAtrIX.gpg" }),
23+
url: z.url().openapi({ example: "https://github.com/oSumAtrIX.gpg" }),
2424
})
2525
.nullable();
2626

2727
export const TeamMemberSchema = z
2828
.object({
2929
name: z.string().openapi({ example: "oSumAtrIX" }),
30-
avatar_url: z.string().url().openapi({ example: "https://avatars.githubusercontent.com/u/..." }),
31-
url: z.string().url().openapi({ example: "https://github.com/oSumAtrIX" }),
30+
avatar_url: z.url().openapi({ example: "https://avatars.githubusercontent.com/u/..." }),
31+
url: z.url().openapi({ example: "https://github.com/oSumAtrIX" }),
3232
bio: z.string().nullable().openapi({ example: "Some bio text" }),
3333
gpg_key: GpgKeySchema,
3434
})

src/schemas/releases.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { z } from "@hono/zod-openapi";
33
export const ReleaseResponseSchema = z
44
.object({
55
version: z.string().openapi({ example: "v4.0.0" }),
6-
created_at: z.string().openapi({ example: "2025-01-15T10:30:00" }),
6+
created_at: z.iso.datetime().openapi({ example: "1970-01-01T00:00:00.000Z" }),
77
description: z.string().openapi({ example: "Release notes markdown here..." }),
88
download_url: z.string().url().openapi({
99
example:
@@ -30,7 +30,7 @@ export const VersionResponseSchema = z
3030
export const ReleaseSimpleSchema = z
3131
.object({
3232
version: z.string().openapi({ example: "v4.0.0" }),
33-
created_at: z.string().openapi({ example: "2025-01-15T10:30:00" }),
33+
created_at: z.iso.datetime().openapi({ example: "1970-01-01T00:00:00.000Z" }),
3434
description: z.string().openapi({ example: "Release notes markdown here..." }),
3535
})
3636
.openapi("ReleaseSimple");

0 commit comments

Comments
 (0)