Add user account management methods and update user-related mappers

This commit is contained in:
zyh
2025-08-24 17:06:52 +08:00
parent bc1f10381a
commit 4cfd19195f
15 changed files with 430 additions and 3 deletions

View File

@@ -41,5 +41,14 @@ public class UserService {
return Mono.fromCallable(() -> userMapper.deleteById(id) > 0)
.subscribeOn(Schedulers.boundedElastic());
}
}
public Mono<User> update(Long id, User user) {
return Mono.fromCallable(() -> {
user.setId(id);
int n = userMapper.update(user);
return n;
})
.subscribeOn(Schedulers.boundedElastic())
.flatMap(n -> n > 0 ? getById(id) : Mono.empty());
}
}

View File

@@ -0,0 +1,131 @@
package com.gameplatform.server.service.account;
import com.gameplatform.server.mapper.account.UserAccountMapper;
import com.gameplatform.server.model.dto.account.AccountCreateRequest;
import com.gameplatform.server.model.dto.account.AccountResponse;
import com.gameplatform.server.model.dto.account.AccountUpdateRequest;
import com.gameplatform.server.model.dto.common.PageResult;
import com.gameplatform.server.model.entity.account.UserAccount;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class AccountService {
private final UserAccountMapper mapper;
private final PasswordEncoder passwordEncoder;
public AccountService(UserAccountMapper mapper, PasswordEncoder passwordEncoder) {
this.mapper = mapper;
this.passwordEncoder = passwordEncoder;
}
public Mono<PageResult<AccountResponse>> list(String userType, String status, String role, String keyword,
Integer page, Integer size) {
int p = (page == null || page < 1) ? 1 : page;
int s = (size == null || size < 1 || size > 200) ? 20 : size;
int offset = (p - 1) * s;
return Mono.fromCallable(() -> {
long total = mapper.countByFilter(userType, status, role, keyword);
List<UserAccount> list = mapper.listByFilter(userType, status, role, keyword, s, offset);
List<AccountResponse> items = list.stream().map(this::toResp).collect(Collectors.toList());
return new PageResult<>(items, total, p, s);
})
.subscribeOn(Schedulers.boundedElastic());
}
@Transactional
public Mono<AccountResponse> create(AccountCreateRequest req) {
return Mono.fromCallable(() -> {
// basic normalize
String type = req.getUserType().toUpperCase();
if (!type.equals("ADMIN") && !type.equals("AGENT")) {
throw new IllegalArgumentException("userType 只能是 ADMIN 或 AGENT");
}
if (mapper.findByUsername(req.getUsername()) != null) {
throw new IllegalArgumentException("用户名已存在");
}
UserAccount acc = new UserAccount();
acc.setUserType(type);
acc.setUsername(req.getUsername());
acc.setDisplayName(req.getDisplayName());
acc.setStatus(req.getStatus() == null ? "ENABLED" : req.getStatus());
if ("ADMIN".equals(type)) {
acc.setRole(req.getRole() == null ? "ADMIN" : req.getRole());
acc.setPointsBalance(0L);
} else {
acc.setRole(null);
acc.setPointsBalance(req.getPointsBalance() == null ? 0L : req.getPointsBalance());
}
acc.setPasswordHash(passwordEncoder.encode(req.getInitialPassword()));
mapper.insert(acc);
return toResp(acc);
})
.subscribeOn(Schedulers.boundedElastic());
}
public Mono<AccountResponse> get(Long id) {
return Mono.fromCallable(() -> mapper.findById(id))
.subscribeOn(Schedulers.boundedElastic())
.map(this::toResp);
}
@Transactional
public Mono<AccountResponse> update(Long id, AccountUpdateRequest req) {
return Mono.fromCallable(() -> {
UserAccount db = mapper.findById(id);
if (db == null) return null;
UserAccount patch = new UserAccount();
patch.setId(id);
patch.setDisplayName(req.getDisplayName());
// Only ADMIN account may set role; AGENT's role must remain null
if ("ADMIN".equalsIgnoreCase(db.getUserType())) {
patch.setRole(req.getRole());
}
patch.setStatus(req.getStatus());
mapper.update(patch);
return mapper.findById(id);
})
.subscribeOn(Schedulers.boundedElastic())
.map(this::toResp);
}
@Transactional
public Mono<Boolean> setStatus(Long id, String status) {
return Mono.fromCallable(() -> mapper.setStatus(id, status) > 0)
.subscribeOn(Schedulers.boundedElastic());
}
@Transactional
public Mono<Void> resetPassword(Long id, String newPassword, boolean forceLogout) {
return Mono.fromRunnable(() -> {
String hash = passwordEncoder.encode(newPassword);
mapper.updatePassword(id, hash);
// TODO: forceLogout 可结合 token 版本/黑名单实现(后续扩展)
})
.subscribeOn(Schedulers.boundedElastic())
.then();
}
private AccountResponse toResp(UserAccount a) {
if (a == null) return null;
AccountResponse r = new AccountResponse();
r.setId(a.getId());
r.setUserType(a.getUserType());
r.setUsername(a.getUsername());
r.setDisplayName(a.getDisplayName());
r.setRole(a.getRole());
r.setStatus(a.getStatus());
r.setPointsBalance(a.getPointsBalance());
r.setCreatedAt(a.getCreatedAt());
r.setUpdatedAt(a.getUpdatedAt());
return r;
}
}