设置促销、全局应用促销功能

Change-Id: I0f4e5be4363e1718e7931a9348b18155efb92dfc
diff --git a/src/main/java/com/pt5/pthouduan/controller/TorrentController.java b/src/main/java/com/pt5/pthouduan/controller/TorrentController.java
index 4cffef8..dac2531 100644
--- a/src/main/java/com/pt5/pthouduan/controller/TorrentController.java
+++ b/src/main/java/com/pt5/pthouduan/controller/TorrentController.java
@@ -108,7 +108,130 @@
 //        return ResponseEntity.badRequest().body("Upload failed:" + e.getMessage());
 //    }
 //}
-    
+//触发检查是否需要促销
+@PostMapping("/applyPromotions")
+public ResponseEntity<?> applyPromotions(@RequestParam("userid") Long userid)
+{
+    if(userMapper.getpermissionByUserid(userid) == 1)
+    {
+        torrentMapper.setFreePromotion();
+        torrentMapper.setDoubleUpload();
+        torrentMapper.setHalfDownload();
+        torrentMapper.setDoubleUpload();
+    }else{
+        throw new SecurityException("无权执行此操作");
+    }
+
+    return ResponseEntity.ok(Map.of(
+            "success", true,
+            "message", "促销规则已应用"
+    ));
+}
+
+//设置促销类型
+@PostMapping("/setPromotion")
+public ResponseEntity<?> setPromotion(
+        @RequestParam("userid") Long userid,
+        @RequestParam("torrentId") Long torrentId,
+        @RequestParam("promotionId") Long promotionId){
+    try {
+        //1-上传加倍;2-下载减半;3-免费下载;NULL-没有促销
+        torrentService.setPromotion(torrentId, promotionId, userid);
+
+        return ResponseEntity.ok(Map.of(
+                "success", true,
+                "message", "促销类型设置成功"
+        ));
+    } catch (SecurityException e) {
+        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(
+                Map.of("success", false, "message", e.getMessage())
+        );
+    } catch (Exception e) {
+        return ResponseEntity.internalServerError().body(
+                Map.of("success", false, "message", "设置促销类型失败: " + e.getMessage())
+        );
+    }
+}
+//@PostMapping("/upload")
+//public ResponseEntity<?> uploadTorrent(
+//        @RequestParam("userid") Long userid,
+//        @RequestParam("file") MultipartFile torrentFile,
+//        @RequestParam("title") String title,
+//        @RequestParam("description") String description,
+//        @RequestParam("categoryId") Integer categoryId,
+//        // 以下为通用扩展字段(根据类型选择性使用)
+//        @RequestParam(value = "dpi",required = false) String dpi,
+//        @RequestParam(value = "caption", required = false) String caption,
+//        @RequestParam(value = "region", required = false) String region,
+//        @RequestParam(value = "year", required = false) Integer year,
+//        @RequestParam(value = "genre", required = false) String genre,
+//        @RequestParam(value = "format", required = false) String format,
+//        @RequestParam(value = "resolution", required = false) String resolution,
+//        @RequestParam(value = "codecFormat", required = false) String codecFormat,
+//        @RequestParam(value = "platform", required = false) String platform,
+//        @RequestParam(value = "language", required = false) String language,
+//        @RequestParam(value = "eventType", required = false) String eventType,
+//        @RequestParam(value = "dataType", required = false) String dataType,
+//        @RequestParam(value = "source", required = false) String source,
+//        @RequestParam(value = "style", required = false) String style,
+//        @RequestParam(value = "isMainland", required = false) Boolean isMainland){
+//    // 创建临时用户对象
+//    //User user = new User(1L,"testuser");
+//    //User user = userMapper.selectById(userid);
+//
+//    // 构建扩展参数Map
+//    Map<String, String> extraParams = new HashMap<>();
+//
+//    // 通用参数
+//    putIfNotNull(extraParams, "dpi", dpi);
+//    putIfNotNull(extraParams, "caption", caption);
+//    putIfNotNull(extraParams, "region", region);
+//    putIfNotNull(extraParams, "year", year != null ? year.toString() : null);
+//    putIfNotNull(extraParams, "genre", genre);
+//    putIfNotNull(extraParams, "format", format);
+//    putIfNotNull(extraParams, "resolution", resolution);
+//
+//    // 特殊参数
+//    putIfNotNull(extraParams, "codecFormat", codecFormat);  // 电影编码格式
+//    putIfNotNull(extraParams, "platform", platform);        // 游戏/软件平台
+//    putIfNotNull(extraParams, "language", language);        // 游戏语言
+//    putIfNotNull(extraParams, "eventType", eventType);      // 体育赛事类型
+//    putIfNotNull(extraParams, "source", source);            // 纪录片来源
+//    putIfNotNull(extraParams, "style", style);              // 音乐风格
+//    putIfNotNull(extraParams, "isMainland", isMainland != null ? isMainland.toString() : null); // 综艺是否大陆
+//    putIfNotNull(extraParams, "dataType", dataType);
+//
+////    extraParams.put("region", "CN");
+////    extraParams.put("year", "2023");
+////    extraParams.put("genre", "Action");
+////    extraParams.put("encodeFormat", "H.264");
+////    extraParams.put("resolution", "1080p");
+//
+//
+//    //user.setUserid(1L); // 设置测试用户ID
+//    try{
+//        //torrentService.Upload(torrentFile,title,description,user);
+//        //return torrentService.Upload(torrentFile, title, description, categoryId, dpi,caption,user);
+//
+////        return torrentService.uploadWithCategory(
+////                torrentFile, title, description, categoryId, user, dpi, caption,
+////                region, year, genre, format, resolution, codecFormat,
+////                platform, language, eventType, source, style, isMainland
+////        );
+//        // 调用Service
+//        return torrentService.uploadWithCategory(
+//                torrentFile,
+//                title,
+//                description,
+//                categoryId,
+//                userid,
+//                extraParams
+//        );
+//    }catch(Exception e){
+//        return ResponseEntity.badRequest().body("Upload failed:" + e.getMessage());
+//    }
+//}
+
 @PostMapping("/upload")
 public ResponseEntity<?> uploadTorrent(
         @RequestParam("userid") Long userid,
diff --git a/src/test/java/com/pt5/pthouduan/ControllerTest/CategoryControllerTest.java b/src/test/java/com/pt5/pthouduan/ControllerTest/CategoryControllerTest.java
new file mode 100644
index 0000000..2c375db
--- /dev/null
+++ b/src/test/java/com/pt5/pthouduan/ControllerTest/CategoryControllerTest.java
@@ -0,0 +1,2 @@
+package com.pt5.pthouduan.ControllerTest;public class CategoryControllerTest {
+}
diff --git a/src/test/java/com/pt5/pthouduan/ControllerTest/TorrentApplyPromotionsControllerTest.java b/src/test/java/com/pt5/pthouduan/ControllerTest/TorrentApplyPromotionsControllerTest.java
new file mode 100644
index 0000000..78ab203
--- /dev/null
+++ b/src/test/java/com/pt5/pthouduan/ControllerTest/TorrentApplyPromotionsControllerTest.java
@@ -0,0 +1,76 @@
+package com.pt5.pthouduan.ControllerTest;
+
+import com.pt5.pthouduan.controller.TorrentController;
+import com.pt5.pthouduan.mapper.TorrentMapper;
+import com.pt5.pthouduan.mapper.UserMapper;
+import com.pt5.pthouduan.service.TorrentService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+class TorrentApplyPromotionsControllerTest {
+
+    @Mock
+    private UserMapper userMapper;
+
+    @Mock
+    private TorrentService torrentService;
+
+    @Mock
+    private TorrentMapper torrentMapper;  // Mock TorrentMapper
+
+    @InjectMocks
+    private TorrentController torrentController;
+
+    private MockMvc mockMvc;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+        mockMvc = MockMvcBuilders.standaloneSetup(torrentController).build();
+    }
+
+    @Test
+    void applyPromotions_WithPermission_ShouldReturnSuccess() throws Exception {
+        // Arrange
+        Long userid = 1L;
+        Long torrentId = 101L;
+        Long helpedId = 2L;
+
+        // 模拟用户有权限(返回1表示有权限)
+        when(userMapper.getpermissionByUserid(userid)).thenReturn(1);
+
+        // 模拟服务层调用成功
+        doNothing().when(torrentService).addcredit(anyLong(), anyLong(), anyInt());
+        doNothing().when(torrentService).deducecredit(anyLong(), anyLong(), anyInt());
+
+        // 模拟 TorrentMapper 方法调用
+        //when(torrentMapper.setFreePromotion()).thenReturn(1);  // 关键:Mock torrentMapper
+
+        // Act & Assert
+        mockMvc.perform(post("/torrent/applyPromotions")
+                        .param("userid", userid.toString())
+                        .param("torrentid", torrentId.toString())
+                        .param("helpedid", helpedId.toString()))
+                .andExpect(status().isOk())  // 验证状态码
+                .andExpect(content().string(containsString("success")));  // 验证响应内容
+    }
+
+
+    @Test
+    void applyPromotions_WithoutParameters_ShouldReturnBadRequest() throws Exception {
+        // Act & Assert
+        mockMvc.perform(post("/torrent/applyPromotions"))
+                .andExpect(status().isBadRequest());  // 验证状态码
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/pt5/pthouduan/ControllerTest/TorrentSetPromotionControllerTest.java b/src/test/java/com/pt5/pthouduan/ControllerTest/TorrentSetPromotionControllerTest.java
new file mode 100644
index 0000000..3717f20
--- /dev/null
+++ b/src/test/java/com/pt5/pthouduan/ControllerTest/TorrentSetPromotionControllerTest.java
@@ -0,0 +1,109 @@
+package com.pt5.pthouduan.ControllerTest;
+
+import com.pt5.pthouduan.controller.TorrentController;
+import com.pt5.pthouduan.service.TorrentService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+class TorrentSetPromotionControllerTest {
+
+    @Mock
+    private TorrentService torrentService;
+
+    @InjectMocks
+    private TorrentController torrentController;
+
+    private MockMvc mockMvc;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+        mockMvc = MockMvcBuilders.standaloneSetup(torrentController).build();
+    }
+
+    @Test
+    void setPromotion_Success_ShouldReturnSuccess() throws Exception {
+        // Arrange
+        Long userid = 1L;
+        Long torrentId = 101L;
+        Long promotionId = 1L;
+
+        // 模拟服务层调用成功
+        doNothing().when(torrentService).setPromotion(torrentId, promotionId, userid);
+
+        // Act & Assert
+        mockMvc.perform(post("/torrent/setPromotion")
+                        .param("userid", userid.toString())
+                        .param("torrentId", torrentId.toString())
+                        .param("promotionId", promotionId.toString()))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.success").value(true))
+                .andExpect(jsonPath("$.message").value("促销类型设置成功"));
+
+        // 验证服务层方法被调用
+        verify(torrentService, times(1)).setPromotion(torrentId, promotionId, userid);
+    }
+
+    @Test
+    void setPromotion_SecurityException_ShouldReturnForbidden() throws Exception {
+        // Arrange
+        Long userid = 1L;
+        Long torrentId = 101L;
+        Long promotionId = 1L;
+
+        // 模拟服务层抛出SecurityException
+        doThrow(new SecurityException("无权设置促销")).when(torrentService).setPromotion(torrentId, promotionId, userid);
+
+        // Act & Assert
+        mockMvc.perform(post("/torrent/setPromotion")
+                        .param("userid", userid.toString())
+                        .param("torrentId", torrentId.toString())
+                        .param("promotionId", promotionId.toString()))
+                .andExpect(status().isForbidden())
+                .andExpect(jsonPath("$.success").value(false))
+                .andExpect(jsonPath("$.message").value("无权设置促销"));
+
+        // 验证服务层方法被调用
+        verify(torrentService, times(1)).setPromotion(torrentId, promotionId, userid);
+    }
+
+    @Test
+    void setPromotion_OtherException_ShouldReturnInternalServerError() throws Exception {
+        // Arrange
+        Long userid = 1L;
+        Long torrentId = 101L;
+        Long promotionId = 1L;
+
+        // 模拟服务层抛出其他异常
+        doThrow(new RuntimeException("数据库错误")).when(torrentService).setPromotion(torrentId, promotionId, userid);
+
+        // Act & Assert
+        mockMvc.perform(post("/torrent/setPromotion")
+                        .param("userid", userid.toString())
+                        .param("torrentId", torrentId.toString())
+                        .param("promotionId", promotionId.toString()))
+                .andExpect(status().isInternalServerError())
+                .andExpect(jsonPath("$.success").value(false))
+                .andExpect(jsonPath("$.message").value("设置促销类型失败: 数据库错误"));
+
+        // 验证服务层方法被调用
+        verify(torrentService, times(1)).setPromotion(torrentId, promotionId, userid);
+    }
+
+    @Test
+    void setPromotion_WithoutParameters_ShouldReturnBadRequest() throws Exception {
+        // Act & Assert
+        mockMvc.perform(post("/torrent/setPromotion"))
+                .andExpect(status().isBadRequest());
+    }
+}
\ No newline at end of file