From 0cd84e7f9c5d314bedcaa64d3c7bb391f7734828 Mon Sep 17 00:00:00 2001 From: Innei Date: Mon, 12 Feb 2024 11:16:37 +0800 Subject: [PATCH] feat: add activity type Signed-off-by: Innei --- .../modules/activity/activity.controller.ts | 39 +++++++++++++-- .../src/modules/activity/activity.service.ts | 48 ++++++++++++++++++- .../src/modules/activity/activity.util.ts | 4 ++ .../src/modules/activity/dtos/activity.dto.ts | 28 +++++++++++ .../processors/database/database.service.ts | 42 ++++++++++++++++ 5 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 apps/core/src/modules/activity/dtos/activity.dto.ts diff --git a/apps/core/src/modules/activity/activity.controller.ts b/apps/core/src/modules/activity/activity.controller.ts index b1a52c29..ae14a156 100644 --- a/apps/core/src/modules/activity/activity.controller.ts +++ b/apps/core/src/modules/activity/activity.controller.ts @@ -1,6 +1,6 @@ import { keyBy } from 'lodash' -import { Body, Get, Post, Query } from '@nestjs/common' +import { Body, Delete, Get, Param, Post, Query } from '@nestjs/common' import { ApiController } from '~/common/decorators/api-controller.decorator' import { Auth } from '~/common/decorators/auth.decorator' @@ -8,7 +8,13 @@ import { HTTPDecorators } from '~/common/decorators/http.decorator' import { IpLocation, IpRecord } from '~/common/decorators/ip.decorator' import { PagerDto } from '~/shared/dto/pager.dto' +import { Activity } from './activity.constant' import { ActivityService } from './activity.service' +import { + ActivityDeleteDto, + ActivityQueryDto, + ActivityTypeParamsDto, +} from './dtos/activity.dto' import { LikeBodyDto } from './dtos/like.dto' import { GetPresenceQueryDto, UpdatePresenceDto } from './dtos/presence.dto' @@ -39,11 +45,16 @@ export class ActivityController { @Get('/') @Auth() - async activities(@Query() pager: PagerDto) { - const { page, size } = pager + async activities(@Query() pager: ActivityQueryDto) { + const { page, size, type } = pager - // TODO currently only support like activities, so hard code here - return this.service.getLikeActivities(page, size) + switch (type) { + case Activity.Like: + return this.service.getLikeActivities(page, size) + + case Activity.ReadDuration: + return this.service.getReadDurationActivities(page, size) + } } @Post('/presence/update') @@ -68,4 +79,22 @@ export class ActivityController { return keyBy(list, 'identity') }) } + + @Delete('/:type') + @Auth() + async deletePresence( + @Param() params: ActivityTypeParamsDto, + @Body() Body: ActivityDeleteDto, + ) { + return this.service.deleteActivityByType( + params.type, + Body.before ? new Date(Body.before) : new Date(), + ) + } + + @Auth() + @Delete('/all') + async deleteAllPresence() { + return this.service.deleteAll() + } } diff --git a/apps/core/src/modules/activity/activity.service.ts b/apps/core/src/modules/activity/activity.service.ts index 72720d7a..2d245e37 100644 --- a/apps/core/src/modules/activity/activity.service.ts +++ b/apps/core/src/modules/activity/activity.service.ts @@ -22,7 +22,7 @@ import { transformDataToPaginate } from '~/transformers/paginate.transformer' import { Activity } from './activity.constant' import { ActivityModel } from './activity.model' -import { isValidRoomName } from './activity.util' +import { extractArticleIdFromRoomName, isValidRoomName } from './activity.util' declare module '~/utils/socket.util' { interface SocketMetadata { @@ -187,6 +187,39 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy { return transformedPager } + async getReadDurationActivities(page = 1, size = 10) { + const activities = await this.model.paginate( + { + type: Activity.ReadDuration, + }, + { + page, + limit: size, + sort: { + created: -1, + }, + }, + ) + const data = transformDataToPaginate(activities) + + const articleIds = [] as string[] + for (let i = 0; i < data.data.length; i++) { + const item = data.data[i] + const roomName = item.payload.roomName + if (!roomName) continue + const refId = extractArticleIdFromRoomName(roomName) + articleIds.push(refId) + data.data[i] = data.data[i].toObject() + ;(data.data[i] as any).refId = refId + } + + const documentMap = await this.databaseService.findGlobalByIds(articleIds) + return { + ...data, + objects: documentMap, + } + } + async likeAndEmit(type: ActivityLikeSupportType, id: string, ip: string) { try { const res = await this.countingService.updateLikeCountWithIp(type, id, ip) @@ -297,4 +330,17 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy { (x) => x.identity, ) } + + async deleteActivityByType(type: Activity, beforeDate: Date) { + return this.model.deleteMany({ + type, + created: { + $lt: beforeDate, + }, + }) + } + + async deleteAll() { + return this.model.deleteMany({}) + } } diff --git a/apps/core/src/modules/activity/activity.util.ts b/apps/core/src/modules/activity/activity.util.ts index 5cdda83e..21a9726d 100644 --- a/apps/core/src/modules/activity/activity.util.ts +++ b/apps/core/src/modules/activity/activity.util.ts @@ -5,3 +5,7 @@ export const isValidRoomName = (roomName: string) => { export const getArticleIdFromRoomName = (roomName: string) => roomName.slice(prefix.length) + +export const extractArticleIdFromRoomName = (roomName: string) => { + return roomName.slice(prefix.length) +} diff --git a/apps/core/src/modules/activity/dtos/activity.dto.ts b/apps/core/src/modules/activity/dtos/activity.dto.ts new file mode 100644 index 00000000..fe2482bb --- /dev/null +++ b/apps/core/src/modules/activity/dtos/activity.dto.ts @@ -0,0 +1,28 @@ +import { Transform } from 'class-transformer' +import { IsEnum, IsNumber, IsOptional } from 'class-validator' + +import { PagerDto } from '~/shared/dto/pager.dto' + +import { Activity } from '../activity.constant' + +const TransformEnum = () => + Transform(({ value }) => (typeof value === 'undefined' ? value : +value)) + +export class ActivityTypeParamsDto { + @IsEnum(Activity) + @TransformEnum() + type: Activity +} + +export class ActivityDeleteDto { + @IsNumber() + @IsOptional() + before?: number +} + +export class ActivityQueryDto extends PagerDto { + @IsEnum(Activity) + @IsOptional() + @TransformEnum() + type: Activity +} diff --git a/apps/core/src/processors/database/database.service.ts b/apps/core/src/processors/database/database.service.ts index c80dce13..53b39661 100644 --- a/apps/core/src/processors/database/database.service.ts +++ b/apps/core/src/processors/database/database.service.ts @@ -128,6 +128,48 @@ export class DatabaseService { } } + public async findGlobalByIds(ids: string[]): Promise<{ + posts: PostModel[] + notes: NoteModel[] + pages: PageModel[] + recentlies: RecentlyModel[] + }> + public async findGlobalByIds(ids: string[]) { + const doc = await Promise.all([ + this.postModel + .find({ + _id: { $in: ids }, + }) + .populate('category') + .lean(), + this.noteModel + .find({ + _id: { $in: ids }, + }) + .lean({ autopopulate: true }) + .select('+password'), + this.pageModel + .find({ + _id: { $in: ids }, + }) + .lean(), + this.recentlyModel + .find({ + _id: { $in: ids }, + }) + .lean(), + ]) + + const result = doc.reduce((acc, list, index) => { + return { + ...acc, + [(['posts', 'notes', 'pages', 'recentlies'] as const)[index]]: list, + } + }, {}) + + return result as any + } + public get db() { return this.connection.db }