新增下载人查询接口,并把管理员判定收敛到服务端
- Gallery 增加 downloaderName,仅在管理员查询任务列表时填充;普通用户 既不获取也不下发他人身份 - 新增 GET /GalleryManage/downloader?gid=&AuthCode=,按 gid 返回实际下载人 昵称,非管理员一律拒绝 - /validate 下发 isAdmin,前端不再各自硬编码 userId === 3 - 管理员判定统一走 UserService.ADMIN_USER_ID - 补充列表填充、按 gid 查询的权限与缺任务分支测试
This commit is contained in:
@@ -67,6 +67,14 @@ public class GalleryManageController {
|
||||
return galleryManageService.deleteGalleryByGid(gid, AuthCode);
|
||||
}
|
||||
|
||||
/** 按 gid 查实际下载人昵称,仅管理员可用。 */
|
||||
@GetMapping("/downloader")
|
||||
public String selectDownloader(Integer gid, String AuthCode){
|
||||
if(gid == null)
|
||||
return Response._failure("参数不全");
|
||||
return galleryManageService.selectDownloaderByGid(gid, AuthCode);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/collect")
|
||||
public String collectGallery(Integer gid, String AuthCode){
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.lion.lionwebsite.Service.PublicService;
|
||||
import com.lion.lionwebsite.Service.QueryService;
|
||||
import com.lion.lionwebsite.Service.RemoteService;
|
||||
import com.lion.lionwebsite.Service.SubService;
|
||||
import com.lion.lionwebsite.Service.UserService;
|
||||
import com.lion.lionwebsite.Util.Response;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -82,9 +83,12 @@ public class PublicController {
|
||||
Response response = Response.generateResponse();
|
||||
User user = publicService.getUserId(AuthCode);
|
||||
String isAvailable = remoteService.isDead() ? "false": "true";
|
||||
// 管理员标记随登录一起下发,前端据此决定是否显示下载人信息与筛选。
|
||||
String isAdmin = user.getId() == UserService.ADMIN_USER_ID ? "true" : "false";
|
||||
response.success(String.format("{\"userId\": %d, " +
|
||||
"\"username\": \"%s\", " +
|
||||
"\"isAvailable\": %s}", user.getId(), user.getUsername(), isAvailable));
|
||||
"\"isAvailable\": %s, " +
|
||||
"\"isAdmin\": %s}", user.getId(), user.getUsername(), isAvailable, isAdmin));
|
||||
return response.toJSONString();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ public interface UserMapper {
|
||||
@Select("select * from User where username=#{username}")
|
||||
User selectUserByUsername(String username);
|
||||
|
||||
@Select("select * from User where id=#{id}")
|
||||
User selectUserById(int id);
|
||||
|
||||
@Select("select AuthCode from User")
|
||||
String[] selectAllAuthCode();
|
||||
|
||||
|
||||
@@ -48,6 +48,11 @@ public class Gallery {
|
||||
@JsonProperty("downloader")
|
||||
private int downloader; //下载人
|
||||
|
||||
/** 下载人昵称。仅管理员查询时填充,普通用户拿不到,避免暴露他人信息。 */
|
||||
@JsonProperty("downloaderName")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private String downloaderName;
|
||||
|
||||
@JsonProperty("collector")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private String collector; //收藏人
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.lion.lionwebsite.Util.GalleryUtil;
|
||||
import com.lion.lionwebsite.Util.Response;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.Data;
|
||||
@@ -254,10 +255,56 @@ public class GalleryManageService {
|
||||
}
|
||||
}
|
||||
|
||||
// 下载人昵称只对管理员下发;一次建表避免逐条查询。
|
||||
if (userId == UserService.ADMIN_USER_ID)
|
||||
fillDownloaderNames(galleries);
|
||||
|
||||
response.success(new ObjectMapper().valueToTree(galleries).toString());
|
||||
return response.toJSONString();
|
||||
}
|
||||
|
||||
/** 给任务列表补上下载人昵称,找不到用户时保留空值而不是报错。 */
|
||||
private void fillDownloaderNames(Gallery[] galleries) {
|
||||
User[] users = userMapper.selectAllUser();
|
||||
Map<Integer, String> names = new HashMap<>();
|
||||
if (users != null)
|
||||
for (User user : users)
|
||||
names.put(user.getId(), user.getUsername());
|
||||
|
||||
for (Gallery gallery : galleries)
|
||||
gallery.setDownloaderName(names.get(gallery.getDownloader()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询某个任务的实际下载人昵称。
|
||||
* 只有管理员可调用,普通用户一律拒绝,避免暴露他人身份。
|
||||
*
|
||||
* @param gid 任务 gid
|
||||
* @param AuthCode 调用方授权码
|
||||
*/
|
||||
public String selectDownloaderByGid(int gid, String AuthCode) {
|
||||
Response response = Response.generateResponse();
|
||||
User requester = userMapper.selectUserByAuthCode(AuthCode);
|
||||
if (requester == null || requester.getId() != UserService.ADMIN_USER_ID) {
|
||||
response.failure("无权查看下载人");
|
||||
return response.toJSONString();
|
||||
}
|
||||
|
||||
Gallery gallery = galleryMapper.selectGalleryByGid(gid);
|
||||
if (gallery == null) {
|
||||
response.failure("任务不存在");
|
||||
return response.toJSONString();
|
||||
}
|
||||
|
||||
User downloader = userMapper.selectUserById(gallery.getDownloader());
|
||||
ObjectNode node = objectMapper.createObjectNode();
|
||||
node.put("gid", gid);
|
||||
node.put("downloader", gallery.getDownloader());
|
||||
node.put("downloaderName", downloader == null ? "" : downloader.getUsername());
|
||||
response.success(node);
|
||||
return response.toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过图片名查询图片
|
||||
*
|
||||
|
||||
@@ -135,4 +135,18 @@ public class UserService{
|
||||
public int getUserId(String AuthCode){
|
||||
return userMapper.selectUserByAuthCode(AuthCode).getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员判定。项目没有角色表,历史上以 id=3(狮子)作为管理员,
|
||||
* 前端也是用 userId === 3 判断;这里把这个约定收敛到一处,
|
||||
* 权限相关的服务端校验统一走它。
|
||||
*/
|
||||
public static final int ADMIN_USER_ID = 3;
|
||||
|
||||
public boolean isAdmin(String AuthCode){
|
||||
if(AuthCode == null)
|
||||
return false;
|
||||
User user = userMapper.selectUserByAuthCode(AuthCode);
|
||||
return user != null && user.getId() == ADMIN_USER_ID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,29 @@ class GalleryManageControllerTest {
|
||||
|
||||
// ---------- deleteTask ----------
|
||||
|
||||
// ---------- 下载人查询 ----------
|
||||
|
||||
/** 缺 gid 时在控制器层拦住,不进服务层。 */
|
||||
@Test
|
||||
void selectDownloaderRejectsMissingGid() throws Exception {
|
||||
mockMvc.perform(get("/GalleryManage/downloader").param("AuthCode", "code"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsFailure()));
|
||||
|
||||
verifyNoInteractions(galleryManageService);
|
||||
}
|
||||
|
||||
/** 正常请求必须把 gid 与授权码原样传给服务层。 */
|
||||
@Test
|
||||
void selectDownloaderDelegatesWithGidAndAuthCode() throws Exception {
|
||||
when(galleryManageService.selectDownloaderByGid(500, "code")).thenReturn("{}");
|
||||
|
||||
mockMvc.perform(get("/GalleryManage/downloader").param("gid", "500").param("AuthCode", "code"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(galleryManageService).selectDownloaderByGid(500, "code");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteTaskRejectsMissingGid() throws Exception {
|
||||
mockMvc.perform(delete("/GalleryManage").param("AuthCode", "code"))
|
||||
|
||||
@@ -94,7 +94,20 @@ class PublicControllerTest {
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\\\"userId\\\": 7")))
|
||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\\\"username\\\": \\\"alice\\\"")))
|
||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\\\"isAvailable\\\": true")));
|
||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\\\"isAvailable\\\": true")))
|
||||
// 普通用户 isAdmin=false,前端据此隐藏下载人信息。
|
||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\\\"isAdmin\\\": false")));
|
||||
}
|
||||
|
||||
/** 管理员(id=3)必须带上 isAdmin=true,前端据此显示下载人信息与筛选。 */
|
||||
@Test
|
||||
void validateMarksAdminAccount() throws Exception {
|
||||
when(publicService.getUserId("admin")).thenReturn(new User(3, "admin", "狮子", null, true));
|
||||
when(remoteService.isDead()).thenReturn(false);
|
||||
|
||||
mockMvc.perform(post("/validate").param("AuthCode", "admin"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\\\"isAdmin\\\": true")));
|
||||
}
|
||||
|
||||
/** 存储节点掉线时 isAvailable 必须为 false,前端据此提示。 */
|
||||
|
||||
@@ -116,6 +116,89 @@ class GalleryQueryTest {
|
||||
assertTrue(ok(service.selectAllGallery(7)));
|
||||
}
|
||||
|
||||
// ---------- 下载人昵称与筛选(仅管理员) ----------
|
||||
|
||||
/** 管理员查询时每条任务都要带上下载人昵称,前端详情直接显示。 */
|
||||
@Test
|
||||
void selectAllGalleryFillsDownloaderNameForAdmin() {
|
||||
Gallery[] all = {gallery(1, "A", "下载完成"), gallery(2, "B", "下载完成")};
|
||||
all[0].setDownloader(24);
|
||||
all[1].setDownloader(26);
|
||||
when(galleries.selectAllGallery()).thenReturn(all);
|
||||
when(collectMapper.selectGidByCollector(3)).thenReturn(new ArrayList<>());
|
||||
when(users.selectAllUser()).thenReturn(new User[]{
|
||||
user(3, "狮子"), user(24, "bot叔叔"), user(26, "贱笑")});
|
||||
|
||||
String json = service.selectAllGallery(3);
|
||||
|
||||
assertTrue(ok(json), "实际输出: " + json);
|
||||
assertEquals("bot叔叔", all[0].getDownloaderName());
|
||||
assertEquals("贱笑", all[1].getDownloaderName());
|
||||
}
|
||||
|
||||
/** 普通用户不得拿到任何下载人昵称,避免泄露他人身份。 */
|
||||
@Test
|
||||
void selectAllGalleryOmitsDownloaderNameForRegularUser() {
|
||||
Gallery[] all = {gallery(1, "A", "下载完成")};
|
||||
all[0].setDownloader(24);
|
||||
when(galleries.selectAllGallery()).thenReturn(all);
|
||||
when(collectMapper.selectGidByCollector(7)).thenReturn(new ArrayList<>());
|
||||
|
||||
String json = service.selectAllGallery(7);
|
||||
|
||||
assertTrue(ok(json));
|
||||
assertNull(all[0].getDownloaderName(), "普通用户不应填充下载人昵称");
|
||||
assertFalse(json.contains("downloaderName"), "响应体不应出现 downloaderName: " + json);
|
||||
}
|
||||
|
||||
private static User user(int id, String username) {
|
||||
User u = new User();
|
||||
u.setId(id);
|
||||
u.setUsername(username);
|
||||
return u;
|
||||
}
|
||||
|
||||
// ---------- selectDownloaderByGid(管理员专用) ----------
|
||||
|
||||
/** 管理员按 gid 查到实际下载人昵称。 */
|
||||
@Test
|
||||
void selectDownloaderByGidResolvesNameForAdmin() {
|
||||
Gallery g = gallery(500, "A", "下载完成");
|
||||
g.setDownloader(24);
|
||||
when(users.selectUserByAuthCode("admin")).thenReturn(user(3, "狮子"));
|
||||
when(galleries.selectGalleryByGid(500)).thenReturn(g);
|
||||
when(users.selectUserById(24)).thenReturn(user(24, "bot叔叔"));
|
||||
|
||||
String json = service.selectDownloaderByGid(500, "admin");
|
||||
|
||||
assertTrue(ok(json), "实际输出: " + json);
|
||||
assertTrue(json.contains("bot叔叔"), "实际输出: " + json);
|
||||
}
|
||||
|
||||
/** 普通用户查下载人必须被拒,不得泄露他人身份。 */
|
||||
@Test
|
||||
void selectDownloaderByGidRejectsRegularUser() {
|
||||
when(users.selectUserByAuthCode("code")).thenReturn(user(7, "tester"));
|
||||
|
||||
String json = service.selectDownloaderByGid(500, "code");
|
||||
|
||||
assertFalse(ok(json));
|
||||
assertTrue(json.contains("无权"), "实际输出: " + json);
|
||||
verify(galleries, never()).selectGalleryByGid(anyInt());
|
||||
}
|
||||
|
||||
/** 任务不存在时回业务失败而不是 NPE。 */
|
||||
@Test
|
||||
void selectDownloaderByGidReportsMissingTask() {
|
||||
when(users.selectUserByAuthCode("admin")).thenReturn(user(3, "狮子"));
|
||||
when(galleries.selectGalleryByGid(404)).thenReturn(null);
|
||||
|
||||
String json = service.selectDownloaderByGid(404, "admin");
|
||||
|
||||
assertFalse(ok(json));
|
||||
assertTrue(json.contains("任务不存在"), "实际输出: " + json);
|
||||
}
|
||||
|
||||
// ---------- selectTaskByLink / ByGid ----------
|
||||
|
||||
/** 库里已有该任务时直接返回,不再去外部站点解析。 */
|
||||
|
||||
Reference in New Issue
Block a user