issue #
- 디렉토리 구조 개선
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { defineConfig } from 'drizzle-kit';
|
import { defineConfig } from 'drizzle-kit';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config({ path: `.env.${process.env.NODE_ENV}` });
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
dialect: "postgresql",
|
dialect: "postgresql",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const userBlockingIdSeq = pgSequence("user_blocking_id_seq", { startWith
|
|||||||
export const emailAddressIdSeq = pgSequence("email_address_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false })
|
export const emailAddressIdSeq = pgSequence("email_address_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false })
|
||||||
|
|
||||||
export const comment = pgTable("comment", {
|
export const comment = pgTable("comment", {
|
||||||
id: uuid().primaryKey().notNull(),
|
id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
|
||||||
content: text(),
|
content: text(),
|
||||||
createdAt: date("created_at"),
|
createdAt: date("created_at"),
|
||||||
isDeleted: boolean("is_deleted").default(false),
|
isDeleted: boolean("is_deleted").default(false),
|
||||||
@@ -72,19 +72,20 @@ export const participant = pgTable("participant", {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export const schedule = pgTable("schedule", {
|
export const schedule = pgTable("schedule", {
|
||||||
id: uuid().primaryKey().notNull(),
|
id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
|
||||||
name: varchar(),
|
name: varchar().notNull(),
|
||||||
startDate: date("start_date"),
|
startDate: date("start_date").notNull(),
|
||||||
endDate: date("end_date"),
|
endDate: date("end_date").notNull(),
|
||||||
status: varchar(),
|
status: varchar().default('yet').notNull(),
|
||||||
content: text(),
|
content: text(),
|
||||||
isDeleted: boolean("is_deleted").default(false),
|
isDeleted: boolean("is_deleted").default(false).notNull(),
|
||||||
type: varchar(),
|
type: varchar().notNull(),
|
||||||
createdAt: date("created_at"),
|
createdAt: date("created_at"),
|
||||||
owner: uuid(),
|
owner: uuid().notNull(),
|
||||||
style: varchar(),
|
style: varchar().notNull(),
|
||||||
startTime: time("start_time"),
|
startTime: time("start_time").notNull(),
|
||||||
endTime: time("end_time"),
|
endTime: time("end_time").notNull(),
|
||||||
|
dayList: varchar("day_list"),
|
||||||
}, (table) => [
|
}, (table) => [
|
||||||
index("schedule_enddatetime_idx").using("btree", table.endDate.asc().nullsLast().op("date_ops")),
|
index("schedule_enddatetime_idx").using("btree", table.endDate.asc().nullsLast().op("date_ops")),
|
||||||
index("schedule_name_idx").using("btree", table.name.asc().nullsLast().op("text_ops"), table.content.asc().nullsLast().op("text_ops")),
|
index("schedule_name_idx").using("btree", table.name.asc().nullsLast().op("text_ops"), table.content.asc().nullsLast().op("text_ops")),
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { RedisModule } from './redis/redis.module';
|
|||||||
import { AccountModule } from './modules/account/account.module';
|
import { AccountModule } from './modules/account/account.module';
|
||||||
import { MailerModule } from './util/mailer/mailer.module';
|
import { MailerModule } from './util/mailer/mailer.module';
|
||||||
import { AppConfigModule } from './config/config.module';
|
import { AppConfigModule } from './config/config.module';
|
||||||
|
import { ScheduleModule } from './modules/schedule/schedule.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [AppConfigModule, DbModule, RedisModule, MailerModule, AccountModule],
|
imports: [AppConfigModule, DbModule, RedisModule, MailerModule, AccountModule, ScheduleModule],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus
|
HttpStatus
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { JsonWebTokenError, TokenExpiredError } from '@nestjs/jwt';
|
||||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
|
|
||||||
@Catch()
|
@Catch()
|
||||||
@@ -13,6 +14,39 @@ export class AllExceptionsFilter implements ExceptionFilter {
|
|||||||
const ctx = host.switchToHttp();
|
const ctx = host.switchToHttp();
|
||||||
const response = ctx.getResponse<FastifyReply>();
|
const response = ctx.getResponse<FastifyReply>();
|
||||||
const request = ctx.getRequest<FastifyRequest>();
|
const request = ctx.getRequest<FastifyRequest>();
|
||||||
|
console.log(exception);
|
||||||
|
|
||||||
|
// TokenExpiredError
|
||||||
|
if (exception instanceof TokenExpiredError) {
|
||||||
|
const status = HttpStatus.UNAUTHORIZED;
|
||||||
|
|
||||||
|
const responseBody = {
|
||||||
|
statusCode: status,
|
||||||
|
message: 'Access Token Expired',
|
||||||
|
code: 'AccessTokenExpired',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
path: ctx.getRequest().url
|
||||||
|
};
|
||||||
|
|
||||||
|
response.status(status).send(responseBody);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JsonWebTokenError
|
||||||
|
if (exception instanceof JsonWebTokenError) {
|
||||||
|
const status = HttpStatus.UNAUTHORIZED;
|
||||||
|
|
||||||
|
const responseBody = {
|
||||||
|
statusCode: status,
|
||||||
|
message: 'Invalid Token',
|
||||||
|
code: 'InvalidToken',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
path: ctx.getRequest().url
|
||||||
|
};
|
||||||
|
|
||||||
|
response.status(status).send(responseBody);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let status =
|
let status =
|
||||||
exception instanceof HttpException
|
exception instanceof HttpException
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ async function bootstrap() {
|
|||||||
app.register(fastifyCookie, {
|
app.register(fastifyCookie, {
|
||||||
secret: process.env.JWT_SECRET
|
secret: process.env.JWT_SECRET
|
||||||
});
|
});
|
||||||
await app.listen(process.env.PORT ?? 3000, '0.0.0.0', () => { process.env.NODE_ENV !== 'prod' && console.log(`servier is running on ${process.env.PORT}`) });
|
// await app.listen(process.env.PORT ?? 3000, '0.0.0.0', () => { process.env.NODE_ENV !== 'prod' && console.log(`servier is running on ${process.env.PORT}`) });
|
||||||
|
await app.listen(process.env.PORT || 3000, () => { process.env.NODE_ENV !== 'prod' && console.log(`service is running on ${process.env.PORT}`)});
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export class AuthService {
|
|||||||
constructor(private readonly jwtService: JwtService) {}
|
constructor(private readonly jwtService: JwtService) {}
|
||||||
|
|
||||||
generateTokens(id: string) {
|
generateTokens(id: string) {
|
||||||
const accessToken = this.jwtService.sign({id: id}, { expiresIn: '5s' });
|
const accessToken = this.jwtService.sign({id: id}, { expiresIn: '1m' });
|
||||||
const refreshToken = this.jwtService.sign({id: id}, { expiresIn: '7d' });
|
const refreshToken = this.jwtService.sign({id: id}, { expiresIn: '7d' });
|
||||||
|
|
||||||
return { accessToken, refreshToken };
|
return { accessToken, refreshToken };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
|
import { ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
|
||||||
import { Reflector } from "@nestjs/core";
|
import { Reflector } from "@nestjs/core";
|
||||||
import { TokenExpiredError } from "@nestjs/jwt";
|
import { JsonWebTokenError, TokenExpiredError } from "@nestjs/jwt";
|
||||||
import { AuthGuard } from "@nestjs/passport";
|
import { AuthGuard } from "@nestjs/passport";
|
||||||
import { IS_PUBLIC_KEY } from "src/common/decorators/public.decorator";
|
import { IS_PUBLIC_KEY } from "src/common/decorators/public.decorator";
|
||||||
|
|
||||||
@@ -23,23 +23,18 @@ export class JwtAccessAuthGuard extends AuthGuard('access-token') {
|
|||||||
return super.canActivate(context);
|
return super.canActivate(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRequest(err: any, user:any, info:any) {
|
handleRequest(err: any, user:any, info:any, context: ExecutionContext) {
|
||||||
if (info instanceof TokenExpiredError) {
|
|
||||||
throw new UnauthorizedException({
|
|
||||||
statusCode: 401,
|
|
||||||
message: 'Access Token Expired',
|
|
||||||
code: 'AccessTokenExpired'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err || !user) {
|
if (err || !user) {
|
||||||
throw new UnauthorizedException({
|
if (info instanceof TokenExpiredError) {
|
||||||
statusCode: 401,
|
throw info;
|
||||||
message: 'Invalid Token',
|
}
|
||||||
code: 'InvalidToken'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (info instanceof JsonWebTokenError) {
|
||||||
|
throw info;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err || new JsonWebTokenError('Unauthorized');
|
||||||
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ import { Injectable, UnauthorizedException } from "@nestjs/common";
|
|||||||
import { ConfigService } from "@nestjs/config";
|
import { ConfigService } from "@nestjs/config";
|
||||||
import { PassportStrategy } from "@nestjs/passport";
|
import { PassportStrategy } from "@nestjs/passport";
|
||||||
import { ExtractJwt, Strategy } from "passport-jwt";
|
import { ExtractJwt, Strategy } from "passport-jwt";
|
||||||
|
import { AccountRepo } from "src/modules/account/account.repo";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JwtAccessStrategy extends PassportStrategy(Strategy, "access-token") {
|
export class JwtAccessStrategy extends PassportStrategy(Strategy, "access-token") {
|
||||||
constructor(configService: ConfigService) {
|
constructor(
|
||||||
|
configService: ConfigService,
|
||||||
|
private accountRepo: AccountRepo
|
||||||
|
) {
|
||||||
super({
|
super({
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||||
secretOrKey: configService.get<string>('JWT_SECRET')!
|
secretOrKey: configService.get<string>('JWT_SECRET')!
|
||||||
@@ -13,10 +17,11 @@ export class JwtAccessStrategy extends PassportStrategy(Strategy, "access-token"
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validate(payload: any) {
|
async validate(payload: any) {
|
||||||
const token = ExtractJwt.fromAuthHeaderAsBearerToken();
|
console.log(payload);
|
||||||
if (!token) {
|
const user = await this.accountRepo.findById(payload.id);
|
||||||
|
if (!user) {
|
||||||
throw new UnauthorizedException();
|
throw new UnauthorizedException();
|
||||||
}
|
}
|
||||||
return { id: payload.id };
|
return user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ export class AccountRepo {
|
|||||||
email: string,
|
email: string,
|
||||||
password: string
|
password: string
|
||||||
) {
|
) {
|
||||||
return this
|
return await this
|
||||||
.db
|
.db
|
||||||
.insert(schema.account)
|
.insert(schema.account)
|
||||||
.values({
|
.values({
|
||||||
@@ -42,7 +42,7 @@ export class AccountRepo {
|
|||||||
type: 'email' | 'accountId'
|
type: 'email' | 'accountId'
|
||||||
, id: string
|
, id: string
|
||||||
) {
|
) {
|
||||||
return this
|
return await this
|
||||||
.db
|
.db
|
||||||
.select()
|
.select()
|
||||||
.from(schema.account)
|
.from(schema.account)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class CheckDuplicationResponseDto extends BaseResponseDto {
|
export class CheckDuplicationResponseDto extends BaseResponseDto {
|
||||||
isDuplicated: boolean;
|
isDuplicated: boolean;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class LoginResponseDto extends BaseResponseDto {
|
export class LoginResponseDto extends BaseResponseDto {
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class RefreshAccessTokenResponseDto extends BaseResponseDto{
|
export class RefreshAccessTokenResponseDto extends BaseResponseDto{
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class ResetPasswordResponseDto extends BaseResponseDto {
|
export class ResetPasswordResponseDto extends BaseResponseDto {
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class SendEmailVerificationCodeResponseDto extends BaseResponseDto{
|
export class SendEmailVerificationCodeResponseDto extends BaseResponseDto{
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class SendResetPasswordCodeResponseDto extends BaseResponseDto {
|
export class SendResetPasswordCodeResponseDto extends BaseResponseDto {
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class SignupResponseDto extends BaseResponseDto {
|
export class SignupResponseDto extends BaseResponseDto {
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class VerifyEmailVerificationCodeResponseDto extends BaseResponseDto{
|
export class VerifyEmailVerificationCodeResponseDto extends BaseResponseDto{
|
||||||
verified: boolean;
|
verified: boolean;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BaseResponseDto } from "../base-response.dto";
|
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
|
||||||
|
|
||||||
export class VerifyResetPasswordCodeResponseDto extends BaseResponseDto {
|
export class VerifyResetPasswordCodeResponseDto extends BaseResponseDto {
|
||||||
verified: boolean;
|
verified: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user