expandAdminFunction
Change-Id: If3b875b3017d1922b15150dd735ca2ce5a3a77f0
diff --git a/src/main/java/com/example/g8backend/controller/AdminController.java b/src/main/java/com/example/g8backend/controller/AdminController.java
index 394e445..a4193cb 100644
--- a/src/main/java/com/example/g8backend/controller/AdminController.java
+++ b/src/main/java/com/example/g8backend/controller/AdminController.java
@@ -1,10 +1,13 @@
package com.example.g8backend.controller;
import com.example.g8backend.dto.ApiResponse;
+import com.example.g8backend.entity.Post;
import com.example.g8backend.entity.Report;
import com.example.g8backend.service.AdminService;
+import com.example.g8backend.service.IPostService;
import com.example.g8backend.service.IReportService;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
@@ -17,6 +20,8 @@
@Autowired
private AdminService adminService;
private IReportService reportService;
+ @Autowired
+ private IPostService postService;
@PostMapping("/grant-vip/{userId}")
@PreAuthorize("hasRole('ADMIN')") // 仅允许管理员访问
public String grantVip(@PathVariable Long userId) {
@@ -43,4 +48,68 @@
return ApiResponse.success("举报处理完成");
}
+
+ // 封禁用户
+ @PostMapping("/users/{userId}/ban")
+ @PreAuthorize("hasRole('ADMIN')")
+ public ApiResponse<String> banUser(
+ @PathVariable Long userId,
+ @RequestParam String reason) {
+ Long adminId = getCurrentAdminId();
+ boolean success = adminService.banUser(userId, reason, adminId);
+ return success ?
+ ApiResponse.success("用户封禁成功") :
+ ApiResponse.error(400, "操作失败");
+ }
+
+ // 解封用户
+ @PostMapping("/users/{userId}/unban")
+ @PreAuthorize("hasRole('ADMIN')")
+ public ApiResponse<String> unbanUser(@PathVariable Long userId) {
+ Long adminId = getCurrentAdminId();
+ boolean success = adminService.unbanUser(userId, adminId);
+ return success ?
+ ApiResponse.success("用户解封成功") :
+ ApiResponse.error(400, "操作失败");
+ }
+
+ // 锁定帖子
+ @PostMapping("/posts/{postId}/lock")
+ @PreAuthorize("hasRole('ADMIN')")
+ public ApiResponse<String> lockPost(
+ @PathVariable Long postId,
+ @RequestParam String reason) {
+ Long adminId = getCurrentAdminId();
+ boolean success = adminService.lockPost(postId, reason, adminId);
+ return success ?
+ ApiResponse.success("帖子已锁定") :
+ ApiResponse.error(400, "操作失败");
+ }
+
+ // 解锁帖子
+ @PostMapping("/posts/{postId}/unlock")
+ @PreAuthorize("hasRole('ADMIN')")
+ public ApiResponse<String> unlockPost(@PathVariable Long postId) {
+ Long adminId = getCurrentAdminId();
+ boolean success = adminService.unlockPost(postId, adminId);
+ return success ?
+ ApiResponse.success("帖子已解锁") :
+ ApiResponse.error(400, "操作失败");
+ }
+ @DeleteMapping("/{postId}")
+ public ResponseEntity<ApiResponse<String>> deletePost(@PathVariable Long postId) {
+ long userId = (long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+ Post post = postService.getById(postId);
+ if (post == null) {
+ return ResponseEntity.status(404).body(ApiResponse.error(404, "Post not found."));
+ }
+ postService.removeById(postId);
+ return ResponseEntity.ok(ApiResponse.message("Post deleted successfully."));
+ }
+
+ private Long getCurrentAdminId() {
+ return (Long) SecurityContextHolder.getContext()
+ .getAuthentication().getPrincipal();
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/controller/AuthController.java b/src/main/java/com/example/g8backend/controller/AuthController.java
index 538d433..48376f2 100644
--- a/src/main/java/com/example/g8backend/controller/AuthController.java
+++ b/src/main/java/com/example/g8backend/controller/AuthController.java
@@ -94,6 +94,10 @@
return ApiResponse.error(400, "用户名或密码错误");
}
+ if (existingUser.getIsBanned()) {
+ return ApiResponse.error(403, "账号已被封禁,请联系管理员");
+ }
+
String token = jwtUtil.generateToken(existingUser.getUserId());
Map<String, String> response = new HashMap<>();
response.put("token", token);
diff --git a/src/main/java/com/example/g8backend/controller/PostController.java b/src/main/java/com/example/g8backend/controller/PostController.java
index 6800666..41be09a 100644
--- a/src/main/java/com/example/g8backend/controller/PostController.java
+++ b/src/main/java/com/example/g8backend/controller/PostController.java
@@ -51,26 +51,12 @@
@GetMapping("/{postId}")
public ResponseEntity<ApiResponse<Post>> getPost(@PathVariable Long postId) {
+ Post post = postService.getById(postId);
long userId = (long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
postService.recordViewHistory(userId, postId);
- Post post = postService.getById(postId);
return ResponseEntity.ok(ApiResponse.success(post));
}
- @DeleteMapping("/{postId}")
- public ResponseEntity<ApiResponse<String>> deletePost(@PathVariable Long postId) {
- long userId = (long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- Post post = postService.getById(postId);
- if (post == null) {
- return ResponseEntity.status(404).body(ApiResponse.error(404, "Post not found."));
- }
- if (post.getUserId() != userId) {
- return ResponseEntity.status(403).body(ApiResponse.error(403, "You are not authorized to delete this post."));
- }
- postService.removeById(postId);
- return ResponseEntity.ok(ApiResponse.message("Post deleted successfully."));
- }
-
@GetMapping("/getAll")
public ResponseEntity<ApiResponse<List<Post>>> getAllPosts() {
return ResponseEntity.ok(ApiResponse.success(postService.list()));
@@ -209,4 +195,18 @@
}
}
+ @DeleteMapping("/{postId}")
+ public ResponseEntity<ApiResponse<String>> deletePost(@PathVariable Long postId) {
+ long userId = (long) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+ Post post = postService.getById(postId);
+ if (post == null) {
+ return ResponseEntity.status(404).body(ApiResponse.error(404, "Post not found."));
+ }
+ if (post.getUserId() != userId) {
+ return ResponseEntity.status(403).body(ApiResponse.error(403, "You are not authorized to delete this post."));
+ }
+ postService.removeById(postId);
+ return ResponseEntity.ok(ApiResponse.message("Post deleted successfully."));
+ }
+
}
diff --git a/src/main/java/com/example/g8backend/entity/Post.java b/src/main/java/com/example/g8backend/entity/Post.java
index 351e24d..e0f2a79 100644
--- a/src/main/java/com/example/g8backend/entity/Post.java
+++ b/src/main/java/com/example/g8backend/entity/Post.java
@@ -5,6 +5,9 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
import lombok.Data;
import lombok.experimental.Accessors;
@@ -20,6 +23,18 @@
private String postContent;
private Timestamp createdAt;
private String postType;
+ // 新增锁定相关字段
+ @TableField("is_locked")
+ private Boolean isLocked = false;
+
+ @TableField("locked_reason")
+ private String lockedReason;
+
+ @TableField("locked_at")
+ private LocalDateTime lockedAt;
+
+ @TableField("locked_by")
+ private Long lockedBy;
@TableField("view_count")
private Integer viewCount = 0;
diff --git a/src/main/java/com/example/g8backend/entity/User.java b/src/main/java/com/example/g8backend/entity/User.java
index 0645824..aea6335 100644
--- a/src/main/java/com/example/g8backend/entity/User.java
+++ b/src/main/java/com/example/g8backend/entity/User.java
@@ -1,12 +1,14 @@
package com.example.g8backend.entity;
import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDate;
+import java.time.LocalDateTime;
@Data
@TableName("users")
@@ -23,6 +25,18 @@
private Integer signinCount;
private LocalDate lastSigninDate;
private String role;
+ @TableField("is_banned")
+ private Boolean isBanned = false;
+
+ @TableField("banned_reason")
+ private String bannedReason;
+
+ @TableField("banned_at")
+ private LocalDateTime bannedAt;
+
+ @TableField("banned_by")
+ private Long bannedBy;
+
@Override
public String toString() {
diff --git a/src/main/java/com/example/g8backend/service/AdminService.java b/src/main/java/com/example/g8backend/service/AdminService.java
index 1f84eec..da672f5 100644
--- a/src/main/java/com/example/g8backend/service/AdminService.java
+++ b/src/main/java/com/example/g8backend/service/AdminService.java
@@ -2,4 +2,8 @@
public interface AdminService {
boolean grantVip(Long targetUserId);
+ boolean banUser(Long userId, String reason, Long adminId);
+ boolean unbanUser(Long userId, Long adminId);
+ boolean lockPost(Long postId, String reason, Long adminId);
+ boolean unlockPost(Long postId, Long adminId);
}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/service/impl/AdminServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/AdminServiceImpl.java
index d3be9fe..24434f4 100644
--- a/src/main/java/com/example/g8backend/service/impl/AdminServiceImpl.java
+++ b/src/main/java/com/example/g8backend/service/impl/AdminServiceImpl.java
@@ -1,12 +1,16 @@
package com.example.g8backend.service.impl;
+import com.example.g8backend.entity.Post;
import com.example.g8backend.entity.User;
import com.example.g8backend.mapper.UserMapper;
+import com.example.g8backend.mapper.PostMapper;
import com.example.g8backend.service.AdminService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.time.LocalDateTime;
+
@Service
@RequiredArgsConstructor
public class AdminServiceImpl implements AdminService {
@@ -23,4 +27,62 @@
userMapper.updateById(user);
return true;
}
+
+ private final PostMapper postMapper;
+
+ @Override
+ @Transactional
+ public boolean banUser(Long userId, String reason, Long adminId) {
+ User user = userMapper.selectById(userId);
+ if (user == null) return false;
+
+ user.setIsBanned(true);
+ user.setBannedReason(reason);
+ user.setBannedAt(LocalDateTime.now());
+ user.setBannedBy(adminId);
+
+ return userMapper.updateById(user) > 0;
+ }
+
+ @Override
+ @Transactional
+ public boolean unbanUser(Long userId, Long adminId) {
+ User user = userMapper.selectById(userId);
+ if (user == null) return false;
+
+ user.setIsBanned(false);
+ user.setBannedReason(null);
+ user.setBannedAt(null);
+ user.setBannedBy(null);
+
+ return userMapper.updateById(user) > 0;
+ }
+
+ @Override
+ @Transactional
+ public boolean lockPost(Long postId, String reason, Long adminId) {
+ Post post = postMapper.selectById(postId);
+ if (post == null) return false;
+
+ post.setIsLocked(true);
+ post.setLockedReason(reason);
+ post.setLockedAt(LocalDateTime.now());
+ post.setLockedBy(adminId);
+
+ return postMapper.updateById(post) > 0;
+ }
+
+ @Override
+ @Transactional
+ public boolean unlockPost(Long postId, Long adminId) {
+ Post post = postMapper.selectById(postId);
+ if (post == null) return false;
+
+ post.setIsLocked(false);
+ post.setLockedReason(null);
+ post.setLockedAt(null);
+ post.setLockedBy(null);
+
+ return postMapper.updateById(post) > 0;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java b/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
index 1fda1e2..2a43439 100644
--- a/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
+++ b/src/main/java/com/example/g8backend/service/impl/PostServiceImpl.java
@@ -178,7 +178,6 @@
.orderByDesc("hot_score"); // 确保排序条件正确
return postMapper.selectPage(new Page<>(page, size), queryWrapper);
}
-
@Override
public List<PostHistoryDTO> getViewHistoryWithTitles(Long userId) {
// 1. 查询浏览记录(按时间倒序)
@@ -187,15 +186,12 @@
.eq("user_id", userId)
.orderByDesc("view_time")
);
-
-
// 2. 转换为DTO并填充标题
return history.stream().map(view -> {
PostHistoryDTO dto = new PostHistoryDTO();
dto.setViewId(view.getViewId());
dto.setPostId(view.getPostId());
dto.setViewTime(view.getViewTime());
-
// 3. 查询帖子标题
Post post = postMapper.selectById(view.getPostId());
if (post != null) {
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
index e5faa3f..8a2387c 100644
--- a/src/main/resources/schema.sql
+++ b/src/main/resources/schema.sql
@@ -9,6 +9,10 @@
`signin_count` INT DEFAULT 0,
`last_signin_date` DATE,
`role` ENUM('USER', 'ADMIN') DEFAULT 'USER' COMMENT '用户角色',
+ `is_banned` BOOLEAN DEFAULT FALSE COMMENT '是否被封禁',
+ `banned_reason` VARCHAR(255) COMMENT '封禁原因',
+ `banned_at` DATETIME COMMENT '封禁时间',
+ `banned_by` BIGINT COMMENT '操作管理员ID',
INDEX `idx_user_level` (`user_level`) -- 按等级查询优化
);
-- 用户统计表
@@ -58,6 +62,10 @@
`last_calculated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后热度计算时间',
`average_rating` DECIMAL(3,2) DEFAULT 0.00 COMMENT '帖子平均评分',
`rating_count` INT DEFAULT 0 COMMENT '总评分人数',
+ `is_locked` BOOLEAN DEFAULT FALSE COMMENT '是否被锁定',
+ `locked_reason` VARCHAR(255) COMMENT '锁定原因',
+ `locked_at` DATETIME COMMENT '锁定时间',
+ `locked_by` BIGINT COMMENT '操作管理员ID',
FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`),
FOREIGN KEY (`torrent_id`) REFERENCES `torrents`(`torrent_id`),
INDEX `idx_hot_score` (`hot_score`), -- 新增热度索引