Skip to content

Commit

Permalink
feat: 관리 페이지와 api 구현 (#197)
Browse files Browse the repository at this point in the history
* feat: admin resource 구현

* feat: 관리자 페이지 추가

* feat: cors 설정 추가

* feat: 임시로 관리자 페이지 권한 제거

* feat: admin sse api 구현

* refactor: redis sub 서비스 구현

* feat: 어드민 페이지 api 기능 추가

* feat: redis pub 서비스 추가

* refactor: admin controller에 redis service로 교체

* feat: log interceptor에 redis pub 추가

* refactor: channels const로 분리

* style: 불필요한 주석 제거

* feat: ws 로그 redis pub 추가

* feat: admin page 박스 누르면 펼치기/접기 기능 추가

* feat: admin 페이지 색깔 변경

* feat: 관리자 페이지 로그인 기능 구현
  • Loading branch information
yangdongsuk authored Dec 7, 2023
1 parent 0014655 commit 5c2f20a
Show file tree
Hide file tree
Showing 18 changed files with 577 additions and 33 deletions.
1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"axios": "^1.6.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"cookie-parser": "^1.4.6",
"nest-winston": "^1.9.4",
"pg": "^8.11.3",
"redis": "^4.6.11",
Expand Down
15 changes: 13 additions & 2 deletions server/redis/redis.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DynamicModule, Global, Module } from '@nestjs/common';
import { RedisClientType, createClient } from 'redis';
import { RedisService } from './redis.service';

/**
* RedisModule은 NestJS 애플리케이션에서 Redis 클라이언트를 설정하고 관리하는데 사용되는 모듈이다.
Expand Down Expand Up @@ -64,8 +65,18 @@ export class RedisModule {
*/
return {
module: RedisModule,
providers: [redisProvider, redisPubProvider, redisSubProvider],
exports: [redisProvider, redisPubProvider, redisSubProvider],
providers: [
redisProvider,
redisPubProvider,
redisSubProvider,
RedisService,
],
exports: [
redisProvider,
redisPubProvider,
redisSubProvider,
RedisService,
],
};
}
}
21 changes: 21 additions & 0 deletions server/redis/redis.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Inject, Injectable } from '@nestjs/common';
import { RedisClientType } from 'redis';

@Injectable()
export class RedisService {
constructor(
@Inject('REDIS_SUB_CLIENT')
private readonly redisSubscriber: RedisClientType,
@Inject('REDIS_PUB_CLIENT')
private readonly redisPublisher: RedisClientType,
) {}

subscribeToChannel(channel: string, callback: Function) {
this.redisSubscriber.subscribe(channel, (message) => {
callback(message);
});
}
publishToChannel(channel: string, message: string) {
this.redisPublisher.publish(channel, message);
}
}
20 changes: 20 additions & 0 deletions server/src/admin/admin.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AdminController } from './admin.controller';
import { AdminService } from './admin.service';

describe('AdminController', () => {
let controller: AdminController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AdminController],
providers: [AdminService],
}).compile();

controller = module.get<AdminController>(AdminController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
59 changes: 59 additions & 0 deletions server/src/admin/admin.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
Controller,
Get,
Req,
Res,
UnauthorizedException,
} from '@nestjs/common';
import { Response } from 'express';
import { RedisService } from 'redis/redis.service';
import { UserId } from 'src/users/decorator/userId.decorator';
import { channels } from './const/channels.const';

@Controller('admin')
export class AdminController {
constructor(private readonly redisService: RedisService) {}

@Get('events')
sse(@Req() req, @Res() res: Response, @UserId() userId: number) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();

if (userId !== 1) {
throw new UnauthorizedException('관리자가 아닙니다.');
}

const changeFormat = (channel, message) => {
const result = { channel, message };
return JSON.stringify(result);
};

res.write(`data: ${changeFormat('notice', 'Server connected')}\n\n`);
channels.forEach((channel) => {
this.redisService.subscribeToChannel(channel, (message) => {
res.write(`data: ${changeFormat(channel, message)}\n\n`);
});
});

req.on('close', () => {
res.end();
});
}
@Get('generate')
generate(@UserId() userId: number) {
if (userId !== 1) {
throw new UnauthorizedException('관리자가 아닙니다.');
}
this.redisService.publishToChannel('channel', 'processAiResult');
}

@Get('category')
category(@UserId() userId: number) {
if (userId !== 1) {
throw new UnauthorizedException('관리자가 아닙니다.');
}
this.redisService.publishToChannel('channel', 'processCategory');
}
}
9 changes: 9 additions & 0 deletions server/src/admin/admin.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { AdminController } from './admin.controller';
import { AdminService } from './admin.service';

@Module({
controllers: [AdminController],
providers: [AdminService],
})
export class AdminModule {}
18 changes: 18 additions & 0 deletions server/src/admin/admin.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AdminService } from './admin.service';

describe('AdminService', () => {
let service: AdminService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AdminService],
}).compile();

service = module.get<AdminService>(AdminService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
4 changes: 4 additions & 0 deletions server/src/admin/admin.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';

@Injectable()
export class AdminService {}
7 changes: 7 additions & 0 deletions server/src/admin/const/channels.const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const channels = [
'channel',
'sharedChecklist',
'ai_result',
'httpLog',
'wsLog',
];
Loading

0 comments on commit 5c2f20a

Please sign in to comment.