From a5e06cd02193afe24292a5ae21a9f7e663e2f176 Mon Sep 17 00:00:00 2001 From: Featyre Date: Sun, 23 Jan 2022 23:55:43 +0800 Subject: Partial integration of categories and discovery --- util/src/entities/Categories.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 util/src/entities/Categories.ts (limited to 'util/src/entities/Categories.ts') diff --git a/util/src/entities/Categories.ts b/util/src/entities/Categories.ts new file mode 100644 index 00000000..2cf89dbc --- /dev/null +++ b/util/src/entities/Categories.ts @@ -0,0 +1,36 @@ +import { PrimaryColumn, Column, Entity} from "typeorm"; +import { BaseClassWithoutId } from "./BaseClass"; + +// TODO: categories: +// [{ +// "id": 16, +// "default": "Anime & Manga", +// "localizations": { +// "de": "Anime & Manga", +// "fr": "Anim\u00e9s et mangas", +// "ru": "\u0410\u043d\u0438\u043c\u0435 \u0438 \u043c\u0430\u043d\u0433\u0430" +// } +// }, +// "is_primary": false/true +// }] + +@Entity("categories") +export class Categories extends BaseClassWithoutId { // Not using snowflake + + @PrimaryColumn() + id: number; + + @Column() + default: string; + + @Column({ type: "simple-json", nullable: false }) + localizations: string; + + @Column() + is_primary: boolean; + +} + +export interface DefaultCategoryValue { // TODO: Load Default Discord Categories + +} \ No newline at end of file -- cgit 1.5.1 From 5e868d431b431cc9f2a57efdbfa4d397e5188a3d Mon Sep 17 00:00:00 2001 From: Featyre Date: Mon, 24 Jan 2022 11:27:12 +0000 Subject: Prep for Category db work --- api/src/routes/discovery.ts | 2 +- util/src/entities/Categories.ts | 6 +----- util/src/util/Categories.ts | 1 + util/src/util/index.ts | 1 + 4 files changed, 4 insertions(+), 6 deletions(-) create mode 100644 util/src/util/Categories.ts (limited to 'util/src/entities/Categories.ts') diff --git a/api/src/routes/discovery.ts b/api/src/routes/discovery.ts index 067dd442..6c004274 100644 --- a/api/src/routes/discovery.ts +++ b/api/src/routes/discovery.ts @@ -5,7 +5,7 @@ const router = Router(); router.get("/categories", route({}), (req: Request, res: Response) => { // TODO: - // Load categories from db instead + // Load categories from db instead of hardcoding const { locale, primary_only } = req.query; diff --git a/util/src/entities/Categories.ts b/util/src/entities/Categories.ts index 2cf89dbc..1d272118 100644 --- a/util/src/entities/Categories.ts +++ b/util/src/entities/Categories.ts @@ -15,7 +15,7 @@ import { BaseClassWithoutId } from "./BaseClass"; // }] @Entity("categories") -export class Categories extends BaseClassWithoutId { // Not using snowflake +export class CategoryEntity extends BaseClassWithoutId { // Not using snowflake @PrimaryColumn() id: number; @@ -29,8 +29,4 @@ export class Categories extends BaseClassWithoutId { // Not using snowflake @Column() is_primary: boolean; -} - -export interface DefaultCategoryValue { // TODO: Load Default Discord Categories - } \ No newline at end of file diff --git a/util/src/util/Categories.ts b/util/src/util/Categories.ts new file mode 100644 index 00000000..a3c69da7 --- /dev/null +++ b/util/src/util/Categories.ts @@ -0,0 +1 @@ +//TODO: populate default discord categories + init, get and set methods \ No newline at end of file diff --git a/util/src/util/index.ts b/util/src/util/index.ts index 98e1146c..f7a273cb 100644 --- a/util/src/util/index.ts +++ b/util/src/util/index.ts @@ -1,6 +1,7 @@ export * from "./ApiError"; export * from "./BitField"; export * from "./Token"; +//export * from "./Categories"; export * from "./cdn"; export * from "./Config"; export * from "./Constants"; -- cgit 1.5.1 From b01a26cdceb2840b44da7033e2f6615a27273595 Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 26 Jan 2022 08:58:36 +0800 Subject: Dev portal + categories load db --- api/client_test/developers.html | 42 +++++++++++++++++++++++++++++++ api/src/middlewares/TestClient.ts | 9 +++++++ api/src/routes/applications/detectable.ts | 2 +- api/src/routes/applications/index.ts | 11 ++++++++ api/src/routes/discoverable-guilds.ts | 6 ++--- api/src/routes/discovery.ts | 21 +++------------- api/src/routes/experiments.ts | 2 +- api/src/routes/guild-recommendations.ts | 5 +++- api/src/routes/teams.ts | 11 ++++++++ util/src/entities/Categories.ts | 6 ++--- 10 files changed, 89 insertions(+), 26 deletions(-) create mode 100644 api/client_test/developers.html create mode 100644 api/src/routes/applications/index.ts create mode 100644 api/src/routes/teams.ts (limited to 'util/src/entities/Categories.ts') diff --git a/api/client_test/developers.html b/api/client_test/developers.html new file mode 100644 index 00000000..2a4402d7 --- /dev/null +++ b/api/client_test/developers.html @@ -0,0 +1,42 @@ + + + + + + + + + Discord Test Client Developer Portal + + + + +
+ + + + + + diff --git a/api/src/middlewares/TestClient.ts b/api/src/middlewares/TestClient.ts index 5c0b081b..ecf87681 100644 --- a/api/src/middlewares/TestClient.ts +++ b/api/src/middlewares/TestClient.ts @@ -83,6 +83,15 @@ export default function TestClient(app: Application) { return res.send(buffer); }); + app.get("/developers*", (req: Request, res: Response) => { + const { useTestClient } = Config.get().client; + res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24); + res.set("content-type", "text/html"); + + if(!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.") + + res.send(fs.readFileSync(path.join(__dirname, "..", "..", "client_test", "developers.html"), { encoding: "utf8" })); + }); app.get("*", (req: Request, res: Response) => { const { useTestClient } = Config.get().client; res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24); diff --git a/api/src/routes/applications/detectable.ts b/api/src/routes/applications/detectable.ts index 411e95bf..28ce42da 100644 --- a/api/src/routes/applications/detectable.ts +++ b/api/src/routes/applications/detectable.ts @@ -5,7 +5,7 @@ const router: Router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { //TODO - res.json([]).status(200); + res.send([]).status(200); }); export default router; diff --git a/api/src/routes/applications/index.ts b/api/src/routes/applications/index.ts new file mode 100644 index 00000000..28ce42da --- /dev/null +++ b/api/src/routes/applications/index.ts @@ -0,0 +1,11 @@ +import { Request, Response, Router } from "express"; +import { route } from "@fosscord/api"; + +const router: Router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + //TODO + res.send([]).status(200); +}); + +export default router; diff --git a/api/src/routes/discoverable-guilds.ts b/api/src/routes/discoverable-guilds.ts index df4448df..0aa2baa9 100644 --- a/api/src/routes/discoverable-guilds.ts +++ b/api/src/routes/discoverable-guilds.ts @@ -13,12 +13,10 @@ router.get("/", route({}), async (req: Request, res: Response) => { // TODO: implement this with default typeorm query // const guilds = await Guild.find({ where: { features: "DISCOVERABLE" } }); //, take: Math.abs(Number(limit)) }); let guilds; - let total; if (categories == undefined) { guilds = showAllGuilds ? await Guild.find({ take: Math.abs(Number(limit || configLimit)) }) : await Guild.find({ where: `"features" LIKE '%DISCOVERABLE%'`, take: Math.abs(Number(limit || configLimit)) }); - total = guilds.length; } else { guilds = showAllGuilds ? await Guild.find({ where: `"primary_category_id" = ${categories}`, take: Math.abs(Number(limit || configLimit)) }) @@ -26,8 +24,10 @@ router.get("/", route({}), async (req: Request, res: Response) => { where: `"primary_category_id" = ${categories} AND "features" LIKE '%DISCOVERABLE%'`, take: Math.abs(Number(limit || configLimit)) }); - total = guilds.length; } + + const total = guilds ? guilds.length : undefined; + res.send({ total: total, guilds: guilds, offset: Number(offset || Config.get().guild.discovery.offset), limit: Number(limit || configLimit) }); }); diff --git a/api/src/routes/discovery.ts b/api/src/routes/discovery.ts index b6a25a13..1991400e 100644 --- a/api/src/routes/discovery.ts +++ b/api/src/routes/discovery.ts @@ -1,29 +1,16 @@ +import { Categories } from "@fosscord/util"; import { Router, Response, Request } from "express"; import { route } from "@fosscord/api"; const router = Router(); -router.get("/categories", route({}), (req: Request, res: Response) => { +router.get("/categories", route({}), async (req: Request, res: Response) => { // TODO: - // Load categories from db instead of hardcoding + // Get locale instead const { locale, primary_only } = req.query; - let categories; - - let out; - - - - switch (locale) { - case "en-US": - switch (primary_only) { - case "false": - out = [{"id": 0, "is_primary": true, "name": "General"}, {"id": 10, "is_primary": true, "name": "Travel & Food"}, {"id": 15, "is_primary": false, "name": "Esports"}, {"id": 30, "is_primary": false, "name": "LFG"}, {"id": 32, "is_primary": false, "name": "Theorycraft"}, {"id": 36, "is_primary": false, "name": "Business"}, {"id": 39, "is_primary": false, "name": "Fandom"}, {"id": 43, "is_primary": true, "name": "Emoji"}, {"id": 18, "is_primary": false, "name": "Books"}, {"id": 23, "is_primary": false, "name": "Podcasts"}, {"id": 28, "is_primary": false, "name": "Investing"}, {"id": 7, "is_primary": true, "name": "Sports"}, {"id": 13, "is_primary": true, "name": "Other"}, {"id": 2, "is_primary": true, "name": "Music"}, {"id": 3, "is_primary": true, "name": "Entertainment"}, {"id": 4, "is_primary": true, "name": "Creative Arts"}, {"id": 6, "is_primary": true, "name": "Education"}, {"id": 9, "is_primary": true, "name": "Relationships & Identity"}, {"id": 11, "is_primary": true, "name": "Fitness & Health"}, {"id": 12, "is_primary": true, "name": "Finance"}, {"id": 45, "is_primary": false, "name": "Mobile"}, {"id": 16, "is_primary": false, "name": "Anime & Manga"}, {"id": 17, "is_primary": false, "name": "Movies & TV"}, {"id": 19, "is_primary": false, "name": "Art"}, {"id": 20, "is_primary": false, "name": "Writing"}, {"id": 22, "is_primary": false, "name": "Programming"}, {"id": 25, "is_primary": false, "name": "Memes"}, {"id": 27, "is_primary": false, "name": "Cryptocurrency"}, {"id": 31, "is_primary": false, "name": "Customer Support"}, {"id": 33, "is_primary": false, "name": "Events"}, {"id": 34, "is_primary": false, "name": "Roleplay"}, {"id": 37, "is_primary": false, "name": "Local Group"}, {"id": 38, "is_primary": false, "name": "Collaboration"}, {"id": 40, "is_primary": false, "name": "Wiki & Guide"}, {"id": 42, "is_primary": false, "name": "Subreddit"}, {"id": 1, "is_primary": true, "name": "Gaming"}, {"id": 5, "is_primary": true, "name": "Science & Tech"}, {"id": 8, "is_primary": true, "name": "Fashion & Beauty"}, {"id": 14, "is_primary": true, "name": "General Chatting"}, {"id": 21, "is_primary": false, "name": "Crafts, DIY, & Making"}, {"id": 48, "is_primary": false, "name": "Game Developer"}, {"id": 49, "is_primary": true, "name": "Bots"}, {"id": 24, "is_primary": false, "name": "Tabletop Games"}, {"id": 26, "is_primary": false, "name": "News & Current Events"}, {"id": 29, "is_primary": false, "name": "Studying & Teaching"}, {"id": 35, "is_primary": false, "name": "Content Creator"}, {"id": 44, "is_primary": false, "name": "Comics & Cartoons"}, {"id": 46, "is_primary": false, "name": "Console"}, {"id": 47, "is_primary": false, "name": "Charity & Nonprofit"}] - case "true": - out = [{"id": 0, "is_primary": true, "name": "General"}, {"id": 10, "is_primary": true, "name": "Travel & Food"}, {"id": 43, "is_primary": true, "name": "Emoji"}, {"id": 7, "is_primary": true, "name": "Sports"}, {"id": 13, "is_primary": true, "name": "Other"}, {"id": 2, "is_primary": true, "name": "Music"}, {"id": 3, "is_primary": true, "name": "Entertainment"}, {"id": 4, "is_primary": true, "name": "Creative Arts"}, {"id": 6, "is_primary": true, "name": "Education"}, {"id": 9, "is_primary": true, "name": "Relationships & Identity"}, {"id": 11, "is_primary": true, "name": "Fitness & Health"}, {"id": 12, "is_primary": true, "name": "Finance"}, {"id": 1, "is_primary": true, "name": "Gaming"}, {"id": 5, "is_primary": true, "name": "Science & Tech"}, {"id": 8, "is_primary": true, "name": "Fashion & Beauty"}, {"id": 14, "is_primary": true, "name": "General Chatting"}] - } - } + const out = primary_only ? await Categories.find() : await Categories.find({ where: `"is_primary" = "true"` }); res.send(out); }); diff --git a/api/src/routes/experiments.ts b/api/src/routes/experiments.ts index 966ed99c..7be86fb8 100644 --- a/api/src/routes/experiments.ts +++ b/api/src/routes/experiments.ts @@ -5,7 +5,7 @@ const router = Router(); router.get("/", route({}), (req: Request, res: Response) => { // TODO: - res.send({ fingerprint: "", assignments: [] }); + res.send({ fingerprint: "", assignments: [], guild_experiments:[] }); }); export default router; diff --git a/api/src/routes/guild-recommendations.ts b/api/src/routes/guild-recommendations.ts index 3e5b8f32..1432f39c 100644 --- a/api/src/routes/guild-recommendations.ts +++ b/api/src/routes/guild-recommendations.ts @@ -11,10 +11,13 @@ router.get("/", route({}), async (req: Request, res: Response) => { // ! this only works using SQL querys // TODO: implement this with default typeorm query // const guilds = await Guild.find({ where: { features: "DISCOVERABLE" } }); //, take: Math.abs(Number(limit)) }); + + const genLoadId = (size: Number) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join(''); + const guilds = showAllGuilds ? await Guild.find({ take: Math.abs(Number(limit || 24)) }) : await Guild.find({ where: `"features" LIKE '%DISCOVERABLE%'`, take: Math.abs(Number(limit || 24)) }); - res.send({ recommended_guilds: guilds }); + res.send({ recommended_guilds: guilds, load_id: `server_recs/${genLoadId(32)}`}).status(200); }); export default router; diff --git a/api/src/routes/teams.ts b/api/src/routes/teams.ts new file mode 100644 index 00000000..7ce3abcb --- /dev/null +++ b/api/src/routes/teams.ts @@ -0,0 +1,11 @@ +import { Request, Response, Router } from "express"; +import { route } from "@fosscord/api"; + +const router: Router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + //TODO + res.send([]); +}); + +export default router; diff --git a/util/src/entities/Categories.ts b/util/src/entities/Categories.ts index 1d272118..269e178f 100644 --- a/util/src/entities/Categories.ts +++ b/util/src/entities/Categories.ts @@ -15,15 +15,15 @@ import { BaseClassWithoutId } from "./BaseClass"; // }] @Entity("categories") -export class CategoryEntity extends BaseClassWithoutId { // Not using snowflake +export class Categories extends BaseClassWithoutId { // Not using snowflake @PrimaryColumn() id: number; @Column() - default: string; + name: string; - @Column({ type: "simple-json", nullable: false }) + @Column({ type: "simple-json" }) localizations: string; @Column() -- cgit 1.5.1 From fb5667e18c9175fdcdaab49f3035e0dfcd0fbc60 Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 2 Feb 2022 01:02:32 +0800 Subject: make everything in categories nullable --- util/src/entities/Categories.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'util/src/entities/Categories.ts') diff --git a/util/src/entities/Categories.ts b/util/src/entities/Categories.ts index 269e178f..18fc755d 100644 --- a/util/src/entities/Categories.ts +++ b/util/src/entities/Categories.ts @@ -17,16 +17,16 @@ import { BaseClassWithoutId } from "./BaseClass"; @Entity("categories") export class Categories extends BaseClassWithoutId { // Not using snowflake - @PrimaryColumn() + @PrimaryColumn({ nullable: true }) id: number; - @Column() + @Column({ nullable: true }) name: string; @Column({ type: "simple-json" }) localizations: string; - @Column() + @Column({ nullable: true }) is_primary: boolean; } \ No newline at end of file -- cgit 1.5.1 From 299b9b8d579da0f29b8be533be08e9fa7d50f147 Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 2 Feb 2022 01:06:42 +0800 Subject: Fix primarycolum being assigned to nullable = true --- util/src/entities/Categories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util/src/entities/Categories.ts') diff --git a/util/src/entities/Categories.ts b/util/src/entities/Categories.ts index 18fc755d..a3c1280f 100644 --- a/util/src/entities/Categories.ts +++ b/util/src/entities/Categories.ts @@ -17,7 +17,7 @@ import { BaseClassWithoutId } from "./BaseClass"; @Entity("categories") export class Categories extends BaseClassWithoutId { // Not using snowflake - @PrimaryColumn({ nullable: true }) + @PrimaryColumn() id: number; @Column({ nullable: true }) -- cgit 1.5.1 From 7b3531cb9015ec5bdf95c97b726d5d64f2ca41fa Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 2 Feb 2022 02:09:57 +0800 Subject: Return none for dev portal + todo for categories --- api/src/routes/users/@me/guilds.ts | 8 +++++++- util/src/entities/Categories.ts | 1 + util/src/entities/Guild.ts | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'util/src/entities/Categories.ts') diff --git a/api/src/routes/users/@me/guilds.ts b/api/src/routes/users/@me/guilds.ts index 22a2c04c..754a240e 100644 --- a/api/src/routes/users/@me/guilds.ts +++ b/api/src/routes/users/@me/guilds.ts @@ -8,7 +8,13 @@ const router: Router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { const members = await Member.find({ relations: ["guild"], where: { id: req.user_id } }); - res.json(members.map((x) => x.guild)); + let guild = members.map((x) => x.guild); + + if ("with_counts" in req.query && req.query.with_counts == "true") { + guild = []; // TODO: Load guilds with user role permissions number + } + + res.json(guild); }); // user send to leave a certain guild diff --git a/util/src/entities/Categories.ts b/util/src/entities/Categories.ts index a3c1280f..81fbc303 100644 --- a/util/src/entities/Categories.ts +++ b/util/src/entities/Categories.ts @@ -13,6 +13,7 @@ import { BaseClassWithoutId } from "./BaseClass"; // }, // "is_primary": false/true // }] +// Also populate discord default categories @Entity("categories") export class Categories extends BaseClassWithoutId { // Not using snowflake diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts index 18fa7a0a..9ac148ee 100644 --- a/util/src/entities/Guild.ts +++ b/util/src/entities/Guild.ts @@ -270,6 +270,9 @@ export class Guild extends BaseClass { @Column({ nullable: true }) nsfw?: boolean; + // only for developer portal + permissions?: number; + static async createGuild(body: { name?: string; icon?: string | null; -- cgit 1.5.1