diff --git a/src/modules/link/link.controller.ts b/src/modules/link/link.controller.ts index 439ff680..f505304f 100644 --- a/src/modules/link/link.controller.ts +++ b/src/modules/link/link.controller.ts @@ -23,7 +23,7 @@ import { BaseCrudModuleType, } from '~/transformers/crud-factor.transformer' -import { AduitReasonDto, LinkDto } from './link.dto' +import { AuditReasonDto, LinkDto } from './link.dto' import { LinkModel, LinkState } from './link.model' import { LinkService } from './link.service' @@ -122,7 +122,7 @@ export class LinkController { @HttpCode(201) async sendReasonByEmail( @Param() params: MongoIdDto, - @Body() body: AduitReasonDto, + @Body() body: AuditReasonDto, ) { const { id } = params const { reason, state } = body diff --git a/src/modules/link/link.dto.ts b/src/modules/link/link.dto.ts index e7b3a798..4868c481 100644 --- a/src/modules/link/link.dto.ts +++ b/src/modules/link/link.dto.ts @@ -8,7 +8,7 @@ export class LinkDto extends LinkModel { author: string } -export class AduitReasonDto { +export class AuditReasonDto { @IsString({ message: '请输入审核理由' }) reason: string diff --git a/src/modules/link/link.service.ts b/src/modules/link/link.service.ts index 4f40676e..85ae9479 100644 --- a/src/modules/link/link.service.ts +++ b/src/modules/link/link.service.ts @@ -34,21 +34,48 @@ export class LinkService { return this.linkModel } async applyForLink(model: LinkModel) { - try { - const doc = await this.model.create({ + const existedDoc = await this.model + .findOne({ + url: model.url, + }) + .lean() + + let nextModel: LinkModel + if (existedDoc) { + switch (existedDoc.state) { + case LinkState.Pass: + case LinkState.Audit: + throw new BadRequestException('请不要重复申请友链哦') + + case LinkState.Banned: + throw new BadRequestException('您的友链已被禁用,请联系管理员') + case LinkState.Reject: + case LinkState.Outdate: + nextModel = await this.model + .findOneAndUpdate( + { _id: existedDoc._id }, + { + $set: { + state: LinkState.Audit, + }, + }, + { new: true }, + ) + .lean() + } + } else { + nextModel = await this.model.create({ ...model, type: LinkType.Friend, state: LinkState.Audit, }) - - process.nextTick(() => { - this.eventManager.broadcast(BusinessEvents.LINK_APPLY, doc, { - scope: EventScope.TO_SYSTEM_ADMIN, - }) - }) - } catch (err) { - throw new BadRequestException('请不要重复申请友链哦') } + + process.nextTick(() => { + this.eventManager.broadcast(BusinessEvents.LINK_APPLY, nextModel, { + scope: EventScope.TO_SYSTEM_ADMIN, + }) + }) } async approveLink(id: string) { diff --git a/test/mock/modules/user.mock.ts b/test/mock/modules/user.mock.ts new file mode 100644 index 00000000..d6d326c6 --- /dev/null +++ b/test/mock/modules/user.mock.ts @@ -0,0 +1,8 @@ +import { defineProvider } from 'test/helper/defineProvider' + +import { UserService } from '~/modules/user/user.service' + +export const userProvider = defineProvider({ + provide: UserService, + useValue: {}, +}) diff --git a/test/src/modules/link/link.controller.e2e-spec.ts b/test/src/modules/link/link.controller.e2e-spec.ts new file mode 100644 index 00000000..9221c899 --- /dev/null +++ b/test/src/modules/link/link.controller.e2e-spec.ts @@ -0,0 +1,88 @@ +import { createE2EApp } from 'test/helper/create-e2e-app' +import { gatewayProviders } from 'test/mock/modules/gateway.mock' +import { userProvider } from 'test/mock/modules/user.mock' + +import { EventEmitter2 } from '@nestjs/event-emitter' +import { ReturnModelType } from '@typegoose/typegoose' + +import { OptionModel } from '~/modules/configs/configs.model' +import { ConfigsService } from '~/modules/configs/configs.service' +import { + LinkController, + LinkControllerCrud, +} from '~/modules/link/link.controller' +import { LinkModel, LinkState } from '~/modules/link/link.model' +import { LinkService } from '~/modules/link/link.service' +import { AssetService } from '~/processors/helper/helper.asset.service' +import { EmailService } from '~/processors/helper/helper.email.service' +import { EventManagerService } from '~/processors/helper/helper.event.service' +import { HttpService } from '~/processors/helper/helper.http.service' +import { SubPubBridgeService } from '~/processors/redis/subpub.service' + +describe('Test LinkController(E2E)', () => { + const proxy = createE2EApp({ + controllers: [LinkController, LinkControllerCrud], + models: [LinkModel, OptionModel], + providers: [ + ...gatewayProviders, + LinkService, + ConfigsService, + EmailService, + HttpService, + EventManagerService, + userProvider, + SubPubBridgeService, + AssetService, + EventEmitter2, + ], + async pourData(modelMap) { + const linkModel = modelMap.get(LinkModel) + + ;(linkModel.model as ReturnModelType).create({ + url: 'https://innei.ren', + name: 'innei', + avatar: 'https://innei.ren/avatar.png', + description: 'innei', + state: LinkState.Outdate, + }) + }, + }) + + it('should change state to audit', async () => { + const app = proxy.app + const res = await app.inject({ + method: 'post', + url: '/links/audit', + payload: { + url: 'https://innei.ren', + name: 'innnnn', + author: 'innei', + avatar: 'https://innei.ren/avatar.png', + description: 'innei', + }, + }) + expect(res.statusCode).toBe(204) + }) + + it('apply link repeat should throw', async () => { + const app = proxy.app + const res = await app.inject({ + method: 'post', + url: '/links/audit', + payload: { + url: 'https://innei.ren', + name: 'innnnn', + author: 'innei', + avatar: 'https://innei.ren/avatar.png', + description: 'innei', + }, + }) + expect(res.json()).toMatchInlineSnapshot(` + { + "error": "Bad Request", + "message": "请不要重复申请友链哦", + "statusCode": 400, + } + `) + }) +})