From ec3d342e8eee6cf6ebf616ebde49bede83230d0f Mon Sep 17 00:00:00 2001 From: Featyre Date: Sun, 23 Jan 2022 02:03:14 +0800 Subject: [PATCH 01/21] Branding updates --- api/assets/fosscord-login.css | 6 +++--- api/assets/fosscord.css | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/assets/fosscord-login.css b/api/assets/fosscord-login.css index bc32b82e..34cf542b 100644 --- a/api/assets/fosscord-login.css +++ b/api/assets/fosscord-login.css @@ -22,10 +22,10 @@ h3.title-jXR8lp.marginBottom8-AtZOdT.base-1x0h_U.size24-RIRrxO::after { /* Logo in top left when bg removed */ #app-mount > div.app-1q1i1E > div > a { /* replace me: original dimensions: 130x36 */ - background: url(https://raw.githubusercontent.com/fosscord/fosscord/9900329e5ef2c17bdeb6893e04c0511f72027f97/assets/logo/temp.svg); + background: url(https://raw.githubusercontent.com/fosscord/fosscord/master/assets-rebrand/svg/Fosscord-Wordmark-Gradient.svg); + width: 130px; + height: 23px; background-size: contain; - width: 128px; - height: 128px; border-radius: 50%; } diff --git a/api/assets/fosscord.css b/api/assets/fosscord.css index 6a8b4c64..6078fdeb 100644 --- a/api/assets/fosscord.css +++ b/api/assets/fosscord.css @@ -13,10 +13,14 @@ /* home button icon */ #app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div { - background-image: url(https://raw.githubusercontent.com/fosscord/fosscord/9900329e5ef2c17bdeb6893e04c0511f72027f97/assets/logo/temp.svg); + background-image: url(https://raw.githubusercontent.com/fosscord/fosscord/master/assets-rebrand/svg/Fosscord-Icon-Rounded-Subtract.svg); background-size: contain; border-radius: 50%; } + +#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div, #app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div:hover { + background-color: white; +} /* Login QR */ #app-mount > div.app-1q1i1E > div > div > div > div > form > div > div > div.transitionGroup-aR7y1d.qrLogin-1AOZMt, #app-mount > div.app-1q1i1E > div > div > div > div > form > div > div > div.verticalSeparator-3huAjp, From 7ba65f8f669b957290411ad1513cd2da0923cabd Mon Sep 17 00:00:00 2001 From: Featyre Date: Sun, 23 Jan 2022 23:55:43 +0800 Subject: [PATCH 02/21] Partial integration of categories and discovery --- api/src/routes/categories.ts | 27 ++++++++++++++++++ api/src/routes/discoverable-guilds.ts | 21 ++++++++++---- api/src/routes/discovery.ts | 12 -------- api/src/routes/guild-recommendations.ts | 6 ++-- bundle/package-lock.json | Bin 606883 -> 606977 bytes bundle/package.json | 2 +- util/src/entities/Categories.ts | 36 ++++++++++++++++++++++++ util/src/entities/Config.ts | 2 ++ util/src/entities/Guild.ts | 26 +++-------------- util/src/entities/index.ts | 1 + 10 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 api/src/routes/categories.ts delete mode 100644 api/src/routes/discovery.ts create mode 100644 util/src/entities/Categories.ts diff --git a/api/src/routes/categories.ts b/api/src/routes/categories.ts new file mode 100644 index 00000000..58322676 --- /dev/null +++ b/api/src/routes/categories.ts @@ -0,0 +1,27 @@ +import { Router, Response, Request } from "express"; +import { route } from "@fosscord/api"; + +const router = Router(); + +router.get("/", route({}), (req: Request, res: Response) => { + // TODO: + // Load categories from db instead + + const { locale, primary_only } = req.query; + + 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"}] + } + } + + res.json(out).status(200); +}); + +export default router; diff --git a/api/src/routes/discoverable-guilds.ts b/api/src/routes/discoverable-guilds.ts index 1cf56f84..a4559b59 100644 --- a/api/src/routes/discoverable-guilds.ts +++ b/api/src/routes/discoverable-guilds.ts @@ -6,15 +6,26 @@ import { route } from "@fosscord/api"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const { limit } = req.params; + const { limit, categories } = req.query; var showAllGuilds = Config.get().guild.showAllGuildsInDiscovery; // ! 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 guilds = showAllGuilds - ? await Guild.find({ take: Math.abs(Number(limit || 20)) }) - : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 20)) }); - res.send({ guilds: guilds }); + let guilds; + let total; + switch (categories) { + case "1": + guilds = showAllGuilds + ? await Guild.find({ take: Math.abs(Number(limit || 24)) }) + : await Guild.find({ where: `"primary_category_id" = 1 AND "features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 24)) }); + total = guilds.length; + default: + guilds = showAllGuilds + ? await Guild.find({ take: Math.abs(Number(limit || 24)) }) + : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 24)) }); + total = guilds.length; + } + res.send({ total: total, guilds: guilds, offset: 0, limit: limit}); }); export default router; diff --git a/api/src/routes/discovery.ts b/api/src/routes/discovery.ts deleted file mode 100644 index bc495d42..00000000 --- a/api/src/routes/discovery.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Router, Response, Request } from "express"; -import { route } from "@fosscord/api"; - -const router = Router(); - -router.get("/categories", route({}), (req: Request, res: Response) => { - // TODO: - //const { locale, primary_only } = req.query; - res.json([]).status(200); -}); - -export default router; diff --git a/api/src/routes/guild-recommendations.ts b/api/src/routes/guild-recommendations.ts index 503b19b7..47017a6f 100644 --- a/api/src/routes/guild-recommendations.ts +++ b/api/src/routes/guild-recommendations.ts @@ -6,14 +6,14 @@ import { route } from "@fosscord/api"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const { limit, personalization_disabled } = req.params; + const { limit, personalization_disabled } = req.query; var showAllGuilds = Config.get().guild.showAllGuildsInDiscovery; // ! 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 guilds = showAllGuilds - ? await Guild.find({ take: Math.abs(Number(limit || 20)) }) - : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 100)) }); + ? await Guild.find({ take: Math.abs(Number(limit || 24)) }) + : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 24)) }); res.send({ recommended_guilds: guilds }); }); diff --git a/bundle/package-lock.json b/bundle/package-lock.json index e8b99037923888c5a45a3d5e0cb11678489edec6..e763f22a3fc8706aa6b04ce832392d76bb8ccab3 100644 GIT binary patch delta 186 zcmZ47s@mA5x`B^-VxW0q%z%3 zi;aD<0lU-WdPdIavn<$Rx1X?L>t)=$fp-}T$b{sSyonPvS;0Cc3%aOJe_+R!w^=~= z9WzjtJw34`wLGyBryY|OHRYP)#M|S<8G)Dyh?#+y1&CRJm<@>8ftX`^oH(beHUPm2 BI~4!` delta 169 zcmZo{Q(fGux`B^-`rI?j+|v_2GV)A+F2E!^IgXo~*)!OAa$=C&bOjD3_Q`(iY?BSx zouvKm1E*Nr^&auRX6(xzhj<$ qo0S!;2*d2=J>u Date: Mon, 24 Jan 2022 07:21:48 +0000 Subject: [PATCH 03/21] category + discovery + custom status fix, new config --- api/assets/fosscord-login.css | 1 - api/src/routes/discoverable-guilds.ts | 29 ++++++++++-------- .../routes/{categories.ts => discovery.ts} | 4 +-- api/src/routes/guild-recommendations.ts | 2 +- bundle/package-lock.json | Bin 607272 -> 607272 bytes bundle/package.json | 2 +- gateway/package.json | 2 +- util/src/entities/Config.ts | 16 +++++++--- util/src/entities/Guild.ts | 2 +- util/src/entities/User.ts | 9 ++---- 10 files changed, 36 insertions(+), 31 deletions(-) rename api/src/routes/{categories.ts => discovery.ts} (97%) diff --git a/api/assets/fosscord-login.css b/api/assets/fosscord-login.css index 34cf542b..d507c545 100644 --- a/api/assets/fosscord-login.css +++ b/api/assets/fosscord-login.css @@ -26,7 +26,6 @@ h3.title-jXR8lp.marginBottom8-AtZOdT.base-1x0h_U.size24-RIRrxO::after { width: 130px; height: 23px; background-size: contain; - border-radius: 50%; } /* replace TOS text */ diff --git a/api/src/routes/discoverable-guilds.ts b/api/src/routes/discoverable-guilds.ts index a4559b59..8b7d343f 100644 --- a/api/src/routes/discoverable-guilds.ts +++ b/api/src/routes/discoverable-guilds.ts @@ -6,26 +6,29 @@ import { route } from "@fosscord/api"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const { limit, categories } = req.query; - var showAllGuilds = Config.get().guild.showAllGuildsInDiscovery; + const { offset, limit, categories } = req.query; + var showAllGuilds = Config.get().guild.discovery.showAllGuilds; + var configLimit = Config.get().guild.discovery.limit; // ! 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)) }); let guilds; let total; - switch (categories) { - case "1": - guilds = showAllGuilds - ? await Guild.find({ take: Math.abs(Number(limit || 24)) }) - : await Guild.find({ where: `"primary_category_id" = 1 AND "features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 24)) }); - total = guilds.length; - default: - guilds = showAllGuilds - ? await Guild.find({ take: Math.abs(Number(limit || 24)) }) - : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 24)) }); + if (categories == undefined) { + guilds = showAllGuilds + ? await Guild.find({ take: Math.abs(Number(limit || configLimit)) }) + : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, 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)) }) + : await Guild.find({ + where: `"primary_category_id" = ${categories} AND "features" LIKE '%COMMUNITY%'`, + take: Math.abs(Number(limit || configLimit)) + }); total = guilds.length; } - res.send({ total: total, guilds: guilds, offset: 0, limit: limit}); + res.send({ total: total, guilds: guilds, offset: Number(offset || Config.get().guild.discovery.offset), limit: Number(limit || configLimit) }); }); export default router; diff --git a/api/src/routes/categories.ts b/api/src/routes/discovery.ts similarity index 97% rename from api/src/routes/categories.ts rename to api/src/routes/discovery.ts index 58322676..067dd442 100644 --- a/api/src/routes/categories.ts +++ b/api/src/routes/discovery.ts @@ -3,7 +3,7 @@ import { route } from "@fosscord/api"; const router = Router(); -router.get("/", route({}), (req: Request, res: Response) => { +router.get("/categories", route({}), (req: Request, res: Response) => { // TODO: // Load categories from db instead @@ -21,7 +21,7 @@ router.get("/", route({}), (req: Request, res: Response) => { } } - res.json(out).status(200); + res.send(out); }); export default router; diff --git a/api/src/routes/guild-recommendations.ts b/api/src/routes/guild-recommendations.ts index 47017a6f..ecc5e546 100644 --- a/api/src/routes/guild-recommendations.ts +++ b/api/src/routes/guild-recommendations.ts @@ -7,7 +7,7 @@ const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { const { limit, personalization_disabled } = req.query; - var showAllGuilds = Config.get().guild.showAllGuildsInDiscovery; + var showAllGuilds = Config.get().guild.discovery.showAllGuilds; // ! 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)) }); diff --git a/bundle/package-lock.json b/bundle/package-lock.json index d026e7c7785fe4ff8a10d165315f79892d994f10..573d40598c29a2dafcaf115e83fc172a85d6973d 100644 GIT binary patch delta 88 zcmZ3{p}L|&bwd#=qtWJKR%u~YBRw-cqsb3hRhxH6wC|8$1Y#y2W(HywAZFdZLxOFw dE<)M#@N+EulY6*y+7Gy~0Wtgb18y7{e*qVk9(Mo$ delta 86 zcmZ3{p}L|&bwd&BWPMT2&DE^J!jr4`_$I$%m1*7~(Y`~15r~<9m>Gy!fS7gr4hgo! ex-do4!_TqsPwwH;X+Pk`2E^>!54dq;`~?6uFCTya diff --git a/bundle/package.json b/bundle/package.json index 071a4899..75827521 100644 --- a/bundle/package.json +++ b/bundle/package.json @@ -91,7 +91,7 @@ "missing-native-js-functions": "^1.2.18", "morgan": "^1.10.0", "multer": "^1.4.2", - "node-fetch": "^2.6.7", + "node-fetch": "^2.6.2", "node-os-utils": "^1.3.5", "patch-package": "^6.4.7", "pg": "^8.7.1", diff --git a/gateway/package.json b/gateway/package.json index 7daddfc0..6d0d2d1c 100644 --- a/gateway/package.json +++ b/gateway/package.json @@ -32,7 +32,7 @@ "jsonwebtoken": "^8.5.1", "lambert-server": "^1.2.11", "missing-native-js-functions": "^1.2.18", - "node-fetch": "^3.1.1", + "node-fetch": "^2.6.2", "proxy-agent": "^5.0.0", "typeorm": "^0.2.37", "ws": "^7.4.2" diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts index 4da65b36..f4a266dc 100644 --- a/util/src/entities/Config.ts +++ b/util/src/entities/Config.ts @@ -157,8 +157,12 @@ export interface ConfigValue { available: Region[]; }; guild: { - showAllGuildsInDiscovery: boolean; - homeDiscoveryUseRecommendation: boolean; // TODO: Recommendation, privacy concern? + discovery: { + showAllGuilds: boolean; + useRecommendation: boolean; // TODO: Recommendation, privacy concern? + offset: number; + limit: number; + }; autoJoin: { enabled: boolean; guilds: string[]; @@ -354,8 +358,12 @@ export const DefaultConfigOptions: ConfigValue = { ], }, guild: { - showAllGuildsInDiscovery: false, - homeDiscoveryUseRecommendation: false, + discovery: { + showAllGuilds: false, + useRecommendation: false, + offset: 0, + limit: 24, + }, autoJoin: { enabled: true, canLeave: true, diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts index 65ba2ae2..18fa7a0a 100644 --- a/util/src/entities/Guild.ts +++ b/util/src/entities/Guild.ts @@ -287,7 +287,7 @@ export class Guild extends BaseClass { default_message_notifications: 1, // defaults effect: setting the push default at mentions-only will save a lot explicit_content_filter: 0, features: [], - primary_category_id: 0, + primary_category_id: null, id: guild_id, max_members: 250000, max_presences: 250000, diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts index 5f2618e0..1027331a 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts @@ -289,12 +289,7 @@ export const defaultSettings: UserSettings = { animate_stickers: 0, contact_sync_enabled: false, convert_emoticons: false, - custom_status: { - emoji_id: undefined, - emoji_name: undefined, - expires_at: undefined, - text: undefined, - }, + custom_status: null, default_guilds_restricted: false, detect_platform_accounts: true, developer_mode: false, @@ -334,7 +329,7 @@ export interface UserSettings { emoji_name?: string; expires_at?: number; text?: string; - }; + } | null; default_guilds_restricted: boolean; detect_platform_accounts: boolean; developer_mode: boolean; From dc3fb1f519e1f2fec7a8bc1117b616e7ccdee585 Mon Sep 17 00:00:00 2001 From: Featyre Date: Mon, 24 Jan 2022 11:27:12 +0000 Subject: [PATCH 04/21] 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 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"; From 858a885b0c71507fc6e9b279f01237bff423843c Mon Sep 17 00:00:00 2001 From: Featyre Date: Mon, 24 Jan 2022 22:59:14 +0800 Subject: [PATCH 05/21] Partnet + Discover fix and join --- api/src/routes/discoverable-guilds.ts | 4 +- api/src/routes/discovery.ts | 4 ++ api/src/routes/guild-recommendations.ts | 2 +- .../#guild_id/discovery-requirements.ts | 39 ++++++++++++++++++ api/src/routes/guilds/#guild_id/index.ts | 2 +- .../#guild_id/members/#member_id/index.ts | 21 ++++++++-- .../routes/partners/#guild_id/requirements.ts | 40 +++++++++++++++++++ api/src/util/handlers/route.ts | 2 +- 8 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 api/src/routes/guilds/#guild_id/discovery-requirements.ts create mode 100644 api/src/routes/partners/#guild_id/requirements.ts diff --git a/api/src/routes/discoverable-guilds.ts b/api/src/routes/discoverable-guilds.ts index 8b7d343f..df4448df 100644 --- a/api/src/routes/discoverable-guilds.ts +++ b/api/src/routes/discoverable-guilds.ts @@ -17,13 +17,13 @@ router.get("/", route({}), async (req: Request, res: Response) => { if (categories == undefined) { guilds = showAllGuilds ? await Guild.find({ take: Math.abs(Number(limit || configLimit)) }) - : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, 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)) }) : await Guild.find({ - where: `"primary_category_id" = ${categories} AND "features" LIKE '%COMMUNITY%'`, + where: `"primary_category_id" = ${categories} AND "features" LIKE '%DISCOVERABLE%'`, take: Math.abs(Number(limit || configLimit)) }); total = guilds.length; diff --git a/api/src/routes/discovery.ts b/api/src/routes/discovery.ts index 6c004274..b6a25a13 100644 --- a/api/src/routes/discovery.ts +++ b/api/src/routes/discovery.ts @@ -9,8 +9,12 @@ router.get("/categories", route({}), (req: Request, res: Response) => { const { locale, primary_only } = req.query; + let categories; + let out; + + switch (locale) { case "en-US": switch (primary_only) { diff --git a/api/src/routes/guild-recommendations.ts b/api/src/routes/guild-recommendations.ts index ecc5e546..3e5b8f32 100644 --- a/api/src/routes/guild-recommendations.ts +++ b/api/src/routes/guild-recommendations.ts @@ -13,7 +13,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { // const guilds = await Guild.find({ where: { features: "DISCOVERABLE" } }); //, take: Math.abs(Number(limit)) }); const guilds = showAllGuilds ? await Guild.find({ take: Math.abs(Number(limit || 24)) }) - : await Guild.find({ where: `"features" LIKE '%COMMUNITY%'`, take: Math.abs(Number(limit || 24)) }); + : await Guild.find({ where: `"features" LIKE '%DISCOVERABLE%'`, take: Math.abs(Number(limit || 24)) }); res.send({ recommended_guilds: guilds }); }); diff --git a/api/src/routes/guilds/#guild_id/discovery-requirements.ts b/api/src/routes/guilds/#guild_id/discovery-requirements.ts new file mode 100644 index 00000000..ad20633f --- /dev/null +++ b/api/src/routes/guilds/#guild_id/discovery-requirements.ts @@ -0,0 +1,39 @@ +import { Guild, Config } from "@fosscord/util"; + +import { Router, Request, Response } from "express"; +import { route } from "@fosscord/api"; + +const router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + const { guild_id } = req.params; + // TODO: + // Load from database + // Admin control, but for now it allows anyone to be discoverable + + res.send({ + guild_id: guild_id, + safe_environment: true, + healthy: true, + health_score_pending: false, + size: true, + nsfw_properties: {}, + protected: true, + sufficient: true, + sufficient_without_grace_period: true, + valid_rules_channel: true, + retention_healthy: true, + engagement_healthy: true, + age: true, + minimum_age: 0, + health_score: { + avg_nonnew_participators: 0, + avg_nonnew_communicators: 0, + num_intentful_joiners: 0, + perc_ret_w1_intentful: 0 + }, + minimum_size: 0 + }); +}); + +export default router; diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts index d8ee86ff..991c3f93 100644 --- a/api/src/routes/guilds/#guild_id/index.ts +++ b/api/src/routes/guilds/#guild_id/index.ts @@ -34,7 +34,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { // @ts-ignore guild.joined_at = member?.joined_at; - return res.json(guild); + return res.send(guild); }); router.patch("/", route({ body: "GuildUpdateSchema", permission: "MANAGE_GUILD" }), async (req: Request, res: Response) => { diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts index ab489743..18a6ed4b 100644 --- a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts +++ b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { Member, getPermission, Role, GuildMemberUpdateEvent, emitEvent } from "@fosscord/util"; +import { Member, getPermission, Role, GuildMemberUpdateEvent, emitEvent, Sticker, Emoji, Guild } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { route } from "@fosscord/api"; @@ -43,13 +43,26 @@ router.patch("/", route({ body: "MemberChangeSchema" }), async (req: Request, re }); router.put("/", route({}), async (req: Request, res: Response) => { + + // TODO: Lurker mode + let { guild_id, member_id } = req.params; if (member_id === "@me") member_id = req.user_id; - throw new HTTPError("Maintenance: Currently you can't add a member", 403); - // TODO: only for oauth2 applications + var guild = await Guild.findOneOrFail({ + where: { id: guild_id } }); + + var emoji = await Emoji.find({ + where: { guild_id: guild_id } }); + + var roles = await Role.find({ + where: { guild_id: guild_id } }); + + var stickers = await Sticker.find({ + where: { guild_id: guild_id } }); + + res.send({...guild, emojis: emoji, roles: roles, stickers: stickers}); await Member.addToGuild(member_id, guild_id); - res.sendStatus(204); }); router.delete("/", route({ permission: "KICK_MEMBERS" }), async (req: Request, res: Response) => { diff --git a/api/src/routes/partners/#guild_id/requirements.ts b/api/src/routes/partners/#guild_id/requirements.ts new file mode 100644 index 00000000..545c5c78 --- /dev/null +++ b/api/src/routes/partners/#guild_id/requirements.ts @@ -0,0 +1,40 @@ + +import { Guild, Config } from "@fosscord/util"; + +import { Router, Request, Response } from "express"; +import { route } from "@fosscord/api"; + +const router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + const { guild_id } = req.params; + // TODO: + // Load from database + // Admin control, but for now it allows anyone to be discoverable + + res.send({ + guild_id: guild_id, + safe_environment: true, + healthy: true, + health_score_pending: false, + size: true, + nsfw_properties: {}, + protected: true, + sufficient: true, + sufficient_without_grace_period: true, + valid_rules_channel: true, + retention_healthy: true, + engagement_healthy: true, + age: true, + minimum_age: 0, + health_score: { + avg_nonnew_participators: 0, + avg_nonnew_communicators: 0, + num_intentful_joiners: 0, + perc_ret_w1_intentful: 0 + }, + minimum_size: 0 + }); +}); + +export default router; diff --git a/api/src/util/handlers/route.ts b/api/src/util/handlers/route.ts index 05658ad3..0048c4dd 100644 --- a/api/src/util/handlers/route.ts +++ b/api/src/util/handlers/route.ts @@ -73,7 +73,7 @@ const normalizeBody = (body: any = {}) => { } else { for (const [key, value] of Object.entries(object)) { if (value == null) { - if (key === "icon" || key === "avatar" || key === "banner" || key === "splash") continue; + if (key === "icon" || key === "avatar" || key === "banner" || key === "splash" || key === "discovery_splash") continue; delete object[key]; } else if (typeof value === "object") { normalizeObject(value); From b8a14b0d18a2edd5f01a0441bf74e52e2c79a956 Mon Sep 17 00:00:00 2001 From: Featyre Date: Tue, 25 Jan 2022 00:30:16 +0800 Subject: [PATCH 06/21] change line --- api/src/routes/guilds/#guild_id/members/#member_id/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts index 18a6ed4b..24c74af7 100644 --- a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts +++ b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts @@ -61,8 +61,8 @@ router.put("/", route({}), async (req: Request, res: Response) => { var stickers = await Sticker.find({ where: { guild_id: guild_id } }); - res.send({...guild, emojis: emoji, roles: roles, stickers: stickers}); await Member.addToGuild(member_id, guild_id); + res.send({...guild, emojis: emoji, roles: roles, stickers: stickers}); }); router.delete("/", route({ permission: "KICK_MEMBERS" }), async (req: Request, res: Response) => { From 821470cc41f7922b3a5f471988e344332a34068d Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 26 Jan 2022 08:58:36 +0800 Subject: [PATCH 07/21] Dev portal + categories load db --- api/client_test/developers.html | 42 +++++++++++++++++++++++ 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 ++-- 9 files changed, 80 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 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/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() From 37bcc2d407df3228a56b84cc1e67bf9c67258d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erkin=20Alp=20G=C3=BCney?= Date: Thu, 27 Jan 2022 16:54:42 +0300 Subject: [PATCH 08/21] A few minor changes --- util/src/entities/User.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts index 1027331a..f157ac39 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts @@ -256,7 +256,7 @@ export class User extends BaseClass { disabled: false, deleted: false, email: email, - rights: "0", + rights: "0", // TODO: grant rights correctly, as 0 actually stands for no rights at all nsfw_allowed: true, // TODO: depending on age public_flags: "0", flags: "0", // TODO: generate @@ -283,7 +283,7 @@ export class User extends BaseClass { } export const defaultSettings: UserSettings = { - afk_timeout: 300, + afk_timeout: 3600, allow_accessibility_detection: true, animate_emoji: true, animate_stickers: 0, @@ -291,10 +291,10 @@ export const defaultSettings: UserSettings = { convert_emoticons: false, custom_status: null, default_guilds_restricted: false, - detect_platform_accounts: true, - developer_mode: false, - disable_games_tab: false, - enable_tts_command: true, + detect_platform_accounts: false, + developer_mode: true, + disable_games_tab: true, + enable_tts_command: false, explicit_content_filter: 0, friend_source_flags: { all: true }, gateway_connected: false, @@ -304,17 +304,16 @@ export const defaultSettings: UserSettings = { inline_attachment_media: true, inline_embed_media: true, locale: "en-US", - message_display_compact: false, + message_display_compact: true, native_phone_integration_enabled: true, render_embeds: true, render_reactions: true, restricted_guilds: [], show_current_game: true, status: "online", - stream_notifications_enabled: true, + stream_notifications_enabled: false, theme: "dark", - timezone_offset: 0, - // timezone_offset: // TODO: timezone from request + timezone_offset: 0, // TODO: timezone from request }; export interface UserSettings { From 9a52549eb8e488e80ddac9aecf20e0a6708c8a33 Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 2 Feb 2022 01:02:32 +0800 Subject: [PATCH 09/21] make everything in categories nullable --- util/src/entities/Categories.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 From d4690aa7b65c9d030de71e8f963789ba213fdd13 Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 2 Feb 2022 01:06:42 +0800 Subject: [PATCH 10/21] Fix primarycolum being assigned to nullable = true --- util/src/entities/Categories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 }) From 9f5c451cbc8bfb714479312c0cdc7349a836505f Mon Sep 17 00:00:00 2001 From: Featyre Date: Wed, 2 Feb 2022 02:09:57 +0800 Subject: [PATCH 11/21] 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(-) 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; From 79cc9badfc3d7af6b847e50a9211bc3b8f015aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erkin=20Alp=20G=C3=BCney?= Date: Sat, 12 Feb 2022 19:53:40 +0300 Subject: [PATCH 12/21] Added a few extensions --- util/src/util/Constants.ts | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/util/src/util/Constants.ts b/util/src/util/Constants.ts index 5fdf5bc0..8d61b9b4 100644 --- a/util/src/util/Constants.ts +++ b/util/src/util/Constants.ts @@ -727,26 +727,44 @@ export const DiscordApiErrors = { * An error encountered while performing an API request (Fosscord only). Here are the potential errors: */ export const FosscordApiErrors = { + MANUALLY_TRIGGERED_ERROR: new ApiError("This is an artificial error", 1), + PREMIUM_DISABLED_FOR_GUILD: new ApiError("This guild cannot be boosted", 25001), + NO_FURTHER_PREMIUM: new ApiError("This guild does not receive further boosts", 25002), + GUILD_PREMIUM_DISABLED_FOR_YOU: new ApiError("This guild cannot be boosted by you", 25003), + CANNOT_FRIEND_SELF: new ApiError("Cannot friend oneself", 25009), + USER_SPECIFIC_INVITE_WRONG_RECIPIENT: new ApiError("This invite is not meant for you", 25010), + USER_SPECIFIC_INVITE_FAILED: new ApiError("Failed to invite user", 25011), + CANNOT_MODIFY_USER_GROUP: new ApiError("This user cannot manipulate this group", 25050), + CANNOT_REMOVE_SELF_FROM_GROUP: new ApiError("This user cannot remove oneself from user group", 25051), + CANNOT_BAN_OPERATOR: new ApiError("Non-OPERATOR cannot ban OPERATOR from instance", 25052), + CANNOT_LEAVE_GUILD: new ApiError("You are not allowed to leave guilds that you joined by yourself", 25059), + EDITS_DISABLED: new ApiError("You are not allowed to edit your own messages", 25060), + DELETE_MESSAGE_DISABLED: new ApiError("You are not allowed to delete your own messages", 25061), + FEATURE_PERMANENTLY_DISABLED: new ApiError("This feature has been disabled server-side", 45006), MISSING_RIGHTS: new ApiError("You lack rights to perform that action ({})", 50013, undefined, [""]), + CANNOT_GRANT_PERMISSIONS_EXCEEDING_RIGHTS: new ApiError("You cannot grant permissions exceeding your own rights", 50050), + ROUTES_LOOPING: new ApiError("Loops in the route definition ({})", 50060, undefined, [""]), + CANNOT_REMOVE_ROUTE: new ApiError("Cannot remove message route while it is in effect and being used", 50061), }; /** * The value set for a guild's default message notifications, e.g. `ALL`. Here are the available types: * * ALL * * MENTIONS + * * MUTED (Fosscord extension) * @typedef {string} DefaultMessageNotifications */ -export const DefaultMessageNotifications = ["ALL", "MENTIONS"]; +export const DefaultMessageNotifications = ["ALL", "MENTIONS", "MUTED"]; /** * The value set for a team members's membership state: * * INVITED * * ACCEPTED + * * INSERTED (Fosscord extension) * @typedef {string} MembershipStates */ export const MembershipStates = [ - // They start at 1 - null, + "INSERTED", "INVITED", "ACCEPTED", ]; @@ -755,11 +773,11 @@ export const MembershipStates = [ * The value set for a webhook's type: * * Incoming * * Channel Follower + * * Custom (Fosscord extension) * @typedef {string} WebhookTypes */ export const WebhookTypes = [ - // They start at 1 - null, + "Custom", "Incoming", "Channel Follower", ]; From 4d9ee5220e38bfc3dd64d28f95f0b1eeb227b92f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 08:01:41 +0300 Subject: [PATCH 13/21] Bump vm2 from 3.9.5 to 3.9.7 in /util (#631) Bumps [vm2](https://github.com/patriksimek/vm2) from 3.9.5 to 3.9.7. - [Release notes](https://github.com/patriksimek/vm2/releases) - [Changelog](https://github.com/patriksimek/vm2/blob/master/CHANGELOG.md) - [Commits](https://github.com/patriksimek/vm2/compare/3.9.5...3.9.7) --- updated-dependencies: - dependency-name: vm2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- util/package-lock.json | Bin 497311 -> 498017 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/util/package-lock.json b/util/package-lock.json index 9d20da93600eedc252341cbf4cfec29d85c2d753..c5e96742fbfededc4daff62b5100c58a90e4c06f 100644 GIT binary patch delta 634 zcmbQgR_@^@xeZTuOz$aXH=OLSmvwslK^D&Gm%cNrgof$+xEC2Z22^SXM0l2arzW|E z7iC8Ul;@}ByJ?pjW@Y+2h31x4lxBu{Ci;7nwRdY01#RhbpT()Hb=%)<^-Il-Lo3aTOe;fEvka4i5{;v>O7g?Xlf#1pO9S=O^2;ZGJSjhY z?*SGrMGHN1Jp&~jE>0j&N=(i#%F``R%*j@=Qc#Ms&@<9An7%QKNpgDkd*%=pkn<)B z?h>BPy^Z7rz;<05!pT^hn-ss0C;rU&j0`b delta 509 zcmaF3NpAjHxeZTuOg8*yIQ_sO7CuIc=?@OFDTh`@Bt@pWRcdF2mPV!+>pQz7ryKcY zdq%oiS{g<~M(8JHrJDQXW_e|%hbCtxrurLt1(`%tM5H@=h8gNdCF`dImAbiBmK*vQ z6eKxn7gpwZWrv$iHe4??xzmDoa_gRiW|3X(BD)xYm}$GnF6MbA)0@&5^`~d$vhz)! zbdpga%%{}Z(Id*w+| z#mK|N$I!dXMBClXBR#RmJJTmEBErWlRNLIg#nH(luiQU7JTHBEBO9~W^b_xyL$-&0 zWd3xHJ|3TL_>)m~Gv6*&#_0kRScE2P?lzo$+MHFUz2FcF5VLMCIK*~(6

H(k29K NZI!nB=Cg}v0RV6Mvibl3 From 44c4b6eb8679e9ff1a47d51bdd6a668ab434c540 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 08:01:55 +0300 Subject: [PATCH 14/21] Bump vm2 from 3.9.5 to 3.9.7 in /gateway (#632) Bumps [vm2](https://github.com/patriksimek/vm2) from 3.9.5 to 3.9.7. - [Release notes](https://github.com/patriksimek/vm2/releases) - [Changelog](https://github.com/patriksimek/vm2/blob/master/CHANGELOG.md) - [Commits](https://github.com/patriksimek/vm2/compare/3.9.5...3.9.7) --- updated-dependencies: - dependency-name: vm2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gateway/package-lock.json | Bin 538296 -> 539529 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/gateway/package-lock.json b/gateway/package-lock.json index dfac1bd71ef56575e36d0fb73c86739fa74e90cb..878799d27d4c2db192a389b5b3c8a4a949e47cb7 100644 GIT binary patch delta 750 zcmdn-R-yB|LPHB<3)2?n9nO>eW=Twc&%@3=U9*8*LohKpzbH>%S07C4TIiWiH@w2G z7#61Q<6dOw7*MGl5aC(wotoqtUX&dbP@bQf@1|XDn3d`86q;LFQJNX*ndt9PlAmM| zm~813QWTkQ9#-mUnigbHQdnH6omA>*6z-OvA7q-JQ&<)_{a`<{*yPf_bx-`W0^2D5MxKltJpnHtK?wQ{EoGos8RTYcOWSu!8Al>4VP*jZ*Op62~%SpEUQoeqvxp8Qv zd68*lXlj;Wa!{giR8~oTSb1`IaA0Yme%f@#I3`7)uQ=J_fZ?ZSFx~JvljL-#X^b-M z^Rroin05R7Y_|1hhzj{k+JwBVtr8a}XRQv9P=W^b^bMKJ;?pyqvq4er^9yoIy^T|hJWPBHy~|9r-Q7IW6N|hvebOQ#eB45{&3#-Pojmf& x{jqvwzf*!4OBTI#Q@j&W19c~ From a864acdeaa4571967ff65d49c833fd5e4d1bf1cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 08:02:08 +0300 Subject: [PATCH 15/21] Bump vm2 from 3.9.5 to 3.9.7 in /api (#633) Bumps [vm2](https://github.com/patriksimek/vm2) from 3.9.5 to 3.9.7. - [Release notes](https://github.com/patriksimek/vm2/releases) - [Changelog](https://github.com/patriksimek/vm2/blob/master/CHANGELOG.md) - [Commits](https://github.com/patriksimek/vm2/compare/3.9.5...3.9.7) --- updated-dependencies: - dependency-name: vm2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- api/package-lock.json | Bin 830739 -> 831561 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index 21afe02c57f5768530c7f50d3dccf53a46751988..a7c29a791d80752f0df6fc7d82aae5dd2acd3090 100644 GIT binary patch delta 772 zcmbPy%jo0-qYc-Yo8L0Gzh!0wVkRJF-u{-EWl8e%`On$7rvFl7RToT5&M(T-*VPBp zx)yro(+k|#6vM*wecX!-9Rn)010p=jy;GB1!;7+`0?PAK^WC(|4YM-+okDXr!)R$5}T|$ z-*@_h5*EJ6ar1blOL(w~OmFaGVwoDiBr~~l?tZY;=D2w>j9^y#-Yga%X5GFwi|t+s zqxtlShAev1U-$Cx0of0=S>!|0_1&Y)!wh_La+5QRQ(eOR9Ye|-BZ>^&i@p5P&9Vbc z1G35@D~&ypynLO5@=S|!{F3tZOU;c#E6s~cD??MW43mQrjia(k^25rL!-E4$1NGDL zryKS$Doo~^$HfW^5

-vh&25E%c10HzqSlPfvNk7Q$SXYc$>Q9+L$)7$qUWSDu)Y z4G&8YN7rI{<3t|i=?VWiKW-7Om|G;lAX4Xm34aGJ*J51hw`~ZwpaJ@%#Z^B;nWce delta 368 zcmX^4z-aO)4E)Th+h(Id*w+| z#mK|N$I!dXMBClXBR#RmJJTmEBErWlRNLIg#nH(luiQU7Ja77k32friFFarina;<{ z{JA~gF&hxG12M<;fXAH2_rjcBH(h~;k+c2ILayz17IN=;i{ZXVnz%3B)>diziitc6 F Date: Tue, 15 Feb 2022 08:02:19 +0300 Subject: [PATCH 16/21] Bump vm2 from 3.9.5 to 3.9.7 in /bundle (#634) Bumps [vm2](https://github.com/patriksimek/vm2) from 3.9.5 to 3.9.7. - [Release notes](https://github.com/patriksimek/vm2/releases) - [Changelog](https://github.com/patriksimek/vm2/blob/master/CHANGELOG.md) - [Commits](https://github.com/patriksimek/vm2/compare/3.9.5...3.9.7) --- updated-dependencies: - dependency-name: vm2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bundle/package-lock.json | Bin 576191 -> 589165 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bundle/package-lock.json b/bundle/package-lock.json index 898c041c76670ef3d9676afe6c64b3b6ac5f60e9..485f3bf4e6191829165c0a4af65094e5be786700 100644 GIT binary patch delta 17777 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 delta 14177 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 lBr6B+GZoLr5 Date: Tue, 15 Feb 2022 08:04:23 +0300 Subject: [PATCH 17/21] Bump follow-redirects from 1.14.6 to 1.14.8 in /cdn (#635) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.6 to 1.14.8. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.6...v1.14.8) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cdn/package-lock.json | Bin 500169 -> 500169 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cdn/package-lock.json b/cdn/package-lock.json index 93d35f895e6be8b03b52a4e0a8a38127a9fbd400..de3dfc7038f1316b8370bb5974c494101d23b759 100644 GIT binary patch delta 252 zcmX?kSnlLuxrP?TElkU_r(a5E(w~0dKda{S#85_sP{Rs?V9U@jFOTBDf+DwMS7-gg zJijU@pJdO9;w;B7O9Rt1{m|^dilpQm=i>a3@SMbCXFvafz(oDTy!;fO9HY`iS8unB zv~d42U!%Zub8~G&)2it&S{Sw3=jt#4F*6XeY@e&c`sEUu-C;Db+j06wU3S^l8n&%9 H?7j;DTGmvb`umv$CmLC}!l>0gSBD9RnSq#P`&=E?FPBiQ4x@?Hj?+KtvdgyCux+hj H_gx48R5e*? From 4eae64b91a296d49e8bb1bc833f2531301eb459a Mon Sep 17 00:00:00 2001 From: RealMANI <96433859+ImAaronFR@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:15:37 +0330 Subject: [PATCH 18/21] [Fix] Invisible space username (#639) You can send only spaces to the server and have a invisible username, this way you can remove the spaces and check and if it wasn't null after you know it's not just spaces --- api/src/routes/users/@me/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts index 1959704a..acca8910 100644 --- a/api/src/routes/users/@me/index.ts +++ b/api/src/routes/users/@me/index.ts @@ -57,6 +57,13 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res: user.data.hash = await bcrypt.hash(body.new_password, 12); } + var check_username = body?.username?.replace(/\s/g, ''); + if(!check_username) { + throw FieldErrors({ + username: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") } + }); + } + await user.save(); // @ts-ignore From 5a215b1af796de6464250b5cc445128b3307457a Mon Sep 17 00:00:00 2001 From: RealMANI <96433859+ImAaronFR@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:15:54 +0330 Subject: [PATCH 19/21] Mutual Guilds (#637) --- api/src/routes/users/#id/profile.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/api/src/routes/users/#id/profile.ts b/api/src/routes/users/#id/profile.ts index 15457547..9481451d 100644 --- a/api/src/routes/users/#id/profile.ts +++ b/api/src/routes/users/#id/profile.ts @@ -1,5 +1,5 @@ import { Router, Request, Response } from "express"; -import { PublicConnectedAccount, PublicUser, User, UserPublic } from "@fosscord/util"; +import { PublicConnectedAccount, PublicUser, User, UserPublic, Member } from "@fosscord/util"; import { route } from "@fosscord/api"; const router: Router = Router(); @@ -15,11 +15,24 @@ router.get("/", route({ test: { response: { body: "UserProfileResponse" } } }), if (req.params.id === "@me") req.params.id = req.user_id; const user = await User.getPublicUser(req.params.id, { relations: ["connected_accounts"] }); + var mutual_guilds: object[] = []; + + const requested_member = await Member.find( { id: req.params.id, }) + const self_member = await Member.find( { id: req.user_id, }) + + for(const rmem of requested_member) { + for(const smem of self_member) { + if (smem.guild_id === rmem.guild_id) { + mutual_guilds.push({id: rmem.guild_id, nick: rmem.nick}) + } + } + } + res.json({ connected_accounts: user.connected_accounts, premium_guild_since: null, // TODO premium_since: null, // TODO - mutual_guilds: [], // TODO {id: "", nick: null} when ?with_mutual_guilds=true + mutual_guilds: mutual_guilds, // TODO {id: "", nick: null} when ?with_mutual_guilds=true user: { username: user.username, discriminator: user.discriminator, From 4825cbb4a7ab297f2767d480b22afa28d17ae60e Mon Sep 17 00:00:00 2001 From: RealMANI <96433859+ImAaronFR@users.noreply.github.com> Date: Tue, 15 Feb 2022 23:57:46 +0330 Subject: [PATCH 20/21] Mutual Friends Added mutual friends --- api/src/routes/users/#id/relationships.ts | 41 +++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 api/src/routes/users/#id/relationships.ts diff --git a/api/src/routes/users/#id/relationships.ts b/api/src/routes/users/#id/relationships.ts new file mode 100644 index 00000000..67668306 --- /dev/null +++ b/api/src/routes/users/#id/relationships.ts @@ -0,0 +1,41 @@ +import { Router, Request, Response } from "express"; +import { User } from "@fosscord/util"; +import { route } from "@fosscord/api"; + +const router: Router = Router(); + +export interface UserRelationsResponse { + object: { + id?: string, + username?: string, + avatar?: string, + discriminator?: string, + public_flags?: number + } +} + + +router.get("/", route({ test: { response: { body: "UserRelationsResponse" } } }), async (req: Request, res: Response) => { + var mutual_relations: object[] = []; + const requested_relations = await User.findOneOrFail({ + where: { id: req.params.id }, + relations: ["relationships"] + }); + const self_relations = await User.findOneOrFail({ + where: { id: req.params.id }, + relations: ["relationships"] + }); + + for(const rmem of requested_relations.relationships) { + for(const smem of self_relations.relationships) + if (rmem.to_id === smem.to_id && rmem.type === 1 && rmem.to_id !== req.user_id) { + var relation_user = await User.getPublicUser(rmem.to_id) + + mutual_relations.push({id: relation_user.id, username: relation_user.username, avatar: relation_user.avatar, discriminator: relation_user.discriminator, public_flags: relation_user.public_flags}) + } + } + + res.json(mutual_relations) +}); + +export default router; From dcf9c436ed5bfdaeb4791ececb1aa89ae5a8cef2 Mon Sep 17 00:00:00 2001 From: RealMANI <96433859+ImAaronFR@users.noreply.github.com> Date: Wed, 16 Feb 2022 00:02:13 +0330 Subject: [PATCH 21/21] Typo --- api/src/routes/users/#id/relationships.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/routes/users/#id/relationships.ts b/api/src/routes/users/#id/relationships.ts index 67668306..de7cb9d3 100644 --- a/api/src/routes/users/#id/relationships.ts +++ b/api/src/routes/users/#id/relationships.ts @@ -22,7 +22,7 @@ router.get("/", route({ test: { response: { body: "UserRelationsResponse" } } }) relations: ["relationships"] }); const self_relations = await User.findOneOrFail({ - where: { id: req.params.id }, + where: { id: req.user_id }, relations: ["relationships"] });