feat(backend): Improve authorization governance and video interactions
This commit is contained in:
+2
-1
@@ -33,12 +33,13 @@ public class AdminUserController {
|
||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||
@RequestParam(value = "size", defaultValue = "10") Integer size,
|
||||
@RequestParam(value = "keyword", required = false) String keyword,
|
||||
@RequestParam(value = "status", required = false) Integer status,
|
||||
HttpServletRequest request) {
|
||||
if (!isInternalRequest(request)) {
|
||||
return Result.error("非法的内部调用");
|
||||
}
|
||||
Page<UserInfo> pageParam = new Page<>(page, size);
|
||||
return userInfoService.getAdminUserList(pageParam, keyword);
|
||||
return userInfoService.getAdminUserList(pageParam, keyword, status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+28
@@ -172,6 +172,34 @@ public class UserProfileController {
|
||||
return userInfoService.increaseFavoriteCount(userId, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加用户硬币余额
|
||||
*/
|
||||
@PostMapping("/count/coin/increase/{userId}/{count}")
|
||||
public Result<Void> increaseCoinCount(
|
||||
@PathVariable Long userId,
|
||||
@PathVariable Integer count,
|
||||
HttpServletRequest request) {
|
||||
if (!isInternalRequest(request)) {
|
||||
return Result.error("非法的内部调用");
|
||||
}
|
||||
return userInfoService.increaseCoinCount(userId, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扣减用户硬币余额
|
||||
*/
|
||||
@PostMapping("/count/coin/decrease/{userId}/{count}")
|
||||
public Result<Void> decreaseCoinCount(
|
||||
@PathVariable Long userId,
|
||||
@PathVariable Integer count,
|
||||
HttpServletRequest request) {
|
||||
if (!isInternalRequest(request)) {
|
||||
return Result.error("非法的内部调用");
|
||||
}
|
||||
return userInfoService.decreaseCoinCount(userId, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求中获取用户名
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.nuaa.video.common.model.vo.Result;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 认证服务Feign客户端
|
||||
*/
|
||||
@@ -44,4 +46,11 @@ public interface AuthFeignClient {
|
||||
@PathVariable Long userId,
|
||||
@RequestParam String newPassword,
|
||||
@RequestHeader("X-Internal-Token") String internalToken);
|
||||
|
||||
/**
|
||||
* 按账号状态查询用户ID - 管理接口
|
||||
*/
|
||||
@GetMapping("/admin/user-ids/status/{status}")
|
||||
Result<List<Long>> getUserIdsByStatus(@PathVariable Integer status,
|
||||
@RequestHeader("X-Internal-Token") String internalToken);
|
||||
}
|
||||
|
||||
@@ -43,4 +43,14 @@ public interface UserInfoMapper extends BaseMapper<UserInfo> {
|
||||
* 增加收藏数
|
||||
*/
|
||||
int increaseFavoriteCount(@Param("userId") Long userId, @Param("count") int count);
|
||||
|
||||
/**
|
||||
* 增加硬币余额
|
||||
*/
|
||||
int increaseCoinCount(@Param("userId") Long userId, @Param("count") int count);
|
||||
|
||||
/**
|
||||
* 扣减硬币余额
|
||||
*/
|
||||
int decreaseCoinCount(@Param("userId") Long userId, @Param("count") int count);
|
||||
}
|
||||
|
||||
@@ -93,10 +93,20 @@ public interface UserInfoService extends IService<UserInfo> {
|
||||
*/
|
||||
Result<Void> increaseFavoriteCount(Long userId, Integer count);
|
||||
|
||||
/**
|
||||
* 增加用户硬币余额
|
||||
*/
|
||||
Result<Void> increaseCoinCount(Long userId, Integer count);
|
||||
|
||||
/**
|
||||
* 扣减用户硬币余额
|
||||
*/
|
||||
Result<Void> decreaseCoinCount(Long userId, Integer count);
|
||||
|
||||
/**
|
||||
* 获取用户列表 - 管理接口
|
||||
*/
|
||||
Result<Page<UserProfileVO>> getAdminUserList(Page<UserInfo> page, String keyword);
|
||||
Result<Page<UserProfileVO>> getAdminUserList(Page<UserInfo> page, String keyword, Integer status);
|
||||
|
||||
/**
|
||||
* 获取用户详情 - 管理接口
|
||||
|
||||
+78
-7
@@ -27,6 +27,8 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -41,9 +43,15 @@ import java.util.stream.Collectors;
|
||||
@RequiredArgsConstructor
|
||||
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
|
||||
|
||||
private static final ZoneId APP_ZONE_ID = ZoneId.of("Asia/Shanghai");
|
||||
private static final long DEFAULT_AVATAR_MAX_SIZE_BYTES = 5L * 1024 * 1024;
|
||||
|
||||
@Value("${service.auth.token}")
|
||||
private String internalServiceToken;
|
||||
|
||||
@Value("${user.avatar.max-size-bytes:" + DEFAULT_AVATAR_MAX_SIZE_BYTES + "}")
|
||||
private long avatarMaxSizeBytes;
|
||||
|
||||
private final UserInfoMapper userInfoMapper;
|
||||
private final UserFollowMapper userFollowMapper;
|
||||
private final UserSettingService userSettingService;
|
||||
@@ -118,6 +126,19 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
|
||||
return Result.error(ResultCode.USER_NOT_FOUND.getCode(),ResultCode.USER_NOT_FOUND.getMessage());
|
||||
}
|
||||
|
||||
if (file == null || file.isEmpty()) {
|
||||
return Result.error("请选择头像文件");
|
||||
}
|
||||
|
||||
String contentType = file.getContentType();
|
||||
if (!StringUtils.hasText(contentType) || !contentType.startsWith("image/")) {
|
||||
return Result.error("仅支持上传图片格式头像");
|
||||
}
|
||||
|
||||
if (file.getSize() > avatarMaxSizeBytes) {
|
||||
return Result.error("头像文件不能超过5MB");
|
||||
}
|
||||
|
||||
// 上传头像
|
||||
String avatarUrl = minioUtils.uploadImage(file);
|
||||
|
||||
@@ -127,8 +148,8 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
|
||||
userInfo.setUpdateTime(LocalDateTime.now());
|
||||
updateById(userInfo);
|
||||
|
||||
// 返回头像URL
|
||||
return Result.success(minioUtils.getPreSignedUrl(avatarUrl));
|
||||
// 返回对象路径,由前端统一拼接可访问的媒体地址
|
||||
return Result.success(avatarUrl);
|
||||
} catch (Exception e) {
|
||||
log.error("上传头像失败", e);
|
||||
return Result.error("上传头像失败: " + e.getMessage());
|
||||
@@ -154,7 +175,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
|
||||
userInfo.setFollowingCount(0);
|
||||
userInfo.setVideoCount(0);
|
||||
userInfo.setLikeCount(0);
|
||||
userInfo.setCoinCount(0);
|
||||
userInfo.setCoinCount(20);
|
||||
userInfo.setFavoriteCount(0);
|
||||
userInfo.setViewCount(0L);
|
||||
userInfo.setLevel(1);
|
||||
@@ -247,14 +268,64 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Page<UserProfileVO>> getAdminUserList(Page<UserInfo> page, String keyword) {
|
||||
public Result<Void> increaseCoinCount(Long userId, Integer count) {
|
||||
if (count == null || count <= 0) {
|
||||
return Result.error("硬币数量无效");
|
||||
}
|
||||
|
||||
UserInfo userInfo = getById(userId);
|
||||
if (userInfo == null) {
|
||||
return Result.error(ResultCode.USER_NOT_FOUND.getCode(), ResultCode.USER_NOT_FOUND.getMessage());
|
||||
}
|
||||
|
||||
userInfoMapper.increaseCoinCount(userId, count);
|
||||
updateUserStatDailyAsync(userId, "coin", count);
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Void> decreaseCoinCount(Long userId, Integer count) {
|
||||
if (count == null || count <= 0) {
|
||||
return Result.error("硬币数量无效");
|
||||
}
|
||||
|
||||
UserInfo userInfo = getById(userId);
|
||||
if (userInfo == null) {
|
||||
return Result.error(ResultCode.USER_NOT_FOUND.getCode(), ResultCode.USER_NOT_FOUND.getMessage());
|
||||
}
|
||||
|
||||
int affectedRows = userInfoMapper.decreaseCoinCount(userId, count);
|
||||
if (affectedRows <= 0) {
|
||||
return Result.error("硬币余额不足");
|
||||
}
|
||||
|
||||
updateUserStatDailyAsync(userId, "coin", -count);
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Page<UserProfileVO>> getAdminUserList(Page<UserInfo> page, String keyword, Integer status) {
|
||||
LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
// 添加关键词搜索条件
|
||||
if (StringUtils.hasText(keyword)) {
|
||||
queryWrapper.like(UserInfo::getNickname, keyword)
|
||||
queryWrapper.and(wrapper -> wrapper
|
||||
.like(UserInfo::getNickname, keyword)
|
||||
.or()
|
||||
.like(UserInfo::getSignature, keyword);
|
||||
.like(UserInfo::getSignature, keyword));
|
||||
}
|
||||
|
||||
if (status != null) {
|
||||
Result<List<Long>> userIdsResult = authFeignClient.getUserIdsByStatus(status, internalServiceToken);
|
||||
List<Long> userIds = userIdsResult.getData() == null ? Collections.emptyList() : userIdsResult.getData();
|
||||
if (userIds.isEmpty()) {
|
||||
Page<UserProfileVO> emptyPage = new Page<>(page.getCurrent(), page.getSize(), 0);
|
||||
emptyPage.setRecords(Collections.emptyList());
|
||||
return Result.success(emptyPage);
|
||||
}
|
||||
queryWrapper.in(UserInfo::getId, userIds);
|
||||
}
|
||||
|
||||
// 按创建时间降序排序
|
||||
@@ -346,7 +417,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
|
||||
stats.put("totalUsers", totalUsers);
|
||||
|
||||
// 今日新增用户
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate today = LocalDate.now(APP_ZONE_ID);
|
||||
long todayNewUsers = count(new LambdaQueryWrapper<UserInfo>()
|
||||
.ge(UserInfo::getCreateTime, today.atStartOfDay()));
|
||||
stats.put("todayNewUsers", todayNewUsers);
|
||||
|
||||
@@ -68,6 +68,11 @@ public class UserProfileVO implements Serializable {
|
||||
*/
|
||||
private Integer likeCount;
|
||||
|
||||
/**
|
||||
* 硬币余额
|
||||
*/
|
||||
private Integer coinCount;
|
||||
|
||||
/**
|
||||
* 等级
|
||||
*/
|
||||
@@ -92,4 +97,4 @@ public class UserProfileVO implements Serializable {
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,4 +37,19 @@
|
||||
WHERE id = #{userId}
|
||||
</update>
|
||||
|
||||
<update id="increaseCoinCount">
|
||||
UPDATE user_info
|
||||
SET coin_count = GREATEST(coin_count + #{count}, 0),
|
||||
update_time = NOW()
|
||||
WHERE id = #{userId}
|
||||
</update>
|
||||
|
||||
<update id="decreaseCoinCount">
|
||||
UPDATE user_info
|
||||
SET coin_count = coin_count - #{count},
|
||||
update_time = NOW()
|
||||
WHERE id = #{userId}
|
||||
AND coin_count >= #{count}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user