Skip to content

Commit

Permalink
Merge pull request #461 from BinaryStudioAcademy/release-5.0.0
Browse files Browse the repository at this point in the history
Release 5.0.0
  • Loading branch information
nikita-remeslov authored Mar 19, 2024
2 parents a3cf89f + e6e4956 commit b49ab97
Show file tree
Hide file tree
Showing 332 changed files with 6,076 additions and 461 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@ build
.env
.idea


# PWA
dev-dist
6 changes: 3 additions & 3 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ STRAVA_CLIENT_ID=client_id
STRAVA_CLIENT_SECRET=client_secret

#
# GOOGLE FIT
# GOOGLE
#
GOOGLE_FIT_CLIENT_ID=client_id
GOOGLE_FIT_CLIENT_SECRET=client_secret
GOOGLE_CLIENT_ID=client_id
GOOGLE_CLIENT_SECRET=client_secret
2 changes: 2 additions & 0 deletions backend/fastify-types.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { type FastifyRequest as OriginalFastifyRequest } from 'fastify';
import { type Server as SocketServer } from 'socket.io';
import { type File } from '~/common/services/file/types/types.ts';

import { type UserAuthResponseDto } from '~/bundles/users/users.js';

declare module 'fastify' {
interface FastifyRequest extends OriginalFastifyRequest {
user: UserAuthResponseDto;
io: SocketServer;
file: File | null;
}
}
2 changes: 1 addition & 1 deletion backend/src/bundles/achievements/achievement.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class AchievementService {
await this.achievementRepository.findByUserId(userId);

if (!userAchievements || userAchievements.length === 0) {
throw new Error('User achievements not found');
return null;
}

return userAchievements;
Expand Down
3 changes: 2 additions & 1 deletion backend/src/bundles/achievements/achievements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const achievementController = new AchievementController(
achievementService,
);

export { achievementController, achievementService };
export { Achievements, ErrorMessage } from './enums/enums.js';
export { achievementController, achievementRepository, achievementService };
export { AchievementEntity } from './achievement.entity.js';
export { AchievementModel } from './achievement.model.js';
export { AchievementService } from './achievement.service.js';
5 changes: 5 additions & 0 deletions backend/src/bundles/achievements/enums/achievements.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const Achievements = {
JOIN: 'Joining Lime',
} as const;

export { Achievements };
2 changes: 2 additions & 0 deletions backend/src/bundles/achievements/enums/enums.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { Achievements } from './achievements.enum.js';
export { ErrorMessage } from './error-message.enum.js';
export { type Entity } from '~/common/types/entity.type.js';
export {
type AchievementGetItemResponseDto,
Expand Down
5 changes: 5 additions & 0 deletions backend/src/bundles/achievements/enums/error-message.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const ErrorMessage = {
ACHIEVEMENT_NOT_FOUND: 'Achievement was not found',
} as const;

export { ErrorMessage };
82 changes: 77 additions & 5 deletions backend/src/bundles/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { type UserAuthRequestDto } from '~/bundles/users/users.js';
import {
type UserAuthSignInRequestDto,
type UserAuthSignUpRequestDto,
} from '~/bundles/users/users.js';
import { userAuthValidationSchema } from '~/bundles/users/users.js';
import {
type ApiHandlerOptions,
Expand All @@ -12,6 +15,7 @@ import { type Logger } from '~/common/logger/logger.js';

import { type AuthService } from './auth.service.js';
import { AuthApiPath } from './enums/enums.js';
import { type IdentityAuthTokenDto } from './types/types.js';

class AuthController extends BaseController {
private authService: AuthService;
Expand All @@ -30,7 +34,7 @@ class AuthController extends BaseController {
handler: (options) =>
this.signUp(
options as ApiHandlerOptions<{
body: UserAuthRequestDto;
body: UserAuthSignUpRequestDto;
}>,
),
});
Expand All @@ -44,7 +48,18 @@ class AuthController extends BaseController {
handler: (options) =>
this.signIn(
options as ApiHandlerOptions<{
body: UserAuthRequestDto;
body: UserAuthSignInRequestDto;
}>,
),
});

this.addRoute({
path: AuthApiPath.IDENTITY,
method: 'POST',
handler: (options) =>
this.signInIdentity(
options as ApiHandlerOptions<{
body: IdentityAuthTokenDto;
}>,
),
});
Expand Down Expand Up @@ -94,7 +109,7 @@ class AuthController extends BaseController {

private async signIn(
options: ApiHandlerOptions<{
body: UserAuthRequestDto;
body: UserAuthSignInRequestDto;
}>,
): Promise<ApiHandlerResponse> {
return {
Expand All @@ -111,6 +126,13 @@ class AuthController extends BaseController {
* tags:
* - Auth
* description: Sign up user into the application
* parameters:
* - in: query
* name: referralCode
* schema:
* type: string
* required: false
* description: Optional referral code to invite other users
* requestBody:
* description: User auth data
* required: true
Expand Down Expand Up @@ -147,7 +169,7 @@ class AuthController extends BaseController {
*/
private async signUp(
options: ApiHandlerOptions<{
body: UserAuthRequestDto;
body: UserAuthSignUpRequestDto;
}>,
): Promise<ApiHandlerResponse> {
return {
Expand All @@ -156,6 +178,56 @@ class AuthController extends BaseController {
payload: await this.authService.signUp(options.body),
};
}

/**
* @swagger
* /api/v1/auth/sign-in-identity:
* post:
* tags:
* - Auth
* description: Sign in user into the application using token
* requestBody:
* description: Token data
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* token:
* type: string
* responses:
* 201:
* description: Successful operation
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: object
* $ref: '#/components/schemas/User'
* token:
* type: string
* 400:
* description: Failed operation
* content:
* application/json:
* schema:
* type: object
* $ref: '#/components/schemas/Error'
*/
private async signInIdentity(
options: ApiHandlerOptions<{
body: IdentityAuthTokenDto;
}>,
): Promise<ApiHandlerResponse> {
return {
type: ApiHandlerResponseType.DATA,
status: HttpCode.OK,
payload: await this.authService.signInIdentity(options.body),
};
}
}

export { AuthController };
102 changes: 94 additions & 8 deletions backend/src/bundles/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { IDENTITY_TOKEN_ADDITIONAL } from '~/bundles/identity/identity.js';
import {
type UserAuthRequestDto,
type UserAuthResponseDto,
type UserAuthSignInRequestDto,
type UserAuthSignUpRequestDto,
type UserService,
} from '~/bundles/users/users.js';
import { cryptService, jwtService } from '~/common/services/services.js';

import {
BonusAmount,
UserBonusActionType,
UserBonusTransactionType,
} from '../user-bonuses/user-bonuses.js';
import { HttpCode, HttpError, UserValidationMessage } from './enums/enums.js';
import { type AuthResponseDto } from './types/types.js';
import {
type AuthResponseDto,
type IdentityAuthTokenDto,
} from './types/types.js';

class AuthService {
private userService: UserService;
Expand All @@ -16,7 +26,7 @@ class AuthService {
}

private async verifyLoginCredentials(
userRequestDto: UserAuthRequestDto,
userRequestDto: UserAuthSignInRequestDto,
): Promise<UserAuthResponseDto> {
const user = await this.userService.find({
email: userRequestDto.email,
Expand All @@ -29,9 +39,18 @@ class AuthService {
});
}

const userPasswordHash = user.getPasswordHash();

if (!userPasswordHash) {
throw new HttpError({
message: UserValidationMessage.USER_OAUTH,
status: HttpCode.BAD_REQUEST,
});
}

const isEqualPassword = cryptService.compareSyncPassword(
userRequestDto.password,
user.getPasswordHash(),
userPasswordHash,
);

if (!isEqualPassword) {
Expand All @@ -45,7 +64,7 @@ class AuthService {
}

public async signIn(
userRequestDto: UserAuthRequestDto,
userRequestDto: UserAuthSignInRequestDto,
): Promise<AuthResponseDto> {
const user = await this.verifyLoginCredentials(userRequestDto);
const token = await jwtService.createToken({ userId: user.id });
Expand All @@ -54,10 +73,12 @@ class AuthService {
}

public async signUp(
userRequestDto: UserAuthRequestDto,
userRequestDto: UserAuthSignUpRequestDto,
): Promise<AuthResponseDto> {
const { referralCode, ...payload } = userRequestDto;

const userByEmail = await this.userService.find({
email: userRequestDto.email,
email: payload.email,
});

if (userByEmail) {
Expand All @@ -67,11 +88,76 @@ class AuthService {
});
}

const user = await this.userService.create(userRequestDto);
const inviterUser = await this.userService.findWithUserDetailsJoined({
referralCode,
});

if (referralCode && !inviterUser) {
throw new HttpError({
message: UserValidationMessage.USER_WITH_REFERRAL_ID_NOT_FOUND,
status: HttpCode.NOT_FOUND,
});
}

const user = await this.userService.create(payload);
const token = await jwtService.createToken({ userId: user.id });

if (referralCode && inviterUser) {
const { id: inviterId } = inviterUser.toObject();

await this.userService.createUserBonusTransaction({
userId: user.id,
actionType: UserBonusActionType.REGISTERED,
transactionType: UserBonusTransactionType.INCOME,
amount: BonusAmount[UserBonusActionType.REGISTERED],
});

await this.userService.createUserBonusTransaction({
userId: inviterId,
actionType: UserBonusActionType.INVITED,
transactionType: UserBonusTransactionType.INCOME,
amount: BonusAmount[UserBonusActionType.INVITED],
});

return {
user: {
...user,
bonusBalance: BonusAmount[UserBonusActionType.REGISTERED],
},
token,
};
}

return { user, token };
}

public async signInIdentity(
tokenRequestDto: IdentityAuthTokenDto,
): Promise<AuthResponseDto> {
try {
const { userId } = await jwtService.verifyToken(
tokenRequestDto.token,
IDENTITY_TOKEN_ADDITIONAL,
);

const userById = await this.userService.find({ id: userId });

if (!userById) {
throw new HttpError({
message: UserValidationMessage.USER_NOT_FOUND,
status: HttpCode.NOT_FOUND,
});
}
const user = userById.toObject();
const newToken = await jwtService.createToken({ userId: user.id });
return { user, token: newToken };
} catch {
throw new HttpError({
message: UserValidationMessage.TOKEN_INVALID,
status: HttpCode.FORBIDDEN,
});
}
}
}

export { AuthService };
6 changes: 5 additions & 1 deletion backend/src/bundles/auth/types/types.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export { type AuthResponseDto } from 'shared';
export {
type AuthResponseDto,
type AuthSignUpRequestDto,
type IdentityAuthTokenDto,
} from 'shared';
Loading

0 comments on commit b49ab97

Please sign in to comment.