Add user account management methods and update user-related mappers
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user