diff --git a/src/api/routes/unique-username/username-attempt-unauthed.ts b/src/api/routes/unique-username/username-attempt-unauthed.ts
index b225a2996..d1768ee00 100644
--- a/src/api/routes/unique-username/username-attempt-unauthed.ts
+++ b/src/api/routes/unique-username/username-attempt-unauthed.ts
@@ -1,34 +1,31 @@
import { route } from "@spacebar/api";
-import { Config, UniqueUsernameAttemptSchema, User } from "@spacebar/util";
+import { Config, User } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
+import { UniqueUsernameAttemptSchema } from "@spacebar/schemas";
const router = Router();
router.post(
- "/",
- route({
- requestBody: "UniqueUsernameAttemptSchema",
- responses: {
- 200: { body: "UniqueUsernameAttemptResponse" },
- 400: { body: "APIErrorResponse" },
- },
- description:
- "Checks whether a unique username is available for the user to claim.",
- }),
- async (req: Request, res: Response) => {
- const body = req.body as UniqueUsernameAttemptSchema;
- const { uniqueUsernames } = Config.get().general;
- if (!uniqueUsernames) {
- throw new HTTPError(
- "Unique Usernames feature is not enabled on this instance.",
- 400,
- );
- }
+ "/",
+ route({
+ requestBody: "UniqueUsernameAttemptSchema",
+ responses: {
+ 200: { body: "UniqueUsernameAttemptResponse" },
+ 400: { body: "APIErrorResponse" },
+ },
+ description: "Checks whether a unique username is available for the user to claim.",
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UniqueUsernameAttemptSchema;
+ const { uniqueUsernames } = Config.get().general;
+ if (!uniqueUsernames) {
+ throw new HTTPError("Unique Usernames feature is not enabled on this instance.", 400);
+ }
- res.json({
- taken: !(await User.isUsernameAvailable(body.username)),
- });
- },
+ res.json({
+ taken: !(await User.isUsernameAvailable(body.username)),
+ });
+ },
);
export default router;
diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts
deleted file mode 100644
index eecec0f35..000000000
--- a/src/api/routes/users/#id/profile.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-import { route } from "@spacebar/api";
-import {
- Member,
- PrivateUserProjection,
- User,
- UserProfileModifySchema,
- UserUpdateEvent,
- emitEvent,
- handleFile,
-} from "@spacebar/util";
-import { Request, Response, Router } from "express";
-
-const router: Router = Router();
-
-router.get(
- "/",
- route({ responses: { 200: { body: "UserProfileResponse" } } }),
- async (req: Request, res: Response) => {
- if (req.params.id === "@me") req.params.id = req.user_id;
-
- const { guild_id, with_mutual_guilds } = req.query;
-
- const user = await User.getPublicUser(req.params.id, {
- relations: ["connected_accounts"],
- });
-
- const mutual_guilds: object[] = [];
- let premium_guild_since;
-
- if (with_mutual_guilds == "true") {
- const requested_member = await Member.find({
- where: { id: req.params.id },
- });
- const self_member = await Member.find({
- where: { id: req.user_id },
- });
-
- for (const rmem of requested_member) {
- if (rmem.premium_since) {
- if (premium_guild_since) {
- if (premium_guild_since > rmem.premium_since) {
- premium_guild_since = rmem.premium_since;
- }
- } else {
- premium_guild_since = rmem.premium_since;
- }
- }
- for (const smem of self_member) {
- if (smem.guild_id === rmem.guild_id) {
- mutual_guilds.push({
- id: rmem.guild_id,
- nick: rmem.nick,
- });
- }
- }
- }
- }
-
- const guild_member =
- guild_id && typeof guild_id == "string"
- ? await Member.findOneOrFail({
- where: { id: req.params.id, guild_id: guild_id },
- relations: ["roles"],
- })
- : undefined;
-
- // TODO: make proper DTO's in util?
-
- const userProfile = {
- bio: req.user_bot ? null : user.bio,
- accent_color: user.accent_color,
- banner: user.banner,
- pronouns: user.pronouns,
- theme_colors: user.theme_colors,
- };
-
- const guildMemberProfile = {
- accent_color: null,
- banner: guild_member?.banner || null,
- bio: guild_member?.bio || "",
- guild_id,
- };
- res.json({
- connected_accounts: user.connected_accounts.filter(
- (x) => x.visibility != 0,
- ),
- premium_guild_since: premium_guild_since, // TODO
- premium_since: user.premium_since, // TODO
- mutual_guilds: mutual_guilds, // TODO {id: "", nick: null} when ?with_mutual_guilds=true
- user: user.toPublicUser(),
- premium_type: user.premium_type,
- profile_themes_experiment_bucket: 4, // TODO: This doesn't make it available, for some reason?
- user_profile: userProfile,
- guild_member: guild_member?.toPublicMember(),
- guild_member_profile: guild_id && guildMemberProfile,
- });
- },
-);
-
-router.patch(
- "/",
- route({ requestBody: "UserProfileModifySchema" }),
- async (req: Request, res: Response) => {
- const body = req.body as UserProfileModifySchema;
-
- if (body.banner)
- body.banner = await handleFile(
- `/banners/${req.user_id}`,
- body.banner as string,
- );
- const user = await User.findOneOrFail({
- where: { id: req.user_id },
- select: [...PrivateUserProjection, "data"],
- });
-
- user.assign(body);
- await user.save();
-
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- delete user.data;
-
- // TODO: send update member list event in gateway
- await emitEvent({
- event: "USER_UPDATE",
- user_id: req.user_id,
- data: user,
- } as UserUpdateEvent);
-
- res.json({
- accent_color: user.accent_color,
- bio: user.bio,
- banner: user.banner,
- theme_colors: user.theme_colors,
- pronouns: user.pronouns,
- });
- },
-);
-
-export default router;
diff --git a/src/api/routes/users/@me/pomelo-attempt.ts b/src/api/routes/users/@me/pomelo-attempt.ts
index d4327f618..69438c300 100644
--- a/src/api/routes/users/@me/pomelo-attempt.ts
+++ b/src/api/routes/users/@me/pomelo-attempt.ts
@@ -1,35 +1,32 @@
import { route } from "@spacebar/api";
-import { Config, UniqueUsernameAttemptSchema, User } from "@spacebar/util";
+import { Config, User } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
+import { UniqueUsernameAttemptSchema } from "@spacebar/schemas";
const router = Router();
// https://discord-userdoccers.vercel.app/resources/user#get-pomelo-eligibility
router.post(
- "/",
- route({
- requestBody: "UniqueUsernameAttemptSchema",
- responses: {
- 200: { body: "UniqueUsernameAttemptResponse" },
- 400: { body: "APIErrorResponse" },
- },
- description:
- "Checks whether a unique username is available for the user to claim.",
- }),
- async (req: Request, res: Response) => {
- const body = req.body as UniqueUsernameAttemptSchema;
- const { uniqueUsernames } = Config.get().general;
- if (!uniqueUsernames) {
- throw new HTTPError(
- "Unique Usernames feature is not enabled on this instance.",
- 400,
- );
- }
+ "/",
+ route({
+ requestBody: "UniqueUsernameAttemptSchema",
+ responses: {
+ 200: { body: "UniqueUsernameAttemptResponse" },
+ 400: { body: "APIErrorResponse" },
+ },
+ description: "Checks whether a unique username is available for the user to claim.",
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UniqueUsernameAttemptSchema;
+ const { uniqueUsernames } = Config.get().general;
+ if (!uniqueUsernames) {
+ throw new HTTPError("Unique Usernames feature is not enabled on this instance.", 400);
+ }
- res.json({
- taken: !(await User.isUsernameAvailable(body.username)),
- });
- },
+ res.json({
+ taken: !(await User.isUsernameAvailable(body.username)),
+ });
+ },
);
export default router;
diff --git a/src/api/routes/users/@me/pomelo.ts b/src/api/routes/users/@me/pomelo.ts
index e10beaa41..11e0517d3 100644
--- a/src/api/routes/users/@me/pomelo.ts
+++ b/src/api/routes/users/@me/pomelo.ts
@@ -1,61 +1,52 @@
import { route } from "@spacebar/api";
-import {
- Config,
- FieldErrors,
- UniqueUsernameAttemptSchema,
- User,
-} from "@spacebar/util";
+import { Config, FieldErrors, User } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
+import { UniqueUsernameAttemptSchema } from "@spacebar/schemas";
const router = Router();
// https://discord-userdoccers.vercel.app/resources/user#create-pomelo-migration
router.post(
- "/",
- route({
- description:
- "Claims a unique username for the user. Returns the updated user object on success. Fires a User Update Gateway event.",
- requestBody: "UniqueUsernameAttemptSchema",
- responses: {
- 200: { body: "PrivateUserResponse" },
- 400: { body: "APIErrorResponse" },
- },
- }),
- async (req: Request, res: Response) => {
- const body = req.body as UniqueUsernameAttemptSchema;
- const { uniqueUsernames } = Config.get().general;
- if (!uniqueUsernames) {
- throw new HTTPError(
- "Unique Usernames feature is not enabled on this instance.",
- 400,
- );
- }
+ "/",
+ route({
+ description: "Claims a unique username for the user. Returns the updated user object on success. Fires a User Update Gateway event.",
+ requestBody: "UniqueUsernameAttemptSchema",
+ responses: {
+ 200: { body: "PrivateUserResponse" },
+ 400: { body: "APIErrorResponse" },
+ },
+ }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UniqueUsernameAttemptSchema;
+ const { uniqueUsernames } = Config.get().general;
+ if (!uniqueUsernames) {
+ throw new HTTPError("Unique Usernames feature is not enabled on this instance.", 400);
+ }
- const isAvailable = await User.isUsernameAvailable(body.username);
+ const isAvailable = await User.isUsernameAvailable(body.username);
- if (!isAvailable) {
- throw FieldErrors({
- username: {
- code: "USERNAME_TOO_MANY_USERS",
- message:
- req?.t("auth:register.USERNAME_TOO_MANY_USERS") || "",
- },
- });
- }
+ if (!isAvailable) {
+ throw FieldErrors({
+ username: {
+ code: "USERNAME_TOO_MANY_USERS",
+ message: req?.t("auth:register.USERNAME_TOO_MANY_USERS") || "",
+ },
+ });
+ }
- const user = await User.findOneOrFail({
- where: {
- id: req.user_id,
- },
- });
+ const user = await User.findOneOrFail({
+ where: {
+ id: req.user_id,
+ },
+ });
- user.legacy_username = user.username;
- user.username = body.username;
- user.discriminator = "0";
- const newUser = await user.save();
+ user.legacy_username = user.username;
+ user.username = body.username;
+ user.discriminator = "0";
+ const newUser = await user.save();
- res.json(newUser.toPrivateUser());
- },
+ res.json(newUser.toPrivateUser());
+ },
);
export default router;
diff --git a/src/connections/Discord/index.ts b/src/connections/Discord/index.ts
index 3f5585580..9661ba1cc 100644
--- a/src/connections/Discord/index.ts
+++ b/src/connections/Discord/index.ts
@@ -16,15 +16,7 @@
along with this program. If not, see .
*/
-import {
- Config,
- ConnectedAccount,
- ConnectedAccountCommonOAuthTokenResponse,
- Connection,
- ConnectionCallbackSchema,
- ConnectionLoader,
- DiscordApiErrors,
-} from "@spacebar/util";
+import { Config, ConnectedAccount, ConnectedAccountCommonOAuthTokenResponse, Connection, ConnectionLoader, DiscordApiErrors } from "@spacebar/util";
import wretch from "wretch";
import { DiscordSettings } from "./DiscordSettings";
import { ConnectionCallbackSchema } from "@spacebar/schemas";
@@ -33,7 +25,7 @@ interface UserResponse {
id: string;
username: string;
discriminator: string;
- global_name: string | null;
+ global_name: string | null;
avatar_url: string | null;
}
@@ -122,14 +114,12 @@ export default class DiscordConnection extends Connection {
if (exists) return null;
- const { uniqueUsernames } = Config.get().general;
+ const { uniqueUsernames } = Config.get().general;
return await this.createConnection({
user_id: userId,
external_id: userInfo.id,
friend_sync: params.friend_sync,
- name: uniqueUsernames
- ? userInfo.username
- : `${userInfo.username}#${userInfo.discriminator}`,
+ name: uniqueUsernames ? userInfo.username : `${userInfo.username}#${userInfo.discriminator}`,
type: this.id,
});
}
diff --git a/src/schemas/api/users/User.ts b/src/schemas/api/users/User.ts
index 41d606730..df3fa3433 100644
--- a/src/schemas/api/users/User.ts
+++ b/src/schemas/api/users/User.ts
@@ -57,6 +57,7 @@ interface UserEntityPleaseRewriteThankYou {
fingerprints: string[];
settings?: UserSettingsSchema;
badge_ids?: string[];
+ global_name?: string;
}
export interface PartialUser {
@@ -109,6 +110,7 @@ export interface PrimaryGuild {
export enum PublicUserEnum {
username,
+ global_name,
discriminator,
id,
public_flags,
diff --git a/src/schemas/uncategorised/index.ts b/src/schemas/uncategorised/index.ts
index 2d6779032..99c3a20a6 100644
--- a/src/schemas/uncategorised/index.ts
+++ b/src/schemas/uncategorised/index.ts
@@ -84,8 +84,6 @@ export * from "./UserGuildSettingsSchema";
export * from "./UserModifySchema";
export * from "./UserNoteUpdateSchema";
export * from "./UserProfileModifySchema";
-export * from "./UserSettingsSchema";
-export * from "./Validator";
export * from "./VanityUrlSchema";
export * from "./VerifyEmailSchema";
export * from "./VoiceStateUpdateSchema";