调整了相关字段信息,并1. 根据用户id获取用户未完成上传任务的作品的接口2. 根据用户id获取已完成上传任务的作品3. 根据用户id获取用户角色, 至少要有管理员,同时合并了帖子功能与作品
Change-Id: Id2c664cc212f2aef1f99054d386d28083fe13d92
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/UserRoleController.java b/src/main/java/edu/bjtu/groupone/backend/api/UserRoleController.java
new file mode 100644
index 0000000..56abf19
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/api/UserRoleController.java
@@ -0,0 +1,31 @@
+package edu.bjtu.groupone.backend.api;
+
+import edu.bjtu.groupone.backend.domain.UserRole;
+import edu.bjtu.groupone.backend.service.UserRoleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/user-roles")
+public class UserRoleController {
+ @Autowired
+ private UserRoleService userRoleService;
+
+ @GetMapping("/{userId}")
+ public ResponseEntity<List<UserRole>> getUserRoles(@PathVariable Long userId) {
+ return ResponseEntity.ok(userRoleService.getUserRolesByUserId(userId));
+ }
+
+ @GetMapping("/{userId}/is-admin")
+ public ResponseEntity<Boolean> isAdmin(@PathVariable Long userId) {
+ return ResponseEntity.ok(userRoleService.isAdmin(userId));
+ }
+
+ @PostMapping
+ public ResponseEntity<Integer> addUserRole(@RequestBody UserRole userRole) {
+ return ResponseEntity.ok(userRoleService.addUserRole(userRole));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java b/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java
index d15c4ce..28cd43d 100644
--- a/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java
+++ b/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java
@@ -1,8 +1,11 @@
package edu.bjtu.groupone.backend.api;
import edu.bjtu.groupone.backend.domain.dto.WorkResponse;
+import edu.bjtu.groupone.backend.domain.dto.WorkDetailResponse;
import edu.bjtu.groupone.backend.domain.entity.Result;
import edu.bjtu.groupone.backend.domain.entity.Work;
+import edu.bjtu.groupone.backend.domain.entity.Version;
+import edu.bjtu.groupone.backend.domain.entity.Comment;
import edu.bjtu.groupone.backend.service.WorkService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -34,36 +37,70 @@
@Parameter(description = "每页数量", example = "20") @RequestParam(defaultValue = "20") int size) {
return ResponseEntity.ok(workService.getWorks(categoryId, page, size));
}
- @PostMapping
- @Operation(summary = "创建新作品")
- public ResponseEntity<String> createWork(@RequestBody Work work) {
- workService.addWork(work);
- return ResponseEntity.ok("作品创建成功");
+
+ @GetMapping("/uncompleted/{userId}")
+ public ResponseEntity<List<Work>> getUncompletedWorks(@PathVariable Long userId) {
+ return ResponseEntity.ok(workService.getUncompletedWorksByUserId(userId));
}
- // 删除作品
- @DeleteMapping("/{id}")
- @Operation(summary = "删除作品")
- public ResponseEntity<String> deleteWork(@PathVariable Long id) {
- workService.deleteWork(id);
- return ResponseEntity.ok("作品删除成功");
+ @GetMapping("/completed/{userId}")
+ public ResponseEntity<List<Work>> getCompletedWorks(@PathVariable Long userId) {
+ return ResponseEntity.ok(workService.getCompletedWorksByUserId(userId));
}
- // 更新作品
- @PutMapping("/{id}")
- @Operation(summary = "更新作品信息")
- public ResponseEntity<String> updateWork(@PathVariable Long id, @RequestBody Work work) {
- work.setId(id);
- workService.updateWork(work);
- return ResponseEntity.ok("作品更新成功");
- }
-
- // 获取单个作品
@GetMapping("/{id}")
- @Operation(summary = "获取作品详情")
- public ResponseEntity<Work> getWork(@PathVariable Long id) {
+ public ResponseEntity<Work> getWorkById(@PathVariable Long id) {
return ResponseEntity.ok(workService.getWorkById(id));
}
+
+ @GetMapping("/detail/{id}")
+ public ResponseEntity<WorkDetailResponse> getWorkDetail(@PathVariable Long id) {
+ WorkDetailResponse dto = workService.getWorkDetailById(id);
+ if (dto == null) return ResponseEntity.notFound().build();
+ return ResponseEntity.ok(dto);
+ }
+
+ @PostMapping
+ @Operation(summary = "创建新作品")
+ public ResponseEntity<Integer> createWork(@RequestBody Work work) {
+ return ResponseEntity.ok(workService.createWork(work));
+ }
+
+ @PutMapping("/{id}")
+ @Operation(summary = "更新作品信息")
+ public ResponseEntity<Integer> updateWork(@PathVariable Long id, @RequestBody Work work) {
+ work.setId(id);
+ return ResponseEntity.ok(workService.updateWork(work));
+ }
+
+ @DeleteMapping("/{id}")
+ @Operation(summary = "删除作品")
+ public ResponseEntity<Integer> deleteWork(@PathVariable Long id) {
+ return ResponseEntity.ok(workService.deleteWork(id));
+ }
+
+ @PostMapping("/{workId}/versions")
+ public ResponseEntity<Integer> addVersion(@PathVariable Long workId, @RequestBody Version version) {
+ version.setWorkId(workId);
+ return ResponseEntity.ok(workService.addVersion(version));
+ }
+
+ @DeleteMapping("/versions/{id}")
+ public ResponseEntity<Integer> deleteVersion(@PathVariable Long id) {
+ return ResponseEntity.ok(workService.deleteVersion(id));
+ }
+
+ @PostMapping("/{workId}/comments")
+ public ResponseEntity<Integer> addComment(@PathVariable Long workId, @RequestBody Comment comment) {
+ comment.setPostId(workId);
+ return ResponseEntity.ok(workService.addComment(comment));
+ }
+
+ @DeleteMapping("/comments/{id}")
+ public ResponseEntity<Integer> deleteComment(@PathVariable Long id) {
+ return ResponseEntity.ok(workService.deleteComment(id));
+ }
+
@Operation(
summary = "根据作者查询所有作品",
description = "根据作者名称查询其所有作品",
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/UserRole.java b/src/main/java/edu/bjtu/groupone/backend/domain/UserRole.java
new file mode 100644
index 0000000..18e7b6a
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/UserRole.java
@@ -0,0 +1,11 @@
+package edu.bjtu.groupone.backend.domain;
+
+import lombok.Data;
+
+@Data
+public class UserRole {
+ private Long id;
+ private Long userId;
+ private String role; // ADMIN, USER
+ private String createTime;
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/Work.java b/src/main/java/edu/bjtu/groupone/backend/domain/Work.java
new file mode 100644
index 0000000..673acb3
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/Work.java
@@ -0,0 +1,35 @@
+package edu.bjtu.groupone.backend.domain;
+
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class Work {
+ private Long id;
+ private String title;
+ private String description;
+ private Long userId;
+ private String status; // UPLOADING, COMPLETED
+ private List<Version> versions;
+ private List<Comment> comments;
+ private String createTime;
+ private String updateTime;
+}
+
+@Data
+class Version {
+ private Long id;
+ private Long workId;
+ private String versionNumber;
+ private String fileUrl;
+ private String createTime;
+}
+
+@Data
+class Comment {
+ private Long id;
+ private Long workId;
+ private Long userId;
+ private String content;
+ private String createTime;
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/dto/WorkDetailResponse.java b/src/main/java/edu/bjtu/groupone/backend/domain/dto/WorkDetailResponse.java
new file mode 100644
index 0000000..84065b0
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/dto/WorkDetailResponse.java
@@ -0,0 +1,59 @@
+package edu.bjtu.groupone.backend.domain.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class WorkDetailResponse {
+ @JsonProperty("artworkId")
+ private String artworkId;
+ @JsonProperty("artworkCover")
+ private String artworkCover;
+ private String author;
+ @JsonProperty("authorId")
+ private String authorId;
+ @JsonProperty("artworkName")
+ private String artworkName;
+ @JsonProperty("artworkCategory")
+ private String artworkCategory;
+ @JsonProperty("comments")
+ private List<CommentDTO> comments;
+ @JsonProperty("artworkDescription")
+ private String artworkDescription;
+ @JsonProperty("versionList")
+ private List<VersionDTO> versionList;
+ @JsonProperty("usersSeedingCurrently")
+ private List<UserDTO> usersSeedingCurrently;
+ @JsonProperty("usersSeedingHistory")
+ private List<HistoryUserDTO> usersSeedingHistory;
+
+ @Data
+ public static class CommentDTO {
+ private String id;
+ private String content;
+ private String author;
+ private String authorId;
+ private String createdAt;
+ private List<CommentDTO> child;
+ }
+
+ @Data
+ public static class VersionDTO {
+ private String version;
+ private String seedFile;
+ private String versionDescription;
+ }
+
+ @Data
+ public static class UserDTO {
+ private String username;
+ private String userId;
+ }
+
+ @Data
+ public static class HistoryUserDTO {
+ private String username;
+ private String uploadTotal;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Version.java b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Version.java
new file mode 100644
index 0000000..1cd1706
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Version.java
@@ -0,0 +1,13 @@
+package edu.bjtu.groupone.backend.domain.entity;
+
+import lombok.Data;
+
+@Data
+public class Version {
+ private Long id;
+ private Long workId;
+ private String versionNumber;
+ private String fileUrl;
+ private String description; // 版本描述
+ private String createTime;
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Work.java b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Work.java
index ca3b365..1512c2f 100644
--- a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Work.java
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Work.java
@@ -34,4 +34,7 @@
@Column(name = "create_time")
private String createTime;
+
+ @Column(length = 255)
+ private String cover;
}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/mapper/UserRoleMapper.java b/src/main/java/edu/bjtu/groupone/backend/mapper/UserRoleMapper.java
new file mode 100644
index 0000000..01efb71
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/mapper/UserRoleMapper.java
@@ -0,0 +1,16 @@
+package edu.bjtu.groupone.backend.mapper;
+
+import edu.bjtu.groupone.backend.domain.UserRole;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+@Mapper
+public interface UserRoleMapper {
+ @Select("SELECT * FROM user_role WHERE user_id = #{userId}")
+ List<UserRole> getUserRolesByUserId(Long userId);
+
+ @Insert("INSERT INTO user_role (user_id, role, create_time) VALUES (#{userId}, #{role}, NOW())")
+ @Options(useGeneratedKeys = true, keyProperty = "id")
+ int insertUserRole(UserRole userRole);
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/mapper/WorkMapper.java b/src/main/java/edu/bjtu/groupone/backend/mapper/WorkMapper.java
new file mode 100644
index 0000000..2ec1050
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/mapper/WorkMapper.java
@@ -0,0 +1,62 @@
+package edu.bjtu.groupone.backend.mapper;
+
+import edu.bjtu.groupone.backend.domain.entity.Work;
+import edu.bjtu.groupone.backend.domain.entity.Version;
+import edu.bjtu.groupone.backend.domain.entity.Comment;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface WorkMapper {
+ @Select("SELECT * FROM work WHERE user_id = #{userId} AND status = 'UPLOADING'")
+ List<Work> getUncompletedWorksByUserId(Long userId);
+
+ @Select("SELECT * FROM work WHERE user_id = #{userId} AND status = 'COMPLETED'")
+ List<Work> getCompletedWorksByUserId(Long userId);
+
+ @Select("SELECT * FROM work WHERE id = #{id}")
+ Work getWorkById(Long id);
+
+ @Insert("INSERT INTO work (title, description, user_id, status, create_time, update_time) " +
+ "VALUES (#{title}, #{description}, #{userId}, #{status}, NOW(), NOW())")
+ @Options(useGeneratedKeys = true, keyProperty = "id")
+ int insertWork(Work work);
+
+ @Update("UPDATE work SET title = #{title}, description = #{description}, status = #{status}, " +
+ "update_time = NOW() WHERE id = #{id}")
+ int updateWork(Work work);
+
+ @Delete("DELETE FROM work WHERE id = #{id}")
+ int deleteWork(Long id);
+
+ @Insert("INSERT INTO version (work_id, version_number, file_url, description, create_time) " +
+ "VALUES (#{workId}, #{versionNumber}, #{fileUrl}, #{description}, NOW())")
+ @Options(useGeneratedKeys = true, keyProperty = "id")
+ int insertVersion(Version version);
+
+ @Delete("DELETE FROM version WHERE id = #{id}")
+ int deleteVersion(Long id);
+
+ @Insert("INSERT INTO comment (work_id, user_id, content, create_time) " +
+ "VALUES (#{workId}, #{userId}, #{content}, NOW())")
+ @Options(useGeneratedKeys = true, keyProperty = "id")
+ int insertComment(Comment comment);
+
+ @Delete("DELETE FROM comment WHERE id = #{id}")
+ int deleteComment(Long id);
+
+ // 新增聚合查询
+ @Select("SELECT content FROM comment WHERE work_id = #{workId}")
+ List<String> getCommentsByWorkId(Long workId);
+
+ @Select("SELECT version_number, file_url, description FROM version WHERE work_id = #{workId}")
+ List<Map<String, Object>> getVersionsByWorkId(Long workId);
+
+ @Select("SELECT u.username, u.user_id FROM seeding_user su JOIN user u ON su.user_id = u.user_id WHERE su.work_id = #{workId} AND su.status = 'seeding'")
+ List<Map<String, Object>> getSeedingUsersByWorkId(Long workId);
+
+ @Select("SELECT u.username, u.user_id, su.uploaded FROM seeding_user su JOIN user u ON su.user_id = u.user_id WHERE su.work_id = #{workId} AND su.status = 'history'")
+ List<Map<String, Object>> getHistorySeedingUsersByWorkId(Long workId);
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/UserRoleService.java b/src/main/java/edu/bjtu/groupone/backend/service/UserRoleService.java
new file mode 100644
index 0000000..6c303c0
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/UserRoleService.java
@@ -0,0 +1,27 @@
+package edu.bjtu.groupone.backend.service;
+
+import edu.bjtu.groupone.backend.domain.UserRole;
+import edu.bjtu.groupone.backend.mapper.UserRoleMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class UserRoleService {
+ @Autowired
+ private UserRoleMapper userRoleMapper;
+
+ public List<UserRole> getUserRolesByUserId(Long userId) {
+ return userRoleMapper.getUserRolesByUserId(userId);
+ }
+
+ public boolean isAdmin(Long userId) {
+ List<UserRole> roles = getUserRolesByUserId(userId);
+ return roles.stream().anyMatch(role -> "ADMIN".equals(role.getRole()));
+ }
+
+ public int addUserRole(UserRole userRole) {
+ return userRoleMapper.insertUserRole(userRole);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java b/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
index 7aeebf1..5693bb1 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
@@ -1,30 +1,57 @@
package edu.bjtu.groupone.backend.service;
-//import edu.bjtu.groupone.backend.model.Work;
import edu.bjtu.groupone.backend.domain.dto.WorkResponse;
import edu.bjtu.groupone.backend.domain.entity.Work;
import edu.bjtu.groupone.backend.mapper.WorkMybatisMapper;
+import edu.bjtu.groupone.backend.mapper.WorkMapper;
+//import edu.bjtu.groupone.backend.model.Work;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
+
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
+
+import edu.bjtu.groupone.backend.domain.dto.WorkDetailResponse;
+import edu.bjtu.groupone.backend.domain.entity.Version;
+import edu.bjtu.groupone.backend.domain.entity.Comment;
+import edu.bjtu.groupone.backend.mapper.UserMapper;
+import edu.bjtu.groupone.backend.domain.entity.Post;
+import edu.bjtu.groupone.backend.mapper.PostMapper;
+import edu.bjtu.groupone.backend.mapper.CommentMapper;
+import edu.bjtu.groupone.backend.domain.entity.User;
+
@Service
public class WorkService {
@Autowired
private WorkMybatisMapper workMybatisMapper;
+
@Autowired
private CategoryService categoryService;
+
+ @Autowired
+ private WorkMapper workMapper;
+
+ @Autowired
+ private UserMapper userMapper;
+
+ @Autowired
+ private PostMapper postMapper;
+
+ @Autowired
+ private CommentMapper commentMapper;
+
public Page<WorkResponse> getWorks(Long categoryId, int page, int size) {
List<Long> categoryIds = categoryService.getAllSubcategoryIds(categoryId);
Pageable pageable = PageRequest.of(page-1, size);
return workMybatisMapper.findByCategoryIdIn(categoryIds, pageable)
.map(this::convertToResponse);
}
+
private WorkResponse convertToResponse(Work work) {
return new WorkResponse(
work.getId(),
@@ -36,27 +63,124 @@
work.getCreateTime()
);
}
+
public void addWork(Work work) {
work.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
workMybatisMapper.save(work);
}
- public void deleteWork(Long id) {
- workMybatisMapper.deleteById(id);
- }
- public void updateWork(Work work) {
- Work existing = workMybatisMapper.findById(work.getId());
- if (existing != null) {
- work.setCreateTime(existing.getCreateTime());
- }
- workMybatisMapper.update(work);
- }
+
+
+
public Work getWorkById(Long id) {
return workMybatisMapper.findById(id);
}
+
public List<WorkResponse> getWorksByAuthor(String author) {
List<Work> works = workMybatisMapper.findByAuthor(author);
return works.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
+
+ public List<Work> getUncompletedWorksByUserId(Long userId) {
+ return workMapper.getUncompletedWorksByUserId(userId);
+ }
+
+ public List<Work> getCompletedWorksByUserId(Long userId) {
+ return workMapper.getCompletedWorksByUserId(userId);
+ }
+
+ public int createWork(Work work) {
+ return workMapper.insertWork(work);
+ }
+
+ public int updateWork(Work work) {
+ return workMapper.updateWork(work);
+ }
+
+ public int deleteWork(Long id) {
+ return workMapper.deleteWork(id);
+ }
+
+ public int addVersion(Version version) {
+ return workMapper.insertVersion(version);
+ }
+
+ public int deleteVersion(Long id) {
+ return workMapper.deleteVersion(id);
+ }
+
+ public int addComment(Comment comment) {
+ return workMapper.insertComment(comment);
+ }
+
+ public int deleteComment(Long id) {
+ return workMapper.deleteComment(id);
+ }
+
+ public WorkDetailResponse getWorkDetailById(Long workId) {
+ Work work = workMapper.getWorkById(workId);
+ if (work == null) return null;
+ WorkDetailResponse dto = new WorkDetailResponse();
+ // 基本字段映射
+ dto.setArtworkId(work.getId() != null ? work.getId().toString() : null);
+ dto.setArtworkCover(work.getCover());
+ dto.setAuthor(work.getAuthor());
+ dto.setAuthorId(work.getAuthor()); // 如需userId请调整
+ dto.setArtworkName(work.getTitle());
+ dto.setArtworkCategory(work.getCategory() != null ? work.getCategory().getName() : null);
+ dto.setArtworkDescription(work.getDescription());
+ // 版本列表
+ List<java.util.Map<String, Object>> versionList = workMapper.getVersionsByWorkId(workId);
+ List<WorkDetailResponse.VersionDTO> versions = new java.util.ArrayList<>();
+ for (java.util.Map<String, Object> v : versionList) {
+ WorkDetailResponse.VersionDTO vi = new WorkDetailResponse.VersionDTO();
+ vi.setVersion((String)v.get("version_number"));
+ vi.setSeedFile((String)v.get("file_url"));
+ vi.setVersionDescription((String)v.get("description"));
+ versions.add(vi);
+ }
+ dto.setVersionList(versions);
+ // 正在做种用户
+ List<java.util.Map<String, Object>> seedingList = workMapper.getSeedingUsersByWorkId(workId);
+ List<WorkDetailResponse.UserDTO> seedingUsers = new java.util.ArrayList<>();
+ for (java.util.Map<String, Object> u : seedingList) {
+ WorkDetailResponse.UserDTO su = new WorkDetailResponse.UserDTO();
+ su.setUsername((String)u.get("username"));
+ su.setUserId(String.valueOf(u.get("user_id")));
+ seedingUsers.add(su);
+ }
+ dto.setUsersSeedingCurrently(seedingUsers);
+ // 历史做种用户
+ List<java.util.Map<String, Object>> historyList = workMapper.getHistorySeedingUsersByWorkId(workId);
+ List<WorkDetailResponse.HistoryUserDTO> historyUsers = new java.util.ArrayList<>();
+ for (java.util.Map<String, Object> u : historyList) {
+ WorkDetailResponse.HistoryUserDTO hu = new WorkDetailResponse.HistoryUserDTO();
+ hu.setUsername((String)u.get("username"));
+ hu.setUploadTotal((String)u.get("uploaded"));
+ historyUsers.add(hu);
+ }
+ dto.setUsersSeedingHistory(historyUsers);
+ // 评论递归组装
+ Post post = postMapper.selectPostById(workId);
+ if (post != null) {
+ List<Comment> commentList = commentMapper.selectCommentsByPostId(post.getPostId());
+ List<WorkDetailResponse.CommentDTO> commentDTOList = new java.util.ArrayList<>();
+ for (Comment c : commentList) {
+ WorkDetailResponse.CommentDTO cdto = new WorkDetailResponse.CommentDTO();
+ cdto.setId(c.getCommentId() != null ? c.getCommentId().toString() : null);
+ cdto.setContent(c.getContent());
+ User user = userMapper.selectById((long)c.getUserId());
+ cdto.setAuthor(user != null ? user.getUsername() : null);
+ cdto.setAuthorId(String.valueOf(c.getUserId()));
+ cdto.setCreatedAt(c.getCreateTime());
+ cdto.setChild(new java.util.ArrayList<>()); // 如有子评论可递归
+ commentDTOList.add(cdto);
+ }
+ dto.setComments(commentDTOList);
+ } else {
+ dto.setComments(new java.util.ArrayList<>());
+ }
+ return dto;
+ }
}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/WorkServiceDetailTest.java b/src/test/java/edu/bjtu/groupone/backend/WorkServiceDetailTest.java
new file mode 100644
index 0000000..137e43f
--- /dev/null
+++ b/src/test/java/edu/bjtu/groupone/backend/WorkServiceDetailTest.java
@@ -0,0 +1,133 @@
+package edu.bjtu.groupone.backend;
+
+import edu.bjtu.groupone.backend.domain.dto.WorkDetailResponse;
+import edu.bjtu.groupone.backend.domain.entity.*;
+import edu.bjtu.groupone.backend.mapper.*;
+import edu.bjtu.groupone.backend.service.WorkService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class WorkServiceDetailTest {
+
+ @Mock
+ private WorkMapper workMapper;
+ @Mock
+ private UserMapper userMapper;
+ @Mock
+ private PostMapper postMapper;
+ @Mock
+ private CommentMapper commentMapper;
+
+ @InjectMocks
+ private WorkService workService;
+
+ private Work work;
+ private Post post;
+
+ @BeforeEach
+ void setUp() {
+ Category category = new Category(1L, "分区1", null);
+ work = Work.builder()
+ .id(12345L)
+ .title("作品标题")
+ .author("作者A")
+ .views(100)
+ .category(category)
+ .description("作品描述")
+ .createTime("2024-05-01")
+ .cover("https://via.placeholder.com/200/")
+ .build();
+
+ post = new Post();
+ post.setPostId(12345L);
+ post.setUserId(1);
+ post.setTitle("帖子标题");
+ post.setContent("帖子内容");
+ post.setCreateTime("2024-05-01");
+ post.setViews(10);
+ }
+
+ @Test
+ void getWorkDetailById_shouldReturnAggregatedDetail() {
+ // mock 作品
+ when(workMapper.getWorkById(12345L)).thenReturn(work);
+ // mock 版本
+ Map<String, Object> version1 = new HashMap<>();
+ version1.put("version_number", "1.0");
+ version1.put("file_url", "file1.torrent");
+ version1.put("description", "版本1描述");
+ Map<String, Object> version2 = new HashMap<>();
+ version2.put("version_number", "1.1");
+ version2.put("file_url", "file2.torrent");
+ version2.put("description", "版本1.1描述");
+ when(workMapper.getVersionsByWorkId(12345L)).thenReturn(Arrays.asList(version1, version2));
+ // mock 正在做种用户
+ Map<String, Object> seeder = new HashMap<>();
+ seeder.put("username", "用户A");
+ seeder.put("user_id", 1L);
+ when(workMapper.getSeedingUsersByWorkId(12345L)).thenReturn(Collections.singletonList(seeder));
+ // mock 历史做种用户
+ Map<String, Object> historySeeder = new HashMap<>();
+ historySeeder.put("username", "用户B");
+ historySeeder.put("user_id", 2L);
+ historySeeder.put("uploaded", "10GB");
+ when(workMapper.getHistorySeedingUsersByWorkId(12345L)).thenReturn(Collections.singletonList(historySeeder));
+ // mock 帖子
+ when(postMapper.selectPostById(anyLong())).thenReturn(post);
+ // mock 评论
+ Comment comment = new Comment(1L, 12345L, 2, "评论内容", "2024-05-01");
+ when(commentMapper.selectCommentsByPostId(12345L)).thenReturn(Collections.singletonList(comment));
+ User commentUser = new User();
+ commentUser.setUserId(2);
+ commentUser.setUsername("评论者");
+ when(userMapper.selectById(2L)).thenReturn(commentUser);
+
+ WorkDetailResponse detail = workService.getWorkDetailById(12345L);
+
+ assertNotNull(detail);
+ assertEquals("12345", detail.getArtworkId());
+ assertEquals("https://via.placeholder.com/200/", detail.getArtworkCover());
+ assertEquals("作者A", detail.getAuthor());
+ assertEquals("作者A", detail.getAuthorId()); // 如需userId请调整
+ assertEquals("作品标题", detail.getArtworkName());
+ assertEquals("分区1", detail.getArtworkCategory());
+ assertEquals("作品描述", detail.getArtworkDescription());
+ // 版本断言
+ assertEquals(2, detail.getVersionList().size());
+ assertEquals("1.0", detail.getVersionList().get(0).getVersion());
+ assertEquals("file1.torrent", detail.getVersionList().get(0).getSeedFile());
+ assertEquals("版本1描述", detail.getVersionList().get(0).getVersionDescription());
+ // 做种用户断言
+ assertEquals(1, detail.getUsersSeedingCurrently().size());
+ assertEquals("用户A", detail.getUsersSeedingCurrently().get(0).getUsername());
+ assertEquals("1", detail.getUsersSeedingCurrently().get(0).getUserId());
+ // 历史做种用户断言
+ assertEquals(1, detail.getUsersSeedingHistory().size());
+ assertEquals("用户B", detail.getUsersSeedingHistory().get(0).getUsername());
+ assertEquals("10GB", detail.getUsersSeedingHistory().get(0).getUploadTotal());
+ // 评论断言
+ assertEquals(1, detail.getComments().size());
+ assertEquals("1", detail.getComments().get(0).getId());
+ assertEquals("评论内容", detail.getComments().get(0).getContent());
+ assertEquals("评论者", detail.getComments().get(0).getAuthor());
+ assertEquals("2", detail.getComments().get(0).getAuthorId());
+ assertEquals("2024-05-01", detail.getComments().get(0).getCreatedAt());
+ assertTrue(detail.getComments().get(0).getChild().isEmpty());
+ }
+
+ @Test
+ void getWorkDetailById_shouldReturnNullIfWorkNotFound() {
+ when(workMapper.getWorkById(999L)).thenReturn(null);
+ assertNull(workService.getWorkDetailById(999L));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java b/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
index 44a05b6..118ff01 100644
--- a/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
+++ b/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
@@ -6,6 +6,7 @@
import edu.bjtu.groupone.backend.domain.entity.Category;
import edu.bjtu.groupone.backend.domain.entity.Work;
import edu.bjtu.groupone.backend.mapper.WorkMybatisMapper;
+import edu.bjtu.groupone.backend.mapper.WorkMapper;
import edu.bjtu.groupone.backend.service.CategoryService;
import edu.bjtu.groupone.backend.service.PeerTrafficService;
import edu.bjtu.groupone.backend.service.WorkService;
@@ -38,6 +39,9 @@
private WorkMybatisMapper workMybatisMapper;
@Mock
+ private WorkMapper workMapper;
+
+ @Mock
private CategoryService categoryService;
@InjectMocks
@@ -61,8 +65,24 @@
Category category = new Category(1L, "文学艺术", null);
works = Arrays.asList(
- new Work(1L, "《我的世界》", "张三", 1234, category, "一部关于...", "2023-06-15"),
- new Work(2L, "《你的世界》", "张三", 567, category, "另一部关于...", "2023-06-16")
+ Work.builder()
+ .id(1L)
+ .title("《我的世界》")
+ .author("张三")
+ .views(1234)
+ .category(category)
+ .description("一部关于...")
+ .createTime("2023-06-15")
+ .build(),
+ Work.builder()
+ .id(2L)
+ .title("《你的世界》")
+ .author("张三")
+ .views(567)
+ .category(category)
+ .description("另一部关于...")
+ .createTime("2023-06-16")
+ .build()
);
}
@@ -73,15 +93,21 @@
}
@Test
+ void createWork_shouldCallMapper() {
+ workService.createWork(testWork);
+ verify(workMapper, times(1)).insertWork(testWork);
+ }
+
+ @Test
void deleteWork_shouldCallMapper() {
workService.deleteWork(1L);
- verify(workMybatisMapper, times(1)).deleteById(1L);
+ verify(workMapper, times(1)).deleteWork(1L);
}
@Test
void updateWork_shouldCallMapper() {
workService.updateWork(testWork);
- verify(workMybatisMapper, times(1)).update(testWork);
+ verify(workMapper, times(1)).updateWork(testWork);
}
@Test