调试交互

Change-Id: Ib9d7b8432cb622c7e28c842ab4dc4e156fcd6414
diff --git a/src/main/java/com/example/myproject/controller/DynamicController.java b/src/main/java/com/example/myproject/controller/DynamicController.java
index db1d0a2..a988c8f 100644
--- a/src/main/java/com/example/myproject/controller/DynamicController.java
+++ b/src/main/java/com/example/myproject/controller/DynamicController.java
@@ -33,19 +33,22 @@
         return ResponseEntity.ok("动态删除成功");
     }
 
-    //好友动态评论
     @PostMapping("/{user_id}/feeds/{dynamic_id}/comments")
     public ResponseEntity<Map<String, Object>> addComment(
             @PathVariable("user_id") Long userId,
             @PathVariable("dynamic_id") Long dynamicId,
-            @RequestBody Map<String, String> content) {
+            @RequestBody Map<String, Object> content) {
+        String commentContent = (String) content.get("content");
 
-        String commentContent = content.get("content");  // 获取评论内容
-        Map<String, Object> response = dynamicService.addComment(userId, dynamicId, commentContent);
+        Long parentCommentId = content.containsKey("parent_comment_id") && content.get("parent_comment_id") != null ?
+                Long.parseLong(content.get("parent_comment_id").toString()) : null;
 
+        Map<String, Object> response = dynamicService.addComment(userId, dynamicId, commentContent, parentCommentId);
         return ResponseEntity.ok(response);
     }
 
+
+
     //获取某个好友的所有动态
     @GetMapping("/{user_id}/getAdynamic")
     public ResponseEntity<Map<String, Object>> getAllUserDynamics(@PathVariable("user_id") Long userId) {
diff --git a/src/main/java/com/example/myproject/controller/TorrentController.java b/src/main/java/com/example/myproject/controller/TorrentController.java
index 74cb8f9..aecfc64 100644
--- a/src/main/java/com/example/myproject/controller/TorrentController.java
+++ b/src/main/java/com/example/myproject/controller/TorrentController.java
@@ -1,7 +1,331 @@
+// 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;
 import com.example.myproject.common.base.PageUtil;
+import com.example.myproject.dto.TrackerProtocol;
 import com.example.myproject.entity.TorrentEntity;
+import com.example.myproject.entity.TorrentReport;
+import com.example.myproject.repository.TorrentReportRepository;
 import com.example.myproject.service.TorrentService;
 import com.example.myproject.service.PromotionService;
 import com.example.myproject.dto.param.TorrentParam;
@@ -13,11 +337,17 @@
 import com.example.myproject.entity.Promotion;
 import com.example.myproject.service.UserService;
 
+import com.turn.ttorrent.bcodec.BEValue;
+import com.turn.ttorrent.bcodec.BEncoder;
+import com.turn.ttorrent.common.TorrentUtils;
 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 lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -29,15 +359,20 @@
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
-import java.util.List;
+import java.net.URLDecoder;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
 
 import cn.dev33.satoken.annotation.SaCheckLogin;
 import cn.dev33.satoken.stp.StpUtil;
 
 @RestController
 @RequestMapping("/seeds")
+@Slf4j
+@RequiredArgsConstructor
 public class TorrentController {
-
+    private final TorrentReportRepository torrentReportRepository;
     @Autowired
     private TorrentService torrentService;
 
@@ -46,6 +381,7 @@
 
     @Autowired
     private UserService userService;
+    private final List<BEValue> peers = new Vector<>();
 
 
     @SaCheckLogin
@@ -54,8 +390,8 @@
             content = {@Content(mediaType = "application/json",
                     schema = @Schema(implementation = TorrentVO.class))
             })
-    @PostMapping("/list")
-    public Result list(@RequestBody TorrentParam param) {
+    @GetMapping("/list")
+    public Result list( TorrentParam param) {
         // 构建排序和模糊查询条件
         param.validOrder(param.getOrderKey(TorrentEntity.class));
         param.buildLike();
@@ -82,8 +418,7 @@
         return Result.ok(entity);
     }
 
-@Operation(summary = "上传种子")
-
+    @Operation(summary = "上传种子")
     @PostMapping("/upload")
     public Result uploadTorrent(
             @RequestParam("file") MultipartFile file,
@@ -125,7 +460,8 @@
 
 
                 String imageUrl = request.getScheme() + "://" + request.getServerName() + ":" +
-                        request.getServerPort() + "/torrent-images/" + fileName;
+                        request.getServerPort() + "/uploads/torrents/" + fileName;
+//                String imageUrl ="/uploads/torrents/" + fileName;
 
 
                 param.setImageUrl(imageUrl);
@@ -292,31 +628,79 @@
             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("上传量不足,无法下载");
+    @GetMapping("/announce")
+    public ResponseEntity<byte[]> announce(TrackerProtocol trackerProtocol, HttpServletRequest request, @RequestParam(value = "info_hash") String encodedInfoHash){
+        HashMap<String, BEValue> map = new HashMap<>();
+        if (StrUtil.isBlank(trackerProtocol.getIp())) {
+            trackerProtocol.setIp(request.getRemoteAddr());
         }
 
-        // 应用促销折扣(如果有)
-        double downloadSize = torrentService.calculateDownloadSize(torrentId, userId);
+        try {
+            byte[] bytes = URLDecoder.decode(request.getQueryString().split("info_hash=")[1].split("&")[0], StandardCharsets.ISO_8859_1).getBytes(StandardCharsets.ISO_8859_1);
+            String infoHash = TorrentUtils.byteArrayToHexString(bytes);
 
-        // 记录下载
-        torrentService.recordDownload(torrentId, userId, downloadSize);
+            trackerProtocol.setInfo_hash(infoHash);
+            TorrentEntity torrent = torrentService.selectByInfoHash(infoHash);
+            if (torrent == null) {
+                throw new RuntimeException("种子不存在");
+            }
+            Integer userId = trackerProtocol.getUserId();
 
-        return ResponseEntity.ok().build();
+            TorrentReport report = TorrentReport.builder()
+                    .userId(userId )
+                    .torrentId(torrent.getId())
+                    .peerId(trackerProtocol.getPeer_id())
+                    .infoHash(infoHash)
+                    .build();
+            BeanUtils.copyProperties(trackerProtocol, report);
+            torrentReportRepository.save(report);
+synchronized (this){
+
+            boolean isAdded = peers.stream().anyMatch(m -> {
+                try{
+                    Map<String, BEValue> map1 = m.getMap();
+                    return map1.get("ip").getString().equals(trackerProtocol.getIp()) && map1.get("port").getInt() == trackerProtocol.getPort();
+                }catch  (Exception e){
+                    return false;
+                }
+            });
+            log.info("client report: {}", trackerProtocol);
+            map.put("interval", new BEValue(30));
+            map.put("peers", new BEValue(peers));
+            peers.forEach(p -> {
+                try {
+                    Map<String, BEValue> map1 = p.getMap();
+                    log.info("Peer info: ip={}, port={}, id={}", map1.get("ip").getString(), map1.get("port").getInt(), map1.get("peer id").getString());
+                }catch (Exception e){
+                    log.error("Print Peer info error", e);
+                }
+
+            });
+            ByteBuffer bencode = BEncoder.bencode(map);
+            if(!isAdded){
+                log.info("New peer added.");
+                Map<String, BEValue> p = new HashMap<>(3);
+                p.put("ip", new BEValue(trackerProtocol.getIp()));
+                p.put("peer id", new BEValue(trackerProtocol.getPeer_id()));
+                p.put("port", new BEValue(trackerProtocol.getPort()));
+                peers.add(new BEValue(p));
+            }
+
+            return ResponseEntity.ok(bencode.array());
+}
+
+        }catch (Exception e){
+            try{
+                String message = e.getMessage();
+                message = message == null ? "" : message;
+                log.error("announce error", e);
+                map.put("failure reason", new BEValue(message   , "UTF-8"));
+                return ResponseEntity.ok(BEncoder.bencode(map).array());
+            }catch (Exception ex){
+                log.error("announce error ", ex);
+                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal Server Error".getBytes());
+            }
+        }
     }
 
-
-
 }
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/controller/UserController.java b/src/main/java/com/example/myproject/controller/UserController.java
index 6b3d793..41a3350 100644
--- a/src/main/java/com/example/myproject/controller/UserController.java
+++ b/src/main/java/com/example/myproject/controller/UserController.java
@@ -1,21 +1,180 @@
+// package com.example.myproject.controller;
+
+// import com.example.myproject.entity.Users;
+// import com.example.myproject.repository.UserRepository;
+// import com.example.myproject.service.DynamicService;
+// import com.example.myproject.service.TaskService;
+// import com.example.myproject.service.UserService;
+// import org.springframework.beans.factory.annotation.Autowired;
+// import org.springframework.http.ResponseEntity;
+// import org.springframework.web.bind.annotation.*;
+// import org.springframework.web.multipart.MultipartFile;
+
+// import javax.servlet.http.HttpServletRequest;
+// import java.util.Map;
+// import java.util.Optional;
+
+// import java.util.List;
+// import java.util.ArrayList;
+
+
+// @RestController
+// @RequestMapping("/echo/user")
+// public class UserController {
+
+//     @Autowired
+//     private UserService userService;
+
+//     @Autowired
+//     private UserRepository userRepository;
+
+//     @Autowired
+//     private DynamicService dynamicService;
+
+//     // 接口:生成邀请码
+//     @PostMapping("/getInviteCode")
+//     public Map<String, Object> generateInviteCode(@RequestBody Map<String, Object> request) {
+//         Long userId = Long.parseLong(request.get("user_id").toString());
+//         return userService.generateInviteCode(userId);
+//     }
+
+//     //注册
+//     @PostMapping("/register")
+//     public Map<String, Object> register(@RequestBody Map<String, Object> request) {
+//         String username = (String) request.get("username");
+//         String email = (String) request.get("email");
+//         String password = (String) request.get("password");
+//         String role = (String) request.get("role");
+//         String inviteCode = (String) request.get("inviteCode");
+
+//         // 调用服务层的注册方法
+//         String resultMessage = userService.registerUser(username, email, password, role, inviteCode);
+
+//         // 返回注册结果
+//         return Map.of("msg", resultMessage);
+//     }
+
+//     //登录
+//     @PostMapping("/login")
+//     public Map<String, Object> login(@RequestBody Map<String, Object> request) {
+//         String username = (String) request.get("username");
+//         String password = (String) request.get("password");
+
+//         // 调用服务层的登录方法
+//         String resultMessage = userService.loginUser(username, password);
+
+//         // 根据登录结果返回不同的响应
+//         if (resultMessage.equals("登录成功")) {
+//             // 查询用户信息
+//             Optional<Users> user = userRepository.findByUsername(username);
+//             if (user.isPresent()) {
+//                 // 将用户的所有信息作为返回值
+//                 return Map.of("msg", resultMessage, "user", user.get());
+//             } else {
+//                 return Map.of("msg", "用户信息查询失败");
+//             }
+//         } else {
+//             return Map.of("msg", resultMessage);
+//         }
+//     }
+
+//     //修改密码
+//     @PostMapping("/password")
+//     public Map<String, Object> changePassword(@RequestBody Map<String, Object> request) {
+//         Long userId = Long.parseLong(request.get("user_id").toString());
+//         String oldPassword = (String) request.get("old_password");
+//         String newPassword = (String) request.get("new_password");
+//         String confirmPassword = (String) request.get("confirm_password");
+
+//         // 调用服务层的修改密码方法
+//         String resultMessage = userService.changePassword(userId, oldPassword, newPassword, confirmPassword);
+
+//         // 返回修改结果
+//         return Map.of("message", resultMessage, "status", resultMessage.equals("密码修改成功") ? "success" : "error");
+//     }
+
+//     // 获取用户个人资料
+//     @GetMapping("/{userId}/getProfile")
+//     public Map<String, Object> getProfile(@PathVariable("userId") Long userId) {
+//         return userService.getProfile(userId);
+//     }
+
+//     // 修改用户个人资料
+//     @PutMapping("/{userId}/editProfile")
+//     public Map<String, String> editProfile(
+//             @PathVariable("userId") Long userId,
+//             @RequestBody Map<String, Object> profileData) {
+
+//         // 获取请求体中的修改数据
+//         String nickname = (String) profileData.get("nickname");
+//         String gender = (String) profileData.get("gender");
+//         String description = (String) profileData.get("description");
+//         String hobbies = (String) profileData.get("hobbies");
+
+//         // 调用服务层方法进行修改
+//         boolean updated = userService.editProfile(userId, nickname, gender, description, hobbies);
+
+//         // 返回操作结果消息
+//         if (updated) {
+//             return Map.of("message", "用户资料更新成功");
+//         } else {
+//             return Map.of("message", "用户不存在");
+//         }
+//     }
+
+//     // 计算分享率
+//     @GetMapping("/{user_id}/calculate-share-rate")
+//     public Map<String, Object> calculateShareRate(@PathVariable("user_id") Long userId) {
+//         return userService.calculateShareRate(userId);
+//     }
+
+//     // 获取用户所有好友的基本信息
+//     @GetMapping("/{userId}/friends")
+//     public List<Map<String, Object>> getUserFriends(@PathVariable("userId") Long userId) {
+//         List<Long> friendIds = dynamicService.getAllFriendIds(userId);  // 注意这里用的是实例对象
+//         List<Map<String, Object>> friends = new ArrayList<>();
+
+//         for (Long friendId : friendIds) {
+//             Optional<Users> userOpt = userRepository.findById(friendId);
+//             if (userOpt.isPresent()) {
+//                 Users user = userOpt.get();
+//                 Map<String, Object> friendInfo = Map.of(
+//                         "id", user.getUserId(),
+//                         "avatar", user.getAvatarUrl() != null ? user.getAvatarUrl() : "https://example.com/default-avatar.jpg",
+//                         "nickname", user.getUsername() != null ? user.getUsername() : "未知用户",
+//                         "email", user.getEmail() != null ? user.getEmail() : "未填写"
+//                 );
+//                 friends.add(friendInfo);
+//             }
+//         }
+
+//         return friends;
+//     }
+
+//     @PostMapping("/{userId}/uploadAvatar")
+//     public Map<String, Object> uploadAvatar(
+//             @PathVariable Long userId,
+//             @RequestParam("file") MultipartFile file) {
+//         return userService.uploadUserAvatar(userId, file);
+//     }
+
+
+
+// }
+
 package com.example.myproject.controller;
 
+import com.example.myproject.entity.FriendRelation;
 import com.example.myproject.entity.Users;
+import com.example.myproject.repository.FriendRelationRepository;
 import com.example.myproject.repository.UserRepository;
 import com.example.myproject.service.DynamicService;
-import com.example.myproject.service.TaskService;
 import com.example.myproject.service.UserService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
-import javax.servlet.http.HttpServletRequest;
-import java.util.Map;
-import java.util.Optional;
-
-import java.util.List;
-import java.util.ArrayList;
+import java.util.*;
 
 
 @RestController
@@ -31,6 +190,41 @@
     @Autowired
     private DynamicService dynamicService;
 
+    @Autowired
+    private FriendRelationRepository friendRelationRepository;
+
+
+    @PostMapping ("/addFriend")
+    public Map<String, Object> addFriend(@RequestBody Map<String, Object> request) {
+        //邮箱查用户
+        Optional<Users> userOptional = userRepository.findByEmail(request.get("email").toString());
+        // 如果用户不存在,返回null或者可以抛出异常
+        if (userOptional.isEmpty()) {
+            return Map.of("msg", "没有找到该用户"); // 可以返回 null 或者根据需要返回错误信息
+        }
+        Long userId = Long.parseLong(request.get("userid").toString());       //id查用户
+        Map<String, Object> users = userService.getProfile(userId);
+        // 如果用户不存在,返回null或者可以抛出异常
+        if (users.isEmpty()) {
+            return Map.of("msg", "当前登录账号异常"); // 可以返回 null 或者根据需要返回错误信息
+        }
+
+        FriendRelation  newFriendRelation  = new FriendRelation();
+        newFriendRelation.setUserId(userId);
+        newFriendRelation.setCreateTime(new Date());
+        newFriendRelation.setFriendId(userOptional.get().getUserId());
+
+        FriendRelation  newFriendRelations  = new FriendRelation();
+        newFriendRelations.setCreateTime(new Date());
+        newFriendRelations.setUserId(userOptional.get().getUserId());
+        newFriendRelations.setFriendId(userId);
+
+        friendRelationRepository.save(newFriendRelation);
+        friendRelationRepository.save(newFriendRelations);
+
+        return Map.of("msg", "添加成功");
+    }
+
     // 接口:生成邀请码
     @PostMapping("/getInviteCode")
     public Map<String, Object> generateInviteCode(@RequestBody Map<String, Object> request) {
@@ -163,3 +357,7 @@
 }
 
 
+
+
+
+