feat: add activity type

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei
2024-02-12 11:16:37 +08:00
parent 449b941c2c
commit 0cd84e7f9c
5 changed files with 155 additions and 6 deletions

View File

@@ -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()
}
}

View File

@@ -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({})
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}