Skip to content

Commit

Permalink
internationalization, rename host to master chef
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaMulein committed Dec 21, 2024
1 parent 12b373a commit 02166e8
Show file tree
Hide file tree
Showing 49 changed files with 1,206 additions and 258 deletions.
10 changes: 7 additions & 3 deletions chili-and-cilantro-api/src/controllers/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@ export class UserController extends BaseController {
);
this.sendApiMessageResponse(
200,
{ message: 'Password changed successfully' } as IApiMessageResponse,
{
message: translate(StringNames.ChangePassword_Success),
} as IApiMessageResponse,
res,
);
} catch (error) {
Expand Down Expand Up @@ -535,7 +537,9 @@ export class UserController extends BaseController {
await this.userService.verifyEmailToken(token as string);
this.sendApiMessageResponse(
200,
{ message: 'Token is valid' } as IApiMessageResponse,
{
message: translate(StringNames.Common_TokenValid),
} as IApiMessageResponse,
res,
);
} catch (error) {
Expand Down Expand Up @@ -564,7 +568,7 @@ export class UserController extends BaseController {
RequestUserService.makeRequestUser(user);
res.header('Authorization', `Bearer ${newToken}`);
res.status(200).json({
message: 'Password reset successfully',
message: translate(StringNames.ResetPassword_Success),
user: requestUser,
} as IUserResponse);
} catch (error) {
Expand Down
8 changes: 4 additions & 4 deletions chili-and-cilantro-api/src/services/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ export class ActionService extends BaseService {
ActionType.START_GAME,
{
gameId: game._id,
chefId: game.hostChefId,
userId: game.hostUserId,
chefId: game.masterChefId,
userId: game.masterChefUserId,
type: ActionType.START_GAME,
details: {} as IStartGameDetails,
round: game.currentRound,
Expand All @@ -133,8 +133,8 @@ export class ActionService extends BaseService {
ActionType.EXPIRE_GAME,
{
gameId: game._id,
chefId: game.hostChefId,
userId: game.hostUserId,
chefId: game.masterChefId,
userId: game.masterChefUserId,
type: ActionType.EXPIRE_GAME,
details: {} as IExpireGameDetails,
round: game.currentRound,
Expand Down
8 changes: 4 additions & 4 deletions chili-and-cilantro-api/src/services/chef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ export class ChefService extends BaseService {
* @param game The game the chef is joining
* @param user The user joining the game
* @param displayName The display name of the chef
* @param host Whether the chef is the host of the game
* @param masterChef 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,
displayName: string,
host: boolean,
masterChef: boolean,
chefId?: DefaultIdType,
): Promise<IChefDocument> {
const ChefModel = this.application.getModel<IChefDocument>(ModelName.Chef);
Expand All @@ -39,7 +39,7 @@ export class ChefService extends BaseService {
placedCards: [],
lostCards: [],
state: ChefState.LOBBY,
host: host,
masterChef: masterChef,
},
]);
if (chefs.length !== 1) {
Expand Down Expand Up @@ -71,7 +71,7 @@ export class ChefService extends BaseService {
placedCards: [],
lostCards: [],
state: ChefState.LOBBY,
host: existingChef.host,
masterChef: existingChef.masterChef,
},
]);
if (chefs.length !== 1) {
Expand Down
46 changes: 23 additions & 23 deletions chili-and-cilantro-api/src/services/game.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import {
AllCardsPlacedError,
AlreadyJoinedOtherError,
CardType,
ChefAlreadyJoinedError,
ChefState,
constants,
DefaultIdType,
GameFullError,
GameInProgressError,
GamePasswordMismatchError,
GamePhase,
Expand All @@ -15,6 +13,7 @@ import {
IGameDocument,
IGameListResponse,
IMessageActionDocument,
IUserDocument,
IncorrectGamePhaseError,
InvalidActionError,
InvalidGameError,
Expand All @@ -23,16 +22,17 @@ import {
InvalidGamePasswordError,
InvalidMessageError,
InvalidUserDisplayNameError,
IUserDocument,
ModelName,
NotEnoughChefsError,
NotHostError,
NotMasterChefError,
OutOfIngredientError,
OutOfOrderError,
StringNames,
translate,
TooManyChefsInGameError,
TurnAction,
UsernameInUseError,
constants,
translate,
} from '@chili-and-cilantro/chili-and-cilantro-lib';
import { IApplication } from '@chili-and-cilantro/chili-and-cilantro-node-lib';
import { ClientSession, Types } from 'mongoose';
Expand Down Expand Up @@ -74,7 +74,7 @@ export class GameService extends BaseService {
): Promise<IGameListResponse> {
const GameModel = this.application.getModel<IGameDocument>(ModelName.Game);
const createdGames = await GameModel.find({
hostUserId: userDoc._id,
masterChefUserId: userDoc._id,
})
.session(session)
.lean();
Expand Down Expand Up @@ -138,7 +138,7 @@ export class GameService extends BaseService {
maxChefs: number,
): Promise<void> {
if (await this.playerService.userIsInAnyActiveGameAsync(user)) {
throw new AlreadyJoinedOtherError();
throw new ChefAlreadyJoinedError();
}
if (
!validator.matches(displayName, constants.MULTILINGUAL_STRING_REGEX) ||
Expand Down Expand Up @@ -202,8 +202,8 @@ export class GameService extends BaseService {
currentChef: constants.NONE,
currentPhase: GamePhase.LOBBY,
currentRound: constants.NONE,
hostChefId: chefId,
hostUserId: user._id,
masterChefId: chefId,
masterChefUserId: user._id,
maxChefs: maxChefs,
name: gameName,
...(password ? { password: password } : {}),
Expand Down Expand Up @@ -295,7 +295,7 @@ export class GameService extends BaseService {
password: string,
): Promise<void> {
if (await this.playerService.userIsInAnyActiveGameAsync(user)) {
throw new AlreadyJoinedOtherError();
throw new ChefAlreadyJoinedError();
}
const chefNames = await this.getGameChefNamesByGameIdAsync(
game._id.toString(),
Expand All @@ -313,7 +313,7 @@ export class GameService extends BaseService {
throw new GameInProgressError();
}
if (game.chefIds.length > game.maxChefs) {
throw new GameFullError();
throw new TooManyChefsInGameError();
}
if (
!validator.matches(
Expand Down Expand Up @@ -367,10 +367,10 @@ export class GameService extends BaseService {
const newChefIds = existingGame.chefIds.map(() => new Types.ObjectId());

// find the existing chef id's index
const hostChefIndex = existingGame.chefIds.findIndex(
(chefId) => existingGame.hostChefId.toString() == chefId.toString(),
const masterChefIndex = existingGame.chefIds.findIndex(
(chefId) => existingGame.masterChefId.toString() == chefId.toString(),
);
const newHostChefId = newChefIds[hostChefIndex];
const newMasterChefId = newChefIds[masterChefIndex];

// we need to look up the user id for all chefs in the current game
const existingChefs =
Expand All @@ -388,8 +388,8 @@ export class GameService extends BaseService {
currentChef: constants.NONE,
currentRound: constants.NONE,
currentPhase: GamePhase.LOBBY,
hostChefId: newChefIds[hostChefIndex],
hostUserId: existingGame.hostUserId,
masterChefId: newChefIds[masterChefIndex],
masterChefUserId: existingGame.masterChefUserId,
lastGame: existingGame._id,
maxChefs: existingGame.maxChefs,
name: existingGame.name,
Expand Down Expand Up @@ -421,11 +421,11 @@ export class GameService extends BaseService {
const chefs = await Promise.all(chefCreations);

// Create action for game creation - this could be moved to an event or a method to encapsulate the logic
const hostChef = chefs.find(
(chef) => chef._id.toString() == newHostChefId.toString(),
const masterChef = chefs.find(
(chef) => chef._id.toString() == newMasterChefId.toString(),
);
await this.actionService.createGameAsync(newGame, hostChef, user);
return { game: newGame, chef: chefs[hostChefIndex] };
await this.actionService.createGameAsync(newGame, masterChef, user);
return { game: newGame, chef: chefs[masterChefIndex] };
}, session);
}

Expand Down Expand Up @@ -501,8 +501,8 @@ export class GameService extends BaseService {
game: IGameDocument,
userId: DefaultIdType,
): Promise<void> {
if (!(await this.playerService.isGameHostAsync(userId, game._id))) {
throw new NotHostError();
if (!(await this.playerService.isMasterChefAsync(userId, game._id))) {
throw new NotMasterChefError();
}
if (game.currentPhase !== GamePhase.LOBBY) {
throw new GameInProgressError();
Expand Down
4 changes: 2 additions & 2 deletions chili-and-cilantro-api/src/services/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ export class PlayerService extends BaseService {
* @param gameId
* @returns boolean
*/
public async isGameHostAsync(
public async isMasterChefAsync(
userId: DefaultIdType,
gameId: DefaultIdType,
): Promise<boolean> {
const GameModel = this.application.getModel<IGameDocument>(ModelName.Game);
try {
const count = await GameModel.countDocuments({
_id: gameId,
hostUserId: userId,
masterChefUserId: userId,
});

return count > 0;
Expand Down
30 changes: 14 additions & 16 deletions chili-and-cilantro-api/src/services/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@ export class UserService extends BaseService {
token: randomBytes(constants.EMAIL_TOKEN_LENGTH).toString('hex'),
lastSent: null,
createdAt: Date.now(),
expiresAt: new Date(Date.now() + constants.EMAIL_TOKEN_EXPIRATION),
expiresAt: new Date(Date.now() + constants.EMAIL_TOKEN_EXPIRATION_MS),
},
]);
if (emailTokens.length !== 1) {
throw new Error('Failed to create email token');
throw new Error(translate(StringNames.Error_FailedToCreateEmailToken));
}
return emailTokens[0];
}
Expand All @@ -97,7 +97,7 @@ export class UserService extends BaseService {
public async sendEmailToken(emailToken: IEmailTokenDocument): Promise<void> {
if (
emailToken.lastSent &&
emailToken.lastSent.getTime() + constants.EMAIL_TOKEN_RESEND_INTERVAL >
emailToken.lastSent.getTime() + constants.EMAIL_TOKEN_RESEND_INTERVAL_MS >
Date.now()
) {
throw new EmailTokenSentTooRecentlyError(emailToken.lastSent);
Expand All @@ -110,18 +110,18 @@ export class UserService extends BaseService {
msg = {
to: emailToken.email,
from: constants.EMAIL_FROM,
subject: `${constants.APPLICATION_NAME} email confirmation`,
text: `Please click the link below to confirm your email.\r\n\r\n${verifyUrl}`,
html: `<p>Please click the link below to confirm your email.</p><br/><p><a href="${verifyUrl}">${verifyUrl}</a></p><p>Link expires in ${constants.EMAIL_TOKEN_RESEND_INTERVAL / 1000} minutes.</p>`,
subject: `${translate(StringNames.Common_Site)} ${translate(StringNames.EmailToken_TitleEmailConfirm)}`,
text: `${translate(StringNames.EmailToken_ClickLinkEmailConfirm)}\r\n\r\n${verifyUrl}`,
html: `<p>${translate(StringNames.EmailToken_ClickLinkEmailConfirm)}</p><br/><p><a href="${verifyUrl}">${verifyUrl}</a></p><p>${translate(StringNames.EmailToken_ExpiresInTemplate)}</p>`,
};
break;
case EmailTokenType.PasswordReset:
msg = {
to: emailToken.email,
from: constants.EMAIL_FROM,
subject: `${constants.APPLICATION_NAME} password reset`,
text: `Please click the link below to reset your password.\r\n\r\n${passwordUrl}`,
html: `<p>Please click the link below to reset your password.</p><br/><p><a href="${passwordUrl}">${passwordUrl}</a></p><p>Link expires in ${constants.EMAIL_TOKEN_RESEND_INTERVAL / 1000} minutes.</p>`,
subject: `${translate(StringNames.Common_Site)} ${translate(StringNames.EmailToken_TitleResetPassword)}`,
text: `${translate(StringNames.EmailToken_ClickLinkResetPassword)}\r\n\r\n${passwordUrl}`,
html: `<p>${translate(StringNames.EmailToken_ClickLinkResetPassword)}</p><br/><p><a href="${passwordUrl}">${passwordUrl}</a></p><p>${translate(StringNames.EmailToken_ExpiresInTemplate)}</p>`,
};
break;
default:
Expand All @@ -133,12 +133,12 @@ export class UserService extends BaseService {
// update lastSent/expiration
emailToken.lastSent = new Date();
emailToken.expiresAt = new Date(
Date.now() + constants.EMAIL_TOKEN_EXPIRATION,
Date.now() + constants.EMAIL_TOKEN_EXPIRATION_MS,
);
await emailToken.save();
} catch (error) {
console.error('Error sending email:', error);
throw new Error('Failed to send verification email');
throw new Error(translate(StringNames.Error_SendTokenFailure));
}
}

Expand Down Expand Up @@ -308,7 +308,7 @@ export class UserService extends BaseService {
);
const now = new Date();
const minLastSentTime = new Date(
now.getTime() - constants.EMAIL_TOKEN_RESEND_INTERVAL,
now.getTime() - constants.EMAIL_TOKEN_RESEND_INTERVAL_MS,
);

// look up the most recent email token for a given user, then send it
Expand Down Expand Up @@ -438,17 +438,15 @@ export class UserService extends BaseService {
// We don't want to reveal whether an email exists in our system
return {
success: true,
message:
'If an account with that email exists, a password reset link has been sent.',
message: translate(StringNames.ResetPassword_Sent),
};
}

// Check if the user's email is not verified
if (!user.emailVerified) {
return {
success: false,
message:
'Please verify your email address before resetting your password.',
message: translate(StringNames.ResetPassword_ChangeEmailFirst),
};
}

Expand Down
2 changes: 1 addition & 1 deletion chili-and-cilantro-api/test/fixtures/chef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function generateChef(
lostCards: [],
userId: generateObjectId(),
state: ChefState.LOBBY,
host: false,
masterChef: false,
...overrides,
} as Partial<IChefDocument>;

Expand Down
18 changes: 9 additions & 9 deletions chili-and-cilantro-api/test/fixtures/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ export function generateGame(
withPassword = true,
overrides?: Partial<IGameDocument>,
): IGameDocument & MockedModel {
const hostChefId = generateObjectId();
const hostUserId = generateObjectId();
const masterChefId = generateObjectId();
const masterChefUserId = generateObjectId();
const gameData = {
_id: generateObjectId(),
code: UtilityService.generateGameCode(),
name: faker.lorem.words(3),
...(withPassword ? { password: generateGamePassword() } : {}),
chefIds: [hostChefId],
chefIds: [masterChefId],
eliminatedChefIds: [],
maxChefs: faker.number.int({
min: constants.MIN_CHEFS,
Expand All @@ -59,9 +59,9 @@ export function generateGame(
currentRound: constants.NONE,
roundBids: {},
roundWinners: {},
turnOrder: [hostChefId],
hostChefId: hostChefId,
hostUserId: hostUserId,
turnOrder: [masterChefId],
masterChefId: masterChefId,
masterUserId: masterChefUserId,
createdAt: faker.date.past(),
updatedAt: faker.date.past(),
...(overrides ? overrides : {}),
Expand Down Expand Up @@ -104,7 +104,7 @@ export function generateChefGameUser(
const user = generateUser(overrides?.user);
const chef = generateChef({
gameId,
host: true,
masterChef: true,
userId: user._id,
...overrides?.chef,
});
Expand All @@ -114,8 +114,8 @@ export function generateChefGameUser(
const chefIds = [chef._id, ...additionalChefs.map((c) => c._id)];
const game = generateGame(withPassword, {
_id: gameId,
hostUserId: user._id,
hostChefId: chef._id,
masterChefUserId: user._id,
masterChefId: chef._id,
chefIds: chefIds,
turnOrder: chefIds,
...overrides?.game,
Expand Down
Loading

0 comments on commit 02166e8

Please sign in to comment.