diff --git a/assets/locales/en/common.json b/assets/locales/en/common.json
index edcafa1d..dcb97ec0 100644
--- a/assets/locales/en/common.json
+++ b/assets/locales/en/common.json
@@ -13,7 +13,11 @@
"BASE_TYPE_CONSTANT": "This field must be {{value}}",
"EMAIL_TYPE_INVALID_EMAIL": "Not a well-formed email address",
"DATE_TYPE_PARSE": "Could not parse {{date}}. Should be ISO8601",
- "BASE_TYPE_BAD_LENGTH": "Must be between {{length}} in length"
+ "BASE_TYPE_BAD_LENGTH": "Must be between {{length}} in length",
+ "PASSWORD_DOES_NOT_MATCH": "Password does not match.",
+ "DISCRIMINATOR_UPDATE_BLOCKED": "This discriminator cannot be updated",
+ "USERNAME_ALREADY_TAKEN": "Username is unavailable. Try adding numbers, letters, underscores _ , or periods.",
+ "INVALID_DISCRIMINATOR": "This discriminator is already in use."
},
"body": {
"INVALID_BODY": "Invalid Body",
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index 796d5629..99ff2b24 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -61,6 +61,8 @@ router.patch(
}),
async (req: Request, res: Response) => {
const body = req.body as UserModifySchema;
+ const { uniqueUsernames } = Config.get().general;
+ const { minUsername, maxUsername } = Config.get().limits.user;
const user = await User.findOneOrFail({
where: { id: req.user_id },
@@ -120,9 +122,53 @@ router.patch(
newToken = (await generateToken(user.id)) as string;
}
- // TODO: uniqueUsernames: disallow if uniqueUsernames is enabled
if (body.username) {
- const check_username = body?.username?.replace(/\s/g, "").trim();
+ // password is required to update username
+ if (!body.password)
+ throw FieldErrors({
+ password: {
+ message: req.t("common:field.PASSWORD_DOES_NOT_MATCH"),
+ code: "PASSWORD_DOES_NOT_MATCH",
+ },
+ });
+
+ // handle username changes (pomelo)
+ if (uniqueUsernames) {
+ body.username = body.username.toLowerCase();
+ // validate username length
+ if (
+ body.username.length < minUsername ||
+ body.username.length > maxUsername
+ ) {
+ throw FieldErrors({
+ username: {
+ code: "BASE_TYPE_BAD_LENGTH",
+ message: req.t(
+ "common:field.BASE_TYPE_BAD_LENGTH",
+ { length: `${minUsername} and ${maxUsername}` },
+ ),
+ },
+ });
+ }
+
+ // check if username is already taken (pomelo only)
+ const userCount = await User.count({
+ where: { username: body.username },
+ });
+ if (userCount > 0) {
+ throw FieldErrors({
+ username: {
+ code: "USERNAME_ALREADY_TAKEN",
+ message: req.t(
+ "common:field.USERNAME_ALREADY_TAKEN",
+ ),
+ },
+ });
+ }
+ }
+
+ // handle username changes (old username system)
+ const check_username = body?.username?.replace(/\s/g, "");
if (!check_username) {
throw FieldErrors({
username: {
@@ -132,8 +178,7 @@ router.patch(
});
}
- const { maxUsername } = Config.get().limits.user;
- if (check_username.length > maxUsername || check_username.length < 2) {
+ if (check_username.length > maxUsername) {
throw FieldErrors({
username: {
code: "BASE_TYPE_BAD_LENGTH",
@@ -152,8 +197,18 @@ router.patch(
}
}
- // TODO: uniqueUsernames: disallow if uniqueUsernames is enabled
if (body.discriminator) {
+ if (uniqueUsernames) {
+ throw FieldErrors({
+ username: {
+ code: "DISCRIMINATOR_UPDATE_BLOCKED",
+ message: req.t(
+ "common:field.DISCRIMINATOR_UPDATE_BLOCKED",
+ ),
+ },
+ });
+ }
+
if (
await User.findOne({
where: {
@@ -165,7 +220,7 @@ router.patch(
throw FieldErrors({
discriminator: {
code: "INVALID_DISCRIMINATOR",
- message: "This discriminator is already in use.",
+ message: req.t("common.field.INVALID_DISCRIMINATOR"),
},
});
}
diff --git a/src/schemas/uncategorised/UserModifySchema.ts b/src/schemas/uncategorised/UserModifySchema.ts
index c7228e7b..a135d8b1 100644
--- a/src/schemas/uncategorised/UserModifySchema.ts
+++ b/src/schemas/uncategorised/UserModifySchema.ts
@@ -18,35 +18,25 @@
export interface UserModifySchema {
/**
- * @minLength 2
+ * @minLength 1
+ * @maxLength 100
*/
username?: string;
avatar?: string | null;
+ /**
+ * @maxLength 1024
+ */
bio?: string;
accent_color?: number;
banner?: string | null;
- /**
- * @minLength 1
- * @maxLength 72
- */
password?: string;
- /**
- * @minLength 1
- * @maxLength 72
- */
new_password?: string;
- /**
- * @minLength 6
- * @maxLength 6
- */
code?: string;
- /**
- * @TJS-format email
- */
email?: string;
/**
* @minLength 4
* @maxLength 4
*/
discriminator?: string;
+ global_name?: string;
}
diff --git a/src/util/config/types/UsersConfiguration.ts b/src/util/config/types/UsersConfiguration.ts
index 2ac058e9..6b61637e 100755
--- a/src/util/config/types/UsersConfiguration.ts
+++ b/src/util/config/types/UsersConfiguration.ts
@@ -19,4 +19,4 @@
export class UserConfiguration {
blockedContains: string[] = ["discord", "clyde", "spacebar", "steam", "community", "support", "ticket"];
blockedEquals: string[] = ["everyone", "here"];
-}
+}
\ No newline at end of file
diff --git a/src/util/config/types/subconfigurations/limits/UserLimits.ts b/src/util/config/types/subconfigurations/limits/UserLimits.ts
index cbe686d1..6fe4d8d8 100644
--- a/src/util/config/types/subconfigurations/limits/UserLimits.ts
+++ b/src/util/config/types/subconfigurations/limits/UserLimits.ts
@@ -18,6 +18,7 @@
export class UserLimits {
maxGuilds: number = 1048576;
+ minUsername: number = 2;
maxUsername: number = 32;
maxFriends: number = 5000;
maxBio: number = 190;
diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts
index e955bd00..1d232fb0 100644
--- a/src/util/entities/User.ts
+++ b/src/util/entities/User.ts
@@ -32,7 +32,6 @@ import { ChannelType, PrivateUserProjection, PublicUser, PublicUserProjection, U
export enum PublicUserEnum {
username,
global_name,
- legacy_username,
discriminator,
id,
public_flags,
@@ -195,7 +194,7 @@ export class User extends BaseClass {
// TODO: I don't like this method?
validate() {
- if (this.discriminator) {
+ if (this.discriminator && this.discriminator !== "0") {
const discrim = Number(this.discriminator);
if (isNaN(discrim) || !(typeof discrim == "number") || !Number.isInteger(discrim) || discrim <= 0 || discrim >= 10000)
throw FieldErrors({
@@ -273,9 +272,8 @@ export class User extends BaseClass {
public get tag(): string {
const { uniqueUsernames } = Config.get().general;
- // if uniqueUsernames is enabled, global_name should be set
return uniqueUsernames
- ? (this.global_name as string)
+ ? this.username
: `${this.username}#${this.discriminator}`;
}
@@ -325,7 +323,7 @@ export class User extends BaseClass {
});
const user = User.create({
- username: username,
+ username: uniqueUsernames ? username.toLowerCase() : username,
discriminator,
id: id || Snowflake.generate(),
email: email,
@@ -334,8 +332,9 @@ export class User extends BaseClass {
valid_tokens_since: new Date(),
},
settings: settings,
-
- premium_since: Config.get().defaults.user.premium ? new Date() : undefined,
+ premium_since: Config.get().defaults.user.premium
+ ? new Date()
+ : undefined,
rights: Config.get().register.defaultRights,
premium: Config.get().defaults.user.premium ?? false,
premium_type: Config.get().defaults.user.premiumType ?? 0,
|