Skip to content

Commit

Permalink
fix: 병합 충돌 해결
Browse files Browse the repository at this point in the history
  • Loading branch information
seoko97 committed Nov 27, 2024
2 parents 926c8bf + 811628a commit cab0f0b
Show file tree
Hide file tree
Showing 56 changed files with 758 additions and 119 deletions.
49 changes: 27 additions & 22 deletions apps/api/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ThrottlerGuard } from '@nestjs/throttler';
import { Response } from 'express';

import { GetUserId } from '@/common/decorator/get-userId.decorator';
import { CookieConfig } from '@/config/cookie.config';

import { AuthService } from './auth.service';
import { LocalLoginRequestDto } from './dto/localLoginRequest.dto';
Expand All @@ -17,10 +18,15 @@ import { LocalAuthGuard } from './local/local-auth.guard';
@Controller('auth')
@ApiTags('Auth')
export class AuthController {
private readonly redirectUrl: string;

constructor(
private authService: AuthService,
private configService: ConfigService
) {}
private readonly authService: AuthService,
private readonly configService: ConfigService,
private readonly cookieConfig: CookieConfig
) {
this.redirectUrl = this.configService.get<string>('LOGIN_REDIRECT_URL');
}

@Post('signup')
@ApiOperation({ summary: '로컬 회원가입' })
Expand All @@ -38,16 +44,16 @@ export class AuthController {
@ApiResponse({ status: 401 })
@UseGuards(LocalAuthGuard)
localLogin(@GetUserId() userId: number, @Res() response: Response) {
this.cookieInsertJWT(response, userId);
this.loginProcess(response, userId);
}

@Post('guest/login')
@Get('guest/login')
@ApiOperation({ summary: '게스트 로그인' })
@ApiResponse({ status: 302, description: '홈으로 리다이렉션' })
@UseGuards(ThrottlerGuard)
async guestLogin(@Res() response: Response) {
const guestUser = await this.authService.createGuestUser();
this.cookieInsertJWT(response, guestUser.id);
this.loginProcess(response, guestUser.id);
}

@Get('google/login')
Expand All @@ -60,7 +66,7 @@ export class AuthController {
@Get('google/callback')
@UseGuards(GoogleAuthGuard)
googleAuthCallback(@GetUserId() userId: number, @Res() response: Response) {
this.cookieInsertJWT(response, userId);
this.loginProcess(response, userId);
}

@Get('github/login')
Expand All @@ -73,25 +79,24 @@ export class AuthController {
@Get('github/callback')
@UseGuards(GitHubAuthGuard)
githubAuthCallback(@GetUserId() userId: number, @Res() response: Response) {
this.cookieInsertJWT(response, userId);
this.loginProcess(response, userId);
}

private setAuthCookie(response: Response, accessToken: string) {
response.cookie('accessToken', accessToken, {
httpOnly: true,
secure: this.configService.get<string>('NODE_ENV') === 'production',
sameSite: 'lax',
path: '/',
});
@Get('logout')
@ApiOperation({ summary: '로그아웃' })
@ApiResponse({ status: 302, description: '홈으로 리다이렉션' })
logout(@Res() response: Response) {
response.clearCookie('accessToken', this.cookieConfig.getAuthCookieOptions());
this.redirectToHome(response);
}

private cookieInsertJWT(
response: Response,
userId: number,
redirectUrl: string = this.configService.get<string>('LOGIN_REDIRECT_URL')
) {
private loginProcess(response: Response, userId: number) {
const { accessToken } = this.authService.createJWT(userId);
this.setAuthCookie(response, accessToken);
response.redirect(redirectUrl);
response.cookie('accessToken', accessToken, this.cookieConfig.getAuthCookieOptions());
this.redirectToHome(response);
}

private redirectToHome(response: Response) {
response.redirect(this.redirectUrl);
}
}
10 changes: 9 additions & 1 deletion apps/api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';

import { CookieConfig } from '@/config/cookie.config';
import { UserModule } from '@/user/user.module';

import { AuthController } from './auth.controller';
Expand All @@ -27,6 +28,13 @@ import { LocalStrategy } from './local/local.strategy';
}),
],
controllers: [AuthController],
providers: [AuthService, LocalStrategy, JwtStrategy, GitHubStrategy, GoogleStrategy],
providers: [
AuthService,
LocalStrategy,
JwtStrategy,
GitHubStrategy,
GoogleStrategy,
CookieConfig,
],
})
export class AuthModule {}
10 changes: 7 additions & 3 deletions apps/api/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';
import { Provider } from '@repo/types';

import { CreateSocialUserDto } from '@/user/dto/createSocialUser.dto';
import { UserService } from '@/user/user.service';
Expand All @@ -15,7 +16,7 @@ export class AuthService {
) {}

async signupLocal(signupRequestDto: LocalSignupRequestDto) {
return this.userService.createLocalUser({ provider: 'local', ...signupRequestDto });
return this.userService.createLocalUser({ provider: Provider.local, ...signupRequestDto });
}

async validateLocalLogin(username: string, inputPassword: string) {
Expand All @@ -32,17 +33,20 @@ export class AuthService {

async createGuestUser() {
const randomNum = Math.floor(Math.random() * 10000);
const response = await fetch('https://api.thecatapi.com/v1/images/search');
const catImageUrl = (await response.json())[0].url;

const guestUser = {
username: `guest_${randomNum}`,
password: `guest_password_${randomNum}`,
email: `[email protected]`,
nickname: `guest_${randomNum}`,
introduce: `게스트 사용자입니다. `,
profileImageUrl: `https://cataas.com/cat?${Date.now()}`,
profileImageUrl: catImageUrl,
};
const user = await this.userService.findUserByUsername(guestUser.username);
if (!user) {
return this.userService.createLocalUser({ provider: 'guest', ...guestUser });
return this.userService.createLocalUser({ provider: Provider.guest, ...guestUser });
}
return user;
}
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/auth/github/github.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-github2';
import { Provider } from '@repo/types';

import { AuthService } from '../auth.service';

@Injectable()
export class GitHubStrategy extends PassportStrategy(Strategy, 'github') {
export class GitHubStrategy extends PassportStrategy(Strategy, Provider.github) {
constructor(
private configService: ConfigService,
private authService: AuthService
Expand All @@ -23,7 +24,7 @@ export class GitHubStrategy extends PassportStrategy(Strategy, 'github') {
const { id, username, emails, photos } = profile;

const user = {
provider: 'github',
provider: Provider.github,
socialId: id,
nickname: username,
email: emails[0].value,
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/auth/google/google.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-google-oauth20';
import { Provider } from '@repo/types';

import { AuthService } from '../auth.service';

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
export class GoogleStrategy extends PassportStrategy(Strategy, Provider.google) {
constructor(
private configService: ConfigService,
private authService: AuthService
Expand All @@ -23,7 +24,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
const { id, displayName, emails, photos } = profile;

const user = {
provider: 'google',
provider: Provider.google,
socialId: id,
nickname: displayName,
email: emails[0].value,
Expand Down
18 changes: 18 additions & 0 deletions apps/api/src/config/cookie.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// config/cookie.config.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { CookieOptions } from 'express';

@Injectable()
export class CookieConfig {
constructor(private configService: ConfigService) {}

getAuthCookieOptions(): CookieOptions {
return {
httpOnly: true,
secure: this.configService.get<string>('NODE_ENV') === 'production',
sameSite: 'lax',
path: '/',
};
}
}
3 changes: 3 additions & 0 deletions apps/api/src/entity/ticle.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,7 @@ export class Ticle {
},
})
tags: Tag[];

@Column({ type: 'varchar', name: 'profile_image_url', nullable: true })
profileImageUrl: string;
}
3 changes: 2 additions & 1 deletion apps/api/src/entity/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { Provider } from '@repo/types';

import { Applicant } from './applicant.entity';
import { Ticle } from './ticle.entity';
Expand Down Expand Up @@ -34,7 +35,7 @@ export class User {
profileImageUrl: string;

@Column({ type: 'varchar', default: 'local' })
provider: string;
provider: Provider;

@Column({ type: 'varchar', name: 'social_id', nullable: true })
socialId: string;
Expand Down
18 changes: 18 additions & 0 deletions apps/api/src/ticle/dto/ticleDetailDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ export class TickleDetailResponseDto {
})
speakerName: string;

@ApiProperty({
example: 1,
description: '발표자 유저 아이디',
})
speakerId: number;

@ApiProperty({
example: '[email protected]',
description: '발표자 이메일',
Expand Down Expand Up @@ -56,4 +62,16 @@ export class TickleDetailResponseDto {
description: '발표자 프로필 이미지 Url',
})
speakerImgUrl: string;

@ApiProperty({
example: 'true',
description: '티클의 호스트 여부',
})
isOwner: boolean;

@ApiProperty({
example: 'true',
description: '이미 참가신청을 했는지 여부',
})
alreadyApplied: boolean;
}
10 changes: 5 additions & 5 deletions apps/api/src/ticle/ticle.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ export class TicleController {
return this.ticleService.getTicleList(parsedQuery);
}

@Get('search')
getTicleSearchList() {}

@Get(':ticleId')
@UseGuards(JwtAuthGuard)
getTicle(@Param('ticleId') ticleId: number): Promise<TickleDetailResponseDto> {
return this.ticleService.getTicleByTicleId(ticleId);
getTicle(
@GetUserId() userId: number,
@Param('ticleId') ticleId: number
): Promise<TickleDetailResponseDto> {
return this.ticleService.getTicleByTicleId(userId, ticleId);
}

@Post(':ticleId/apply')
Expand Down
14 changes: 12 additions & 2 deletions apps/api/src/ticle/ticle.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,13 @@ export class TicleService {
return user;
}

async getTicleByTicleId(ticleId: number): Promise<TickleDetailResponseDto> {
async getTicleByTicleId(userId: number, ticleId: number): Promise<TickleDetailResponseDto> {
const ticle = await this.ticleRepository
.createQueryBuilder('ticle')
.leftJoinAndSelect('ticle.tags', 'tags')
.leftJoinAndSelect('ticle.speaker', 'speaker')
.select(['ticle', 'tags', 'speaker.id', 'speaker.profileImageUrl'])
.leftJoinAndSelect('ticle.applicants', 'applicants')
.select(['ticle', 'tags', 'speaker.id', 'speaker.profileImageUrl', 'applicants'])
.where('ticle.id = :id', { id: ticleId })
.getOne();

Expand All @@ -142,10 +143,15 @@ export class TicleService {
}
const { tags, speaker, ...ticleData } = ticle;

const alreadyApplied = ticle.applicants.some((applicnat) => applicnat.id === userId);

return {
...ticleData,
speakerId: ticle.speaker.id,
tags: tags.map((tag) => tag.name),
speakerImgUrl: speaker.profileImageUrl,
isOwner: speaker.id === userId,
alreadyApplied: alreadyApplied,
};
}

Expand All @@ -161,11 +167,14 @@ export class TicleService {
'ticle.endTime',
'ticle.speakerName',
'ticle.createdAt',
'ticle.profileImageUrl',
])
.addSelect('GROUP_CONCAT(DISTINCT tags.name)', 'tagNames')
.addSelect('COUNT(DISTINCT applicant.id)', 'applicantCount')
.addSelect('speaker.profile_image_url')
.leftJoin('ticle.tags', 'tags')
.leftJoin('ticle.applicants', 'applicant')
.leftJoin('ticle.speaker', 'speaker')
.where('ticle.ticleStatus = :status', {
status: isOpen ? TicleStatus.OPEN : TicleStatus.CLOSED,
})
Expand Down Expand Up @@ -201,6 +210,7 @@ export class TicleService {
speakerName: ticle.ticle_speaker_name,
applicantsCount: ticle.applicantCount,
createdAt: ticle.ticle_created_at,
speakerProfileImageUrl: ticle.profile_image_url,
}));

const totalPages = Math.ceil(totalTicleCount.count / pageSize);
Expand Down
4 changes: 3 additions & 1 deletion apps/api/src/user/dto/createLocalUser.dto.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Provider } from '@repo/types';

export class CreateLocalUserDto {
username: string;
password: string;
email: string;
provider: string;
provider: Provider;
nickname?: string;
introduce?: string;
profileImageUrl?: string;
Expand Down
4 changes: 3 additions & 1 deletion apps/api/src/user/dto/createSocialUser.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Provider } from '@repo/types';

export class CreateSocialUserDto {
email: string;
provider: string;
provider: Provider;
socialId: string;
nickname?: string;
introduce?: string;
Expand Down
Loading

0 comments on commit cab0f0b

Please sign in to comment.