Skip to content

Commit

Permalink
feat: 권한 인증/인가, 초대 기능 구현 (#37)
Browse files Browse the repository at this point in the history
* docs: Swagger /api Auth

* feat: Req < userId 추가

* feat: [POST] /group manager 설정

* test: /group/create 주석

* feat: `owner`, `editor`, `viewer`

* refactor: max-len 120

* refactor: find > get

* refactor: group.auth < `owner`, `editors`, `viewers`

* feat: pushOwner when create group

* refactor: ParseObjectIdPipe when `groupId` parameter

* refactor: ParseObjectIdPipe when `eventId` parameter

* refactor: ParseObjectIdPipe when `memberId` parameter

* feat: validate group

* feat: group 권한 검증

* feat: 모임 편집자/조회자 초대

* refactor: UserController 정리하고 Swagger 병합

* feat: 모임 중복 초대시 예외처리

* feat: 디스코드 웹훅 ON

* test: rm group.controller.spec.ts

* fix: validate memberIds when deleteMembers

* fix: getEvent > getEvents

* test: TDD는 죽었다

* feat: getEvent
  • Loading branch information
w8385 authored May 25, 2024
1 parent 6c4cac7 commit 1460df8
Show file tree
Hide file tree
Showing 42 changed files with 435 additions and 620 deletions.
11 changes: 7 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ module.exports = {
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'max-len': [
'error',
{
code: 120,
},
],
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,3 @@ jobs:
cache: 'npm'
- run: npm ci
- run: npm run build --if-present
- run: npm test
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"printWidth": 80,
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "all",
"singleQuote": true,
Expand Down
10 changes: 6 additions & 4 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { APP_FILTER } from '@nestjs/core';

import { AuthModule } from './auth/auth.module';
import { AllExceptionsFilter } from './common/filters/all-exception.filter';
import { DebugModule } from './debug/debug.module';
import { EventModule } from './event/event.module';
import { GroupModule } from './group/group.module';
Expand All @@ -21,10 +23,10 @@ import { UserModule } from './user/user.module';
UserModule,
],
providers: [
// {
// provide: APP_FILTER,
// useClass: AllExceptionsFilter,
// },
{
provide: APP_FILTER,
useClass: AllExceptionsFilter,
},
],
})
export class AppModule {}
12 changes: 5 additions & 7 deletions src/auth/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';

Expand All @@ -20,9 +15,12 @@ export class AuthGuard implements CanActivate {
throw new UnauthorizedException();
}
try {
request['user'] = await this.jwtService.verifyAsync(token, {
const user = await this.jwtService.verifyAsync(token, {
secret: jwtConstants.secret,
});

request.user = user;
request.userId = user.sub;
} catch {
throw new UnauthorizedException();
}
Expand Down
4 changes: 2 additions & 2 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class AuthService {
const name = kakaoInfo.kakao_account.profile.nickname;
const email = kakaoInfo.kakao_account.email;

let user = await this.userService.findOneByKakaoId(kakaoId);
let user = await this.userService.getOneByKakaoId(kakaoId);
if (!user) {
user = await this.userService.create({
kakaoId,
Expand All @@ -130,7 +130,7 @@ export class AuthService {
async signout(kakaoToken: string) {
const { id } = await this.kakaoTokenInfo(kakaoToken);

this.userService.removeOneByKakaoId(id);
this.userService.deleteOneByKakaoId(id);
await this.kakaoUnlink(kakaoToken);

return { message: 'Successfully signed out' };
Expand Down
15 changes: 12 additions & 3 deletions src/common/configs/swagger.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@ const apiSwaggerConfig = (app: INestApplication) => {
.addTag('Member', '모임 회원 관련 API')
.addTag('Event', '이벤트 관련 API')
.addTag('Transaction', '거래 내역 관련 API')
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
},
'Authorization',
)
.build();

const document = SwaggerModule.createDocument(app, config, {
include: [GroupModule, MemberModule, EventModule, TransactionModule],
include: [GroupModule, MemberModule, EventModule, TransactionModule, UserModule],
});
SwaggerModule.setup('api', app, document);
};
Expand All @@ -45,7 +52,10 @@ const devSwaggerConfig = (app: INestApplication) => {
};

const authSwaggerConfig = (app: INestApplication) => {
const authorizationUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.KAKAO_REST_API_KEY}&redirect_uri=${process.env.KAKAO_REDIRECT_URI}&response_type=code&prompt=select_account`;
const authorizationUrl = `https://kauth.kakao.com/oauth/authorize
?client_id=${process.env.KAKAO_REST_API_KEY}
&redirect_uri=${process.env.KAKAO_REDIRECT_URI}
&response_type=code&prompt=select_account`;
const config = new DocumentBuilder()
.setTitle('sometime API')
.addTag('Auth', 'OAuth 인증 관련 API')
Expand All @@ -55,7 +65,6 @@ const authSwaggerConfig = (app: INestApplication) => {
flows: {
authorizationCode: {
authorizationUrl,
// tokenUrl: 'https://kauth.kakao.com/oauth/token',
scopes: undefined,
},
},
Expand Down
19 changes: 3 additions & 16 deletions src/common/filters/all-exception.filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { Request } from 'express';

Expand All @@ -21,10 +15,7 @@ export class AllExceptionsFilter implements ExceptionFilter {

const ctx = host.switchToHttp();

const httpStatus =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const httpStatus = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;

const request = ctx.getRequest<Request>();

Expand All @@ -33,11 +24,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
const message = exception instanceof Error ? exception.message : exception;
const timestamp = new Date().toISOString();

webhook.error(
`[${request.method}] ${path}`,
timestamp,
'error message: ' + message.toString(),
);
webhook.error(`[${request.method}] ${path}`, timestamp, 'error message: ' + message.toString());

httpAdapter.reply(
ctx.getResponse(),
Expand Down
7 changes: 1 addition & 6 deletions src/common/filters/http-exception.filter.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
Expand Down
15 changes: 15 additions & 0 deletions src/common/pipes/ParseObjectIdPipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
import { Types } from 'mongoose';

@Injectable()
export class ParseObjectIdPipe implements PipeTransform<any, Types.ObjectId> {
transform(value: any): Types.ObjectId {
const validObjectId = Types.ObjectId.isValid(value);

if (!validObjectId) {
throw new BadRequestException('Invalid ObjectId');
}

return Types.ObjectId.createFromHexString(value);
}
}
7 changes: 1 addition & 6 deletions src/debug/debug.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ import { DebugService } from './debug.service';
@Module({
imports: [DatabaseModule],
controllers: [DebugController],
providers: [
DebugService,
...groupProviders,
...memberProviders,
...eventProviders,
],
providers: [DebugService, ...groupProviders, ...memberProviders, ...eventProviders],
})
export class DebugModule {}
3 changes: 1 addition & 2 deletions src/event/event.providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { EventSchema } from './schemas/event.schema';
export const eventProviders = [
{
provide: 'EVENT_MODEL',
useFactory: (connection: Connection) =>
connection.model('Event', EventSchema),
useFactory: (connection: Connection) => connection.model('Event', EventSchema),
inject: ['MONGODB_CONNECTION'],
},
];
4 changes: 1 addition & 3 deletions src/event/event.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ export class EventRepository {
}

update(eventId: string, event: Event): Promise<Event> {
return this.eventModel
.findByIdAndUpdate(eventId, event, { new: true })
.exec() as Promise<Event>;
return this.eventModel.findByIdAndUpdate(eventId, event, { new: true }).exec() as Promise<Event>;
}

delete(eventId: string) {
Expand Down
23 changes: 5 additions & 18 deletions src/excel/excel.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,7 @@ export class ExcelService {
const worksheet = workbook.sheet(0); // Assume we are using the first worksheet

const transactions: Transaction[] = [];
const columns: string[] = [
'',
'거래일시',
'구분',
'거래금액',
'',
'',
'내용',
];
const columns: string[] = ['', '거래일시', '구분', '거래금액', '', '', '내용'];
const startRow = 12;
const endRow = worksheet.usedRange().endCell().rowNumber();

Expand All @@ -91,16 +83,11 @@ export class ExcelService {
const cell = row.cell(index + 1);
const value = cell.value(); // 셀 값 가져오기

if (columnName === '거래일시' && value)
transaction.timestamp = this.parseDate(value.toString().trim());
if (columnName === '구분' && value)
transaction.metadata.transactionType = value.toString().trim();
if (columnName === '거래일시' && value) transaction.timestamp = this.parseDate(value.toString().trim());
if (columnName === '구분' && value) transaction.metadata.transactionType = value.toString().trim();
if (columnName === '거래금액' && value)
transaction.metadata.amount = parseFloat(
value.toString().replace(/,/g, ''),
);
if (columnName === '내용' && value)
transaction.metadata.name = value.toString().trim();
transaction.metadata.amount = parseFloat(value.toString().replace(/,/g, ''));
if (columnName === '내용' && value) transaction.metadata.name = value.toString().trim();
});
transactions.push(transaction);
}
Expand Down
14 changes: 7 additions & 7 deletions src/group/entities/group.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ export class Group {
id: string;
name: string;
description: string;
manager: string;
subManagers: [
{
user: string;
authorities: string[];
},
];

auth: {
owner: any;
editors: any[];
viewers: any[];
};

members: any[];
events: any[];
}
Loading

0 comments on commit 1460df8

Please sign in to comment.