Jelajahi Sumber

refactor: rename UpdateVideoMediaManageDto to UpdateVideoMediaTagsDto and update related methods for tag management

Dave 1 bulan lalu
induk
melakukan
7f298b8019

+ 2 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/provider-video-sync/provider-video-sync.service.ts

@@ -856,10 +856,12 @@ export class ProviderVideoSyncService {
         create: {
           ...record,
           sanitizedSecondTags: record.sanitizedSecondTags ?? [],
+          oSecondTags: record.secondTags ?? [],
         },
         update: {
           ...updateData,
           sanitizedSecondTags: (record as any).sanitizedSecondTags ?? [],
+          oSecondTags: (record as any).secondTags ?? [],
         },
       });
 

+ 5 - 8
apps/box-mgnt-api/src/mgnt-backend/feature/video-media/video-media.controller.ts

@@ -26,7 +26,7 @@ import {
 import { VideoMediaService } from './video-media.service';
 import {
   VideoMediaListQueryDto,
-  UpdateVideoMediaManageDto,
+  UpdateVideoMediaTagsDto,
   UpdateVideoMediaStatusDto,
   BatchUpdateVideoMediaStatusDto,
   VideoMediaListItemDto,
@@ -112,7 +112,7 @@ export class VideoMediaController {
     example: '507f1f77bcf86cd799439011',
   })
   @ApiBody({
-    type: UpdateVideoMediaManageDto,
+    type: UpdateVideoMediaTagsDto,
     description: '更新的管理信息',
   })
   @ApiOkResponse({
@@ -125,12 +125,9 @@ export class VideoMediaController {
   @ApiBadRequestResponse({
     description: '请求参数验证失败',
   })
-  @Patch(':id/manage')
-  async updateManage(
-    @Param('id') id: string,
-    @Body() dto: UpdateVideoMediaManageDto,
-  ) {
-    return this.videoMediaService.updateManage(id, dto);
+  @Post('update-video-tags')
+  async updateManage(@Body() dto: UpdateVideoMediaTagsDto) {
+    return this.videoMediaService.updateVideoTags(dto);
   }
 
   /**

+ 13 - 47
apps/box-mgnt-api/src/mgnt-backend/feature/video-media/video-media.dto.ts

@@ -10,6 +10,7 @@ import {
   Min,
   Max,
   MaxLength,
+  ArrayNotEmpty,
 } from 'class-validator';
 import { Type } from 'class-transformer';
 import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
@@ -87,60 +88,25 @@ export class VideoMediaListQueryDto extends PageListDto {
   updatedTo?: number;
 }
 
-export class UpdateVideoMediaManageDto {
-  @ApiPropertyOptional({
-    type: String,
-    maxLength: 200,
-    description: '视频标题',
-    example: '产品演示视频 2025',
-  })
-  @IsOptional()
-  @IsString()
-  @MaxLength(200)
-  title?: string;
-
-  /**
-   * 分类 ID,可为空(取消分类)
-   */
-  @ApiPropertyOptional({
+export class UpdateVideoMediaTagsDto {
+  @ApiProperty({
     type: String,
-    nullable: true,
-    description: '视频分类 MongoDB ID,设为 null 可取消分类',
+    description: '视频 MongoDB ID',
     example: '507f1f77bcf86cd799439011',
   })
-  @IsOptional()
-  @IsMongoId()
-  categoryId?: string | null;
+  @IsString()
+  id!: string;
 
-  /**
-   * 标签 ID 列表,最多 5 个
-   */
-  @ApiPropertyOptional({
+  @ApiProperty({
     type: [String],
-    maxItems: 5,
-    description: '视频标签 MongoDB ID 列表,最多 5 个',
-    example: ['507f1f77bcf86cd799439012', '507f1f77bcf86cd799439013'],
+    description: '视频标签',
+    example: ['xxx', 'zzz'],
+    minItems: 1,
   })
-  @IsOptional()
   @IsArray()
-  @IsMongoId({ each: true })
-  tagIds?: string[];
-
-  /**
-   * 上/下架状态,也可以在这里一起保存(可选)
-   * 0 = 下架, 1 = 上架
-   */
-  @ApiPropertyOptional({
-    type: Number,
-    enum: [0, 1],
-    description: '上下架状态: 0=下架, 1=上架',
-    example: 1,
-  })
-  @IsOptional()
-  @Type(() => Number)
-  @IsInt()
-  @IsIn([0, 1])
-  listStatus?: number;
+  @ArrayNotEmpty()
+  @IsString({ each: true })
+  tags!: string[];
 }
 
 export class UpdateVideoMediaStatusDto {

+ 19 - 60
apps/box-mgnt-api/src/mgnt-backend/feature/video-media/video-media.service.ts

@@ -14,7 +14,7 @@ import type { StorageStrategy } from '@box/core/media-manager/types';
 import { randomUUID } from 'crypto';
 import {
   VideoMediaListQueryDto,
-  UpdateVideoMediaManageDto,
+  UpdateVideoMediaTagsDto,
   UpdateVideoMediaStatusDto,
   BatchUpdateVideoMediaStatusDto,
 } from './video-media.dto';
@@ -327,77 +327,36 @@ export class VideoMediaService {
     };
   }
 
-  async updateManage(id: string, dto: UpdateVideoMediaManageDto) {
+  async updateVideoTags(dto: UpdateVideoMediaTagsDto) {
     const video = await this.prisma.videoMedia.findUnique({
-      where: { id },
+      where: { id: dto.id },
+      select: {
+        id: true,
+        oSecondTags: true,
+      },
     });
 
     if (!video) {
       throw new NotFoundException('Video not found');
     }
 
-    const updateData: any = {};
-
-    if (typeof dto.title === 'string') {
-      updateData.title = dto.title.trim();
-    }
-
-    let categoryId: string | null | undefined = dto.categoryId;
-    const tagIds: string[] | undefined = dto.tagIds;
-
-    if (dto.categoryId === null) {
-      categoryId = null;
-    }
-
-    if (typeof categoryId !== 'undefined' || typeof tagIds !== 'undefined') {
-      const { finalCategoryIds, finalTagIds, tags, tagsFlat } =
-        await this.validateCategoryAndTags(categoryId, tagIds);
+    const mgntTags = dto.tags; // DTO enforces non-empty string[]
+    const original = video.oSecondTags ?? [];
 
-      updateData.categoryIds = finalCategoryIds;
-      updateData.tagIds = finalTagIds;
-      updateData.tags = tags; // NEW: store denormalised tag names (lowercased)
-      updateData.tagsFlat = tagsFlat; // existing: text for search
-    }
-
-    if (typeof dto.listStatus === 'number') {
-      if (dto.listStatus !== 0 && dto.listStatus !== 1) {
-        throw new BadRequestException('Invalid listStatus value');
-      }
-      updateData.listStatus = dto.listStatus;
-    }
-
-    updateData.editedAt = BigInt(Date.now());
-    updateData.updatedAt = new Date();
+    // combine original + mgnt tags, keep order, remove duplicates
+    const mergedSecondTags = Array.from(new Set([...original, ...mgntTags]));
 
     await this.prisma.videoMedia.update({
-      where: { id },
-      data: updateData,
+      where: { id: dto.id },
+      data: {
+        tags: mgntTags,
+        secondTags: mergedSecondTags,
+        editedAt: BigInt(Math.floor(Date.now() / 1000)), // epoch seconds (BigInt)
+        updatedAt: new Date(),
+      },
     });
 
-    // Refresh category video lists cache if category changed or affected
-    if (video.categoryIds && video.categoryIds.length > 0) {
-      for (const cid of video.categoryIds) {
-        await this.cacheSyncService.scheduleAction({
-          entityType: CacheEntityType.VIDEO_LIST,
-          operation: 'REFRESH',
-          payload: { categoryId: cid },
-        } as any);
-      }
-    }
-    if (updateData.categoryIds && updateData.categoryIds.length > 0) {
-      const oldCategoryIds = new Set(video.categoryIds || []);
-      for (const cid of updateData.categoryIds) {
-        if (!oldCategoryIds.has(cid)) {
-          await this.cacheSyncService.scheduleAction({
-            entityType: CacheEntityType.VIDEO_LIST,
-            operation: 'REFRESH',
-            payload: { categoryId: cid },
-          } as any);
-        }
-      }
-    }
-
-    return this.findOne(id);
+    return this.findOne(dto.id);
   }
 
   async updateStatus(id: string, dto: UpdateVideoMediaStatusDto) {

+ 2 - 2
prisma/mongo/schema/video-media.prisma

@@ -77,14 +77,14 @@ model VideoMedia {
 
   sanitizedSecondTags    String[]  @default([])
 
-
   // all above fields are from provider, keep original, avoid updating,
   // use below fields for local video media controls
   categoryIds   String[]   @default([]) @db.ObjectId  // 分类 IDs (local, supports multiple categories)
   tagIds        String[]   @default([]) @db.ObjectId  // 标签 IDs (local, max 5)
 
   /// Denormalised tag names for fast read (store lowercased or display names)
-  tags          String[] @default([])
+  tags          String[]  @default([])
+  oSecondTags   String[]  @default([])
   
   /// Lowercased concatenation of tag names, for search
   tagsFlat      String     @default("")