You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
4.9 KiB
104 lines
4.9 KiB
package com.mydreamjob.auth.company;
|
|
|
|
import com.mydreamjob.audit.AuditContext;
|
|
import com.mydreamjob.audit.AuditService;
|
|
import com.mydreamjob.auth.AuthService;
|
|
import com.mydreamjob.auth.AuthSessionService;
|
|
import com.mydreamjob.auth.User;
|
|
import com.mydreamjob.auth.UserRepository;
|
|
import com.mydreamjob.auth.SmsVerificationService;
|
|
import com.mydreamjob.common.exception.BusinessException;
|
|
import com.mydreamjob.common.exception.ErrorCode;
|
|
import com.mydreamjob.company.Company;
|
|
import com.mydreamjob.company.CompanyRepository;
|
|
import com.mydreamjob.deletion.AccountDeletionPhoneHasher;
|
|
import com.mydreamjob.deletion.AccountDeletionRepository;
|
|
import com.mydreamjob.auth.password.PasswordPolicy;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.dao.DataIntegrityViolationException;
|
|
import org.springframework.dao.DataAccessException;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.time.Clock;
|
|
import java.time.Instant;
|
|
import java.time.LocalDateTime;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class CompanyRegistrationService {
|
|
private static final String PURPOSE = "company-register";
|
|
|
|
private final CompanyRegistrationProperties properties;
|
|
private final SmsVerificationService smsVerificationService;
|
|
private final UserRepository userRepository;
|
|
private final CompanyRepository companyRepository;
|
|
private final PasswordPolicy passwordPolicy;
|
|
private final PasswordEncoder passwordEncoder;
|
|
private final AccountDeletionRepository accountDeletionRepository;
|
|
private final AccountDeletionPhoneHasher accountDeletionPhoneHasher;
|
|
private final AuthSessionService authSessionService;
|
|
private final AuditService auditService;
|
|
private final Clock clock;
|
|
|
|
@Transactional
|
|
public CompanyRegistrationResponse register(CompanyRegistrationRequest request, AuditContext ctx) {
|
|
if (!properties.isEnabled()) {
|
|
throw new BusinessException(ErrorCode.COMPANY_REGISTRATION_DISABLED);
|
|
}
|
|
String phone = request.getPhone().trim();
|
|
try {
|
|
smsVerificationService.verifyCode(phone, request.getCode(), PURPOSE);
|
|
String phoneHash = accountDeletionPhoneHasher.hash(phone);
|
|
if (accountDeletionRepository.findByDeletedPhoneHash(phoneHash).isPresent()) {
|
|
throw new BusinessException(ErrorCode.COMPANY_REGISTRATION_CONFLICT);
|
|
}
|
|
passwordPolicy.validateNewPassword(request.getPassword(), phone, null, passwordEncoder);
|
|
|
|
if (userRepository.findByPhoneForUpdate(phone).isPresent()) {
|
|
throw new BusinessException(ErrorCode.COMPANY_REGISTRATION_CONFLICT);
|
|
}
|
|
|
|
User user = User.builder()
|
|
.phone(phone)
|
|
.nickname("企业_" + phone.substring(7))
|
|
.passwordHash(passwordEncoder.encode(passwordPolicy.normalize(request.getPassword())))
|
|
.passwordChangedAt(LocalDateTime.ofInstant(clock.instant(), AuthSessionService.BUSINESS_ZONE))
|
|
.role(User.Role.COMPANY)
|
|
.roles(Set.of(User.Role.COMPANY))
|
|
.active(true)
|
|
.verified(false)
|
|
.build();
|
|
user = userRepository.saveAndFlush(user);
|
|
|
|
CompanyRegistrationRequest.CompanyDetails d = request.getCompany();
|
|
Company company = Company.builder()
|
|
.ownerUserId(user.getId())
|
|
.name(d.getName())
|
|
.logoUrl(d.getLogoUrl())
|
|
.description(d.getDescription())
|
|
.industry(d.getIndustry())
|
|
.website(d.getWebsite())
|
|
.address(d.getAddress())
|
|
.verified(false)
|
|
.build();
|
|
company = companyRepository.saveAndFlush(company);
|
|
|
|
Instant now = clock.instant();
|
|
AuthSessionService.SessionTokens tokens = authSessionService.createSession(user, now, ctx);
|
|
auditService.logRequired(user.getId(), "COMPANY_REGISTERED", "COMPANY", company.getId(),
|
|
"{\"result\":\"SUCCESS\"}", ctx,
|
|
LocalDateTime.ofInstant(now, AuthSessionService.BUSINESS_ZONE));
|
|
return new CompanyRegistrationResponse(user.getId(), company.getId(), User.Role.COMPANY.name(),
|
|
"UNVERIFIED", tokens.accessToken(), tokens.refreshToken(), AuthService.EXPIRES_IN_SECONDS);
|
|
} catch (DataIntegrityViolationException e) {
|
|
throw new BusinessException(ErrorCode.COMPANY_REGISTRATION_CONFLICT);
|
|
} catch (DataAccessException e) {
|
|
// 数据库、Redis 或会话持久化故障统一失败关闭,不把 SQL/连接信息返回给客户端。
|
|
throw new BusinessException(ErrorCode.COMPANY_REGISTRATION_DEPENDENCY_UNAVAILABLE);
|
|
}
|
|
}
|
|
}
|
|
|