Merge branch 'master' of ssh://gerrit.lilingkun.com:29418/echo-backend
Change-Id: I1b49fb8032ecd127e91b5cc5fe4962e8dabfb1fd
diff --git a/src/main/java/com/example/myproject/controller/TorrentController.java b/src/main/java/com/example/myproject/controller/TorrentController.java
index 846e5da..ef62c26 100644
--- a/src/main/java/com/example/myproject/controller/TorrentController.java
+++ b/src/main/java/com/example/myproject/controller/TorrentController.java
@@ -1,323 +1,3 @@
-// package com.example.myproject.controller;
-
-// import com.example.myproject.common.base.PageUtil;
-// import com.example.myproject.entity.TorrentEntity;
-// import com.example.myproject.service.TorrentService;
-// import com.example.myproject.service.PromotionService;
-// import com.example.myproject.dto.param.TorrentParam;
-// import com.example.myproject.dto.vo.TorrentVO;
-// import com.example.myproject.common.base.Result;
-// import com.example.myproject.dto.param.TorrentUploadParam;
-// import com.example.myproject.dto.TorrentUpdateDTO;
-// import com.example.myproject.dto.PromotionCreateDTO;
-// import com.example.myproject.entity.Promotion;
-// import com.example.myproject.service.UserService;
-
-// import io.swagger.v3.oas.annotations.Operation;
-// import io.swagger.v3.oas.annotations.media.Content;
-// import io.swagger.v3.oas.annotations.media.Schema;
-// import io.swagger.v3.oas.annotations.responses.ApiResponse;
-
-// import org.springframework.beans.factory.annotation.Autowired;
-// import org.springframework.http.HttpStatus;
-// import org.springframework.http.ResponseEntity;
-// import org.springframework.validation.annotation.Validated;
-// import org.springframework.web.bind.annotation.*;
-// import org.springframework.web.multipart.MultipartFile;
-
-// import javax.servlet.http.HttpServletRequest;
-// import javax.servlet.http.HttpServletResponse;
-// import java.io.File;
-// import java.io.IOException;
-// import java.util.List;
-
-// import cn.dev33.satoken.annotation.SaCheckLogin;
-// import cn.dev33.satoken.stp.StpUtil;
-
-// @RestController
-// @RequestMapping("/seeds")
-// public class TorrentController {
-
-// @Autowired
-// private TorrentService torrentService;
-
-// @Autowired
-// private PromotionService promotionService;
-
-// @Autowired
-// private UserService userService;
-
-
-// @SaCheckLogin
-// @Operation(summary = "种子列表查询", description = "种子列表条件查询-分页-排序")
-// @ApiResponse(responseCode = "0", description = "操作成功",
-// content = {@Content(mediaType = "application/json",
-// schema = @Schema(implementation = TorrentVO.class))
-// })
-// @PostMapping("/list")
-// public Result list(@RequestBody TorrentParam param) {
-// // 构建排序和模糊查询条件
-// param.validOrder(param.getOrderKey(TorrentEntity.class));
-// param.buildLike();
-
-// PageUtil.startPage(param);
-
-// // 查询数据
-// List<TorrentEntity> list = torrentService.search(param);
-
-// // 返回分页结果
-// return Result.ok(list, PageUtil.getPage(list));
-// }
-
-// @SaCheckLogin
-// @Operation(summary = "种子详情查询")
-// @ApiResponse(responseCode = "0", description = "操作成功", content = {
-// @Content(mediaType = "application/json", schema = @Schema(implementation =
-// TorrentEntity.class))
-// })
-// @PostMapping("/info/{id}")
-// public Result info(@PathVariable("id")Long id) {
-
-// TorrentEntity entity = torrentService.selectBySeedId(id);
-// return Result.ok(entity);
-// }
-
-// @Operation(summary = "上传种子")
-
-// @PostMapping("/upload")
-// public Result uploadTorrent(
-// @RequestParam("file") MultipartFile file,
-// @RequestParam("coverImage") MultipartFile coverImage,
-// @ModelAttribute @Validated TorrentUploadParam param,
-// HttpServletRequest request
-// ) throws IOException {
-// try {
-// // 验证用户权限
-// // Long userId = StpUtil.getLoginIdAsLong();
-// String userId = String.valueOf(param.getUploader());
-// param.setUploader(userId);
-
-// // 验证文件大小和类型
-// if (file.isEmpty() || file.getSize() > 10 * 1024 * 1024) { // 10MB限制
-// return Result.error("文件大小不符合要求");
-// }
-
-// if (!file.getOriginalFilename().toLowerCase().endsWith(".torrent")) {
-// return Result.error("只支持.torrent文件");
-// }
-// if (!coverImage.isEmpty()) {
-// String originalFilename = coverImage.getOriginalFilename();
-// String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
-// String fileName = System.currentTimeMillis() + suffix;
-
-// if (!originalFilename.toLowerCase().matches(".*\\.(jpg|jpeg|png)$")) {
-// return Result.error("仅支持 JPG/PNG 格式的封面图片");
-// }
-
-
-// // 项目根目录下的 /uploads/torrents/
-// String uploadDir = System.getProperty("user.dir") + "/uploads/torrents/";
-// File dir = new File(uploadDir);
-// if (!dir.exists()) dir.mkdirs(); // 自动创建目录
-
-// File dest = new File(uploadDir + fileName);
-// coverImage.transferTo(dest);
-
-
-// String imageUrl = request.getScheme() + "://" + request.getServerName() + ":" +
-// request.getServerPort() + "/torrent-images/" + fileName;
-
-
-// param.setImageUrl(imageUrl);
-// }
-
-// torrentService.uploadTorrent(file, param);
-// return Result.ok();
-// } catch (Exception e) {
-// return Result.error("种子上传失败: " + e.getMessage());
-// }
-// }
-
-// /**
-// * 获取种子文件
-// */
-// @GetMapping("/{seed_id}/download")
-// public void downloadTorrent(
-// @PathVariable("seed_id") Long seedId,
-// @RequestParam("passkey") String passkey,
-// HttpServletResponse response) throws IOException {
-
-// // 获取种子实体
-// TorrentEntity entity = torrentService.selectBySeedId(seedId);
-// if (entity == null) {
-// response.sendError(HttpServletResponse.SC_NOT_FOUND, "种子不存在");
-// return;
-// }
-
-// // 获取并处理种子文件内容(需在service中实现passkey注入)
-// byte[] torrentBytes = torrentService.fetch(seedId, passkey);
-
-// // 设置下载文件名
-// String filename = entity.getFileName();
-// if (filename == null || filename.isBlank()) {
-// filename = seedId + ".torrent";
-// }
-// if (!filename.toLowerCase().endsWith(".torrent")) {
-// filename = filename + ".torrent";
-// }
-// filename = java.net.URLEncoder.encode(filename, java.nio.charset.StandardCharsets.UTF_8).replaceAll("\\+",
-// "%20");
-
-// // 设置响应头
-// response.setCharacterEncoding(java.nio.charset.StandardCharsets.UTF_8.name());
-// response.setContentLength(torrentBytes.length);
-// response.setContentType("application/x-bittorrent");
-// response.setHeader("Content-Disposition", "attachment;filename=" + filename);
-
-// // 写入文件内容
-// response.getOutputStream().write(torrentBytes);
-// response.getOutputStream().flush();
-// }
-
-// /**
-// * 收藏或者取消收藏
-// */
-// @PostMapping("/{seed_id}/favorite-toggle")
-// public Result favorite(
-// @PathVariable("seed_id") Long seedId,
-// @RequestParam("user_id") Long userId) {
-// try {
-
-// return torrentService.favorite(seedId, userId);
-// } catch (Exception e) {
-// return Result.error("失败: ");
-// }
-// }
-
-// @SaCheckLogin
-// @Operation(summary = "删除种子")
-// @DeleteMapping("/{torrentId}")
-// public Result deleteTorrent(@PathVariable Long torrentId) {
-// try {
-// // 验证用户权限
-// Long userId = StpUtil.getLoginIdAsLong();
-// if (!torrentService.canUserDeleteTorrent(torrentId, userId)) {
-// return Result.error("没有权限删除此种子");
-// }
-
-// torrentService.deleteTorrent(torrentId);
-// return Result.ok();
-// } catch (Exception e) {
-// return Result.error("删除失败: " + e.getMessage());
-// }
-// }
-
-// @SaCheckLogin
-// @Operation(summary = "修改种子信息")
-// @PutMapping("/{torrentId}")
-// public Result updateTorrent(
-// @PathVariable Long torrentId,
-// @RequestBody @Validated TorrentUpdateDTO updateDTO) {
-// try {
-// // 验证用户权限
-// Long userId = StpUtil.getLoginIdAsLong();
-// if (!torrentService.canUserUpdateTorrent(torrentId, userId)) {
-// return Result.error("没有权限修改此种子");
-// }
-
-// torrentService.updateTorrent(torrentId, updateDTO);
-// return Result.ok();
-// } catch (Exception e) {
-// return Result.error("更新失败: " + e.getMessage());
-// }
-// }
-
-// @SaCheckLogin
-// @Operation(summary = "创建促销活动")
-// @PostMapping("/promotions")
-// public Result createPromotion(@RequestBody @Validated PromotionCreateDTO promotionDTO) {
-// try {
-// // 验证用户权限(只有管理员可以创建促销)
-// // if (!StpUtil.hasRole("admin")) {
-// // return Result.error("没有权限创建促销活动");
-// // }
-// //
-// Promotion promotion = promotionService.createPromotion(promotionDTO);
-// return Result.ok(promotion);
-// } catch (Exception e) {
-// return Result.error("创建促销失败: " + e.getMessage());
-// }
-// }
-
-// @SaCheckLogin
-// @Operation(summary = "获取促销活动列表")
-// @GetMapping("/promotions")
-// public Result getPromotions() {
-// try {
-// List<Promotion> promotions = promotionService.getAllActivePromotions();
-// return Result.ok(promotions);
-// } catch (Exception e) {
-// return Result.error("获取促销列表失败: " + e.getMessage());
-// }
-// }
-
-// @SaCheckLogin
-// @Operation(summary = "获取促销详情")
-// @GetMapping("/promotions/{promotionId}")
-// public Result getPromotionDetails(@PathVariable Long promotionId) {
-// try {
-// Promotion promotion = promotionService.getPromotionById(promotionId);
-// if (promotion == null) {
-// return Result.error("促销活动不存在");
-// }
-// return Result.ok(promotion);
-// } catch (Exception e) {
-// return Result.error("获取促销详情失败: " + e.getMessage());
-// }
-// }
-
-// @SaCheckLogin
-// @Operation(summary = "删除促销活动")
-// @DeleteMapping("/promotions/{promotionId}")
-// public Result deletePromotion(@PathVariable Long promotionId) {
-// try {
-// // 验证用户权限(只有管理员可以删除促销)
-// if (!StpUtil.hasRole("admin")) {
-// return Result.error("没有权限删除促销活动");
-// }
-
-// promotionService.deletePromotion(promotionId);
-// return Result.ok();
-// } catch (Exception e) {
-// return Result.error("删除促销失败: " + e.getMessage());
-// }
-// }
-
-// // 下载种子(包含反作弊机制)
-// @PostMapping("/{torrentId}/download")
-// public ResponseEntity<?> downloadTorrent(@PathVariable Long torrentId,
-// @RequestParam Long userId) {
-// // // 验证用户身份和权限
-// // if (!userService.validateUser(userId)) {
-// // return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-// // }
-
-// // 检查用户上传量是否足够
-// if (!torrentService.checkUserUploadRatio(userId)) {
-// return ResponseEntity.status(HttpStatus.FORBIDDEN)
-// .body("上传量不足,无法下载");
-// }
-
-// // 应用促销折扣(如果有)
-// double downloadSize = torrentService.calculateDownloadSize(torrentId, userId);
-
-// // 记录下载
-// torrentService.recordDownload(torrentId, userId, downloadSize);
-
-// return ResponseEntity.ok().build();
-// }
-
-// }
package com.example.myproject.controller;
import cn.hutool.core.util.StrUtil;
@@ -338,6 +18,7 @@
import com.example.myproject.entity.Promotion;
import com.example.myproject.service.UserService;
+import com.example.myproject.repository.UserRepository;
import com.turn.ttorrent.bcodec.BEValue;
import com.turn.ttorrent.bcodec.BEncoder;
@@ -365,6 +46,9 @@
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
@@ -388,6 +72,8 @@
private UserService userService;
private final List<BEValue> peers = new Vector<>();
+ @Autowired
+ private UserRepository userRepository;
@SaCheckLogin
@Operation(summary = "种子列表查询", description = "种子列表条件查询-分页-排序")
@@ -430,7 +116,7 @@
@RequestParam("coverImage") MultipartFile coverImage,
@ModelAttribute @Validated TorrentUploadParam param,
HttpServletRequest request
- ) throws IOException {
+ ) throws IOException {
try {
// 验证用户权限
// Long userId = StpUtil.getLoginIdAsLong();
@@ -541,16 +227,78 @@
public Result getMyFavorite(
@RequestParam("user_id") Long userId) {
try {
+
return torrentService.getMyfavorite(userId);
} catch (Exception e) {
return Result.error("失败: ");
}
}
+ @SaCheckLogin
+ @Operation(summary = "创建促销活动")
+ @PostMapping("/promotions")
+ public Result createPromotion(@RequestBody @Validated PromotionCreateDTO promotionDTO) {
+ try {
+ // 验证用户权限(只有管理员可以创建促销)
+// if (!StpUtil.hasRole("admin")) {
+// return Result.error("没有权限创建促销活动");
+// }
+//
+ Promotion promotion = promotionService.createPromotion(promotionDTO);
+ return Result.ok(promotion);
+ } catch (Exception e) {
+ return Result.error("创建促销失败: " + e.getMessage());
+ }
+ }
+ @SaCheckLogin
+ @Operation(summary = "获取促销活动列表")
+ @GetMapping("/promotions")
+ public Result getPromotions() {
+ try {
+ List<Promotion> promotions = promotionService.getAllActivePromotions();
+ return Result.ok(promotions);
+ } catch (Exception e) {
+ return Result.error("获取促销列表失败: " + e.getMessage());
+ }
+ }
+
+ @SaCheckLogin
+ @Operation(summary = "获取促销详情")
+ @GetMapping("/promotions/{promotionId}")
+ public Result getPromotionDetails(@PathVariable Long promotionId) {
+ try {
+ Promotion promotion = promotionService.getPromotionById(promotionId);
+ if (promotion == null) {
+ return Result.error("促销活动不存在");
+ }
+ return Result.ok(promotion);
+ } catch (Exception e) {
+ return Result.error("获取促销详情失败: " + e.getMessage());
+ }
+ }
+
+ @SaCheckLogin
+ @Operation(summary = "删除促销活动")
+ @DeleteMapping("/promotions/{promotionId}")
+ public Result deletePromotion(@PathVariable Long promotionId) {
+ try {
+ Long userId = StpUtil.getLoginIdAsLong();
+ // 查询用户
+ var userOpt = userRepository.findById(userId);
+ if (userOpt.isEmpty() || !"admin".equals(userOpt.get().getRole())) {
+ return Result.error("没有权限删除促销活动");
+ }
+
+ promotionService.deletePromotion(promotionId);
+ return Result.ok();
+ } catch (Exception e) {
+ return Result.error("删除促销失败: " + e.getMessage());
+ }
+ }
@GetMapping("/announce")
public ResponseEntity<byte[]> announce(TrackerProtocol trackerProtocol, HttpServletRequest request, @RequestParam(value = "info_hash") String encodedInfoHash){
-
+ log.info("client report: {}", trackerProtocol);
HashMap<String, BEValue> map = new HashMap<>();
if (StrUtil.isBlank(trackerProtocol.getIp())) {
trackerProtocol.setIp(request.getRemoteAddr());
diff --git a/src/main/java/com/example/myproject/mapper/PromotionMapper.java b/src/main/java/com/example/myproject/mapper/PromotionMapper.java
index caf96ee..4ff79ea 100644
--- a/src/main/java/com/example/myproject/mapper/PromotionMapper.java
+++ b/src/main/java/com/example/myproject/mapper/PromotionMapper.java
@@ -25,7 +25,7 @@
"WHERE p.is_deleted = false " +
"AND p.start_time <= #{now} AND p.end_time >= #{now} " +
// "AND FIND_IN_SET(#{torrentId}, p.applicable_torrent_ids) > 0"
- "AND JSON_CONTAINS(p.applicable_torrent_ids, CAST(#{torrentId} AS JSON))")
+ "AND JSON_CONTAINS(p.applicable_torrent_ids, CAST(#{torrentId} AS JSON))")
List<Promotion> findActivePromotionsForTorrent(
@Param("torrentId") Long torrentId,
@Param("now") LocalDateTime now);