ソースを参照

feat(category, tag): add toggle status endpoints and implement corresponding service methods

Dave 2 ヶ月 前
コミット
60c2f45fb3

+ 12 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/category/category.controller.ts

@@ -5,6 +5,7 @@ import {
   Delete,
   Get,
   Param,
+  Patch,
   Post,
   Put,
 } from '@nestjs/common';
@@ -77,4 +78,15 @@ export class CategoryController {
   remove(@Param() { id }: MongoIdParamDto) {
     return this.service.remove(id);
   }
+
+  // add Patch endpoints for status toggles
+  @Patch(':id/status')
+  @ApiOperation({ summary: 'Toggle category status' })
+  @ApiResponse({ status: 200, description: 'Status toggle result' })
+  toggleStatus(
+    @Param() { id }: MongoIdParamDto,
+    @Body() dto: { status: boolean },
+  ) {
+    return this.service.toggleStatus(id, dto.status);
+  }
 }

+ 40 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/category/category.service.ts

@@ -241,4 +241,44 @@ export class CategoryService {
       throw e;
     }
   }
+
+  async toggleStatus(id: string, status: boolean) {
+    // Load existing category to get current data
+    const existingCategory = await this.mongoPrismaService.category.findUnique({
+      where: { id },
+    });
+
+    if (!existingCategory) {
+      throw new NotFoundException('Category not found');
+    }
+
+    const now = this.now();
+
+    try {
+      const category = await this.mongoPrismaService.category.update({
+        where: { id },
+        data: {
+          status: status ? CommonStatus.enabled : CommonStatus.disabled,
+          updateAt: now,
+        },
+      });
+
+      // Schedule cache sync actions
+      // Refresh category-with-tags for this category
+      await this.cacheSyncService.scheduleAction({
+        entityType: CacheEntityType.TAG,
+        operation: CacheOperation.REFRESH,
+        payload: { categoryId: category.id },
+      });
+      // Also refresh category:all for consistency
+      await this.cacheSyncService.scheduleCategoryRefreshAll();
+
+      return category;
+    } catch (e) {
+      if (e instanceof PrismaClientKnownRequestError && e.code === 'P2025') {
+        throw new NotFoundException('Category not found');
+      }
+      throw e;
+    }
+  }
 }

+ 10 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/tag/tag.controller.ts

@@ -69,4 +69,14 @@ export class TagController {
   remove(@Param() { id }: MongoIdParamDto) {
     return this.service.remove(id);
   }
+
+  @Put(':id/status')
+  @ApiOperation({ summary: 'Toggle tag status' })
+  @ApiResponse({ status: 200, type: TagDto })
+  toggleStatus(
+    @Param() { id }: MongoIdParamDto,
+    @Body() dto: { status: boolean },
+  ) {
+    return this.service.toggleStatus(id, dto.status);
+  }
 }

+ 32 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/tag/tag.service.ts

@@ -265,4 +265,36 @@ export class TagService {
       throw e;
     }
   }
+
+  // toggle status
+  async toggleStatus(id: string, status: boolean) {
+    const tag = await this.mongoPrismaService.tag.findUnique({
+      where: { id },
+    });
+
+    if (!tag) {
+      throw new NotFoundException('Tag not found');
+    }
+
+    const updatedTag = await this.mongoPrismaService.tag.update({
+      where: { id },
+      data: {
+        status: status ? CommonStatus.enabled : CommonStatus.disabled,
+        updateAt: this.now(),
+      },
+    });
+
+    // Schedule cache sync actions
+    await this.cacheSyncService.scheduleAction({
+      entityType: CacheEntityType.TAG,
+      operation: CacheOperation.REFRESH,
+      payload: { categoryId: tag.categoryId },
+    });
+    await this.cacheSyncService.scheduleAction({
+      entityType: CacheEntityType.TAG,
+      operation: CacheOperation.REFRESH_ALL,
+    });
+
+    return updatedTag;
+  }
 }

+ 9 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/video-media/video-media.service.ts

@@ -81,6 +81,7 @@ export class VideoMediaService {
         tagIds: row.tagIds ?? [],
         listStatus: row.listStatus ?? 0,
         editedAt: Number(row.editedAt ?? 0),
+        updatedAt: row.updatedAt ?? null,
         tags: row.tags ?? [],
         tagsFlat: row.tagsFlat ?? '',
         secondTags: row.secondTags ?? [],
@@ -130,6 +131,7 @@ export class VideoMediaService {
       tagIds: video.tagIds ?? [],
       listStatus: video.listStatus ?? 0,
       editedAt: Number(video.editedAt ?? 0),
+      updatedAt: video.updatedAt ?? null,
       categoryName: category?.name ?? null,
       // Existing DTO: tags as {id, name}[]
       tags: video.tags ?? [],
@@ -178,6 +180,7 @@ export class VideoMediaService {
     }
 
     updateData.editedAt = BigInt(Date.now());
+    updateData.updatedAt = new Date();
 
     await this.prisma.videoMedia.update({
       where: { id },
@@ -201,12 +204,14 @@ export class VideoMediaService {
     }
 
     const editedAt = BigInt(Date.now());
+    const updatedAt = new Date();
 
     await this.prisma.videoMedia.update({
       where: { id },
       data: {
         listStatus: dto.listStatus,
         editedAt,
+        updatedAt,
       },
     });
 
@@ -227,12 +232,14 @@ export class VideoMediaService {
     }
 
     const editedAt = BigInt(Date.now());
+    const updatedAt = new Date();
 
     const result = await this.prisma.videoMedia.updateMany({
       where: { id: { in: dto.ids } },
       data: {
         listStatus: dto.listStatus,
         editedAt,
+        updatedAt,
       },
     });
 
@@ -256,12 +263,14 @@ export class VideoMediaService {
     }
 
     const editedAt = BigInt(Date.now());
+    const updatedAt = new Date();
 
     await this.prisma.videoMedia.update({
       where: { id },
       data: {
         coverImg,
         editedAt,
+        updatedAt,
       },
     });