Skip to content

Commit

Permalink
internationalization, improvements to login flow
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaMulein committed Dec 19, 2024
1 parent ce751d6 commit 12b373a
Show file tree
Hide file tree
Showing 34 changed files with 906 additions and 272 deletions.
20 changes: 16 additions & 4 deletions chili-and-cilantro-api/src/controllers/api/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ export class GameController extends BaseController {
.isString()
.trim()
.notEmpty()
.matches(constants.USERNAME_REGEX, constants.USERNAME_REGEX_ERROR),
.matches(
constants.USERNAME_REGEX,
translate(StringNames.Validation_UsernameRegexErrorTemplate),
),
body('displayname')
.isString()
.trim()
Expand All @@ -90,7 +93,10 @@ export class GameController extends BaseController {
.optional()
.isString()
.trim()
.matches(constants.PASSWORD_REGEX, constants.PASSWORD_REGEX_ERROR),
.matches(
constants.PASSWORD_REGEX,
translate(StringNames.Validation_PasswordRegexErrorTemplate),
),
body('maxChefs').isInt({ min: 2, max: 8 }),
],
}),
Expand All @@ -104,12 +110,18 @@ export class GameController extends BaseController {
.isString()
.trim()
.notEmpty()
.matches(constants.USERNAME_REGEX, constants.USERNAME_REGEX_ERROR),
.matches(
constants.USERNAME_REGEX,
translate(StringNames.Validation_UsernameRegexErrorTemplate),
),
body('password')
.optional()
.isString()
.trim()
.matches(constants.PASSWORD_REGEX, constants.PASSWORD_REGEX_ERROR),
.matches(
constants.PASSWORD_REGEX,
translate(StringNames.Validation_PasswordRegexErrorTemplate),
),
body('displayname')
.isString()
.trim()
Expand Down
60 changes: 44 additions & 16 deletions chili-and-cilantro-api/src/controllers/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
import { MailService } from '@sendgrid/mail';
import { NextFunction, Request, Response } from 'express';
import { body, query } from 'express-validator';
import moment from 'moment-timezone';
import { findAuthToken } from '../../middlewares/authenticate-token';
import { JwtService } from '../../services/jwt';
import { RequestUserService } from '../../services/request-user';
Expand Down Expand Up @@ -58,7 +59,9 @@ export class UserController extends BaseController {
.withMessage('Current password is required'),
body('newPassword')
.matches(constants.PASSWORD_REGEX)
.withMessage(constants.PASSWORD_REGEX_ERROR),
.withMessage(
translate(StringNames.Validation_PasswordRegexErrorTemplate),
),
],
}),
routeConfig<unknown[]>({
Expand All @@ -68,15 +71,24 @@ export class UserController extends BaseController {
validation: [
body('username')
.matches(constants.USERNAME_REGEX)
.withMessage(constants.USERNAME_REGEX_ERROR),
.withMessage(
translate(StringNames.Validation_UsernameRegexErrorTemplate),
),
body('displayname')
.matches(constants.USER_DISPLAY_NAME_REGEX)
.withMessage(constants.USER_DISPLAY_NAME_REGEX_ERROR),
body('email').isEmail().withMessage('Invalid email address'),
body('email')
.isEmail()
.withMessage(translate(StringNames.Validation_InvalidEmail)),
body('password')
.matches(constants.PASSWORD_REGEX)
.withMessage(constants.PASSWORD_REGEX_ERROR),
body('timezone').optional().isString(),
.withMessage(
translate(StringNames.Validation_PasswordRegexErrorTemplate),
),
body('timezone')
.optional()
.isIn(moment.tz.names())
.withMessage(translate(StringNames.Validation_InvalidTimezone)),
],
useAuthentication: false,
}),
Expand All @@ -87,21 +99,27 @@ export class UserController extends BaseController {
validation: [
body().custom((value, { req }) => {
if (!req.body.username && !req.body.email) {
throw new Error('Either username or email is required');
throw new Error(
translate(StringNames.Login_UsernameOrEmailRequired),
);
}
return true;
}),
body('username')
.optional()
.matches(constants.USERNAME_REGEX)
.withMessage(constants.USERNAME_REGEX_ERROR),
.withMessage(
translate(StringNames.Validation_UsernameRegexErrorTemplate),
),
body('email')
.optional()
.isEmail()
.withMessage('Invalid email address'),
.withMessage(translate(StringNames.Validation_InvalidEmail)),
body('password')
.matches(constants.PASSWORD_REGEX)
.withMessage(constants.PASSWORD_REGEX_ERROR),
.withMessage(
translate(StringNames.Validation_PasswordRegexErrorTemplate),
),
],
useAuthentication: false,
}),
Expand All @@ -116,13 +134,16 @@ export class UserController extends BaseController {
path: '/verify-email',
handler: this.verifyEmailToken,
validation: [
query('token').not().isEmpty().withMessage('Token is required'),
query('token')
.not()
.isEmpty()
.withMessage(translate(StringNames.Validation_Required)),
query('token')
.isLength({
min: constants.EMAIL_TOKEN_LENGTH * 2,
max: constants.EMAIL_TOKEN_LENGTH * 2,
})
.withMessage('Invalid token'),
.withMessage(translate(StringNames.Validation_InvalidToken)),
],
useAuthentication: false,
}),
Expand All @@ -139,7 +160,9 @@ export class UserController extends BaseController {
validation: [
body().custom((value, { req }) => {
if (!req.body.username && !req.body.email) {
throw new Error('Either username or email is required');
throw new Error(
translate(StringNames.Login_UsernameOrEmailRequired),
);
}
return true;
}),
Expand All @@ -156,7 +179,7 @@ export class UserController extends BaseController {
body('email')
.isEmail()
.normalizeEmail()
.withMessage('Invalid email address'),
.withMessage(translate(StringNames.Validation_InvalidEmail)),
],
useAuthentication: false,
}),
Expand All @@ -165,13 +188,16 @@ export class UserController extends BaseController {
path: '/verify-reset-token',
handler: this.verifyResetToken,
validation: [
query('token').not().isEmpty().withMessage('Token is required'),
query('token')
.not()
.isEmpty()
.withMessage(translate(StringNames.Validation_Required)),
query('token')
.isLength({
min: constants.EMAIL_TOKEN_LENGTH * 2,
max: constants.EMAIL_TOKEN_LENGTH * 2,
})
.withMessage('Invalid token'),
.withMessage(translate(StringNames.Validation_InvalidToken)),
],
useAuthentication: false,
}),
Expand All @@ -183,7 +209,9 @@ export class UserController extends BaseController {
body('token').notEmpty(),
body('password')
.matches(constants.PASSWORD_REGEX)
.withMessage(constants.PASSWORD_REGEX_ERROR),
.withMessage(
translate(StringNames.Validation_PasswordRegexErrorTemplate),
),
],
useAuthentication: false,
}),
Expand Down
6 changes: 3 additions & 3 deletions chili-and-cilantro-api/src/services/chef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ export class ChefService extends BaseService {
* Creates a new chef in the database
* @param game The game the chef is joining
* @param user The user joining the game
* @param userName The display name of the chef
* @param displayName The display name of the chef
* @param host Whether the chef is the host of the game
* @param chefId The id of the chef to create. If not provided, a new id will be generated
* @returns A new chef document
*/
public async newChefAsync(
game: IGameDocument,
user: IUserDocument,
userName: string,
displayName: string,
host: boolean,
chefId?: DefaultIdType,
): Promise<IChefDocument> {
Expand All @@ -33,7 +33,7 @@ export class ChefService extends BaseService {
{
_id: chefId ?? new Types.ObjectId(),
gameId: game._id,
name: userName,
name: displayName,
userId: user._id,
hand: UtilityService.makeHand(),
placedCards: [],
Expand Down
10 changes: 7 additions & 3 deletions chili-and-cilantro-api/src/services/user.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
AccountDeletedError,
AccountLockedError,
AccountStatusError,
AccountStatusTypeEnum,
constants,
DefaultIdType,
Expand All @@ -11,6 +10,7 @@ import {
EmailTokenType,
EmailTokenUsedOrInvalidError,
EmailVerifiedError,
HandleableError,
ICreateUserBasics,
IEmailTokenDocument,
InvalidCredentialsError,
Expand All @@ -24,6 +24,8 @@ import {
ModelName,
PendingEmailVerificationError,
StringLanguages,
StringNames,
translate,
UsernameInUseError,
UsernameOrEmailRequiredError,
UserNotFoundError,
Expand Down Expand Up @@ -185,9 +187,11 @@ export class UserService extends BaseService {
case AccountStatusTypeEnum.AdminDelete:
case AccountStatusTypeEnum.SelfDelete:
case AccountStatusTypeEnum.SelfDeleteWaitPeriod:
throw new AccountDeletedError();
throw new AccountDeletedError(userDoc.accountStatusType);
default:
throw new AccountStatusError(userDoc.accountStatusType);
throw new HandleableError(
translate(StringNames.Common_UnexpectedError),
);
}

return userDoc;
Expand Down
6 changes: 5 additions & 1 deletion chili-and-cilantro-lib/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"files": ["*.ts", "*.tsx"],
"rules": {},
"parserOptions": {
"project": ["chili-and-cilantro-lib/tsconfig.json"]
"project": [
"chili-and-cilantro-lib/tsconfig.json",
"chili-and-cilantro-lib/tsconfig.spec.json",
"chili-and-cilantro-lib/tsconfig.lib.json"
]
}
},
{
Expand Down
Loading

0 comments on commit 12b373a

Please sign in to comment.