Merge branch 'feature_devis2' into folder_export2
This commit is contained in:
commit
cf5f4e74a1
@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(name = "/",
|
@RequestMapping(value = "/",
|
||||||
produces = APPLICATION_JSON_VALUE)
|
produces = APPLICATION_JSON_VALUE)
|
||||||
public class IndexRestController {
|
public class IndexRestController {
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||||
@ -121,11 +122,28 @@ public class UserRestController {
|
|||||||
@RequestParam(required = false) UUID companyId) {
|
@RequestParam(required = false) UUID companyId) {
|
||||||
log.info("User list request - page: {}, size: {}, companyId: {}", page, size, companyId);
|
log.info("User list request - page: {}, size: {}, companyId: {}", page, size, companyId);
|
||||||
|
|
||||||
Pageable pageable = PageRequest.of(page, size);
|
List<UserAccount> userAccounts;
|
||||||
|
long totalElements;
|
||||||
|
|
||||||
// TODO: Implement pagination and company filtering in service layer
|
if (companyId != null) {
|
||||||
// For now, return an empty page
|
userAccounts = userService.findUsersByCompany(companyId, page, size);
|
||||||
Page<UserResponse> users = Page.empty(pageable);
|
totalElements = userService.countUsersByCompany(companyId);
|
||||||
|
} else {
|
||||||
|
userAccounts = userService.findAllUsers(page, size);
|
||||||
|
totalElements = userService.countAllUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to UserResponse DTOs
|
||||||
|
List<UserResponse> userResponses = userAccounts.stream()
|
||||||
|
.map(this::mapToUserResponse)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
|
// Create Page object
|
||||||
|
Pageable pageable = PageRequest.of(page, size);
|
||||||
|
Page<UserResponse> users = new org.springframework.data.domain.PageImpl<>(
|
||||||
|
userResponses,
|
||||||
|
pageable,
|
||||||
|
totalElements);
|
||||||
|
|
||||||
return ResponseEntity.ok(users);
|
return ResponseEntity.ok(users);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import com.dh7789dev.xpeditis.dto.request.RegisterRequest;
|
|||||||
import com.dh7789dev.xpeditis.port.in.UserManagementUseCase;
|
import com.dh7789dev.xpeditis.port.in.UserManagementUseCase;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -32,4 +33,12 @@ public interface UserService extends UserManagementUseCase {
|
|||||||
boolean existsByEmail(String email);
|
boolean existsByEmail(String email);
|
||||||
|
|
||||||
boolean existsByUsername(String username);
|
boolean existsByUsername(String username);
|
||||||
|
|
||||||
|
List<UserAccount> findAllUsers(int page, int size);
|
||||||
|
|
||||||
|
List<UserAccount> findUsersByCompany(UUID companyId, int page, int size);
|
||||||
|
|
||||||
|
long countAllUsers();
|
||||||
|
|
||||||
|
long countUsersByCompany(UUID companyId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,4 +85,24 @@ public class UserServiceImpl implements UserService {
|
|||||||
public boolean existsByUsername(String username) {
|
public boolean existsByUsername(String username) {
|
||||||
return userRepository.existsByUsername(username);
|
return userRepository.existsByUsername(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.util.List<UserAccount> findAllUsers(int page, int size) {
|
||||||
|
return userRepository.findAllUsers(page, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.util.List<UserAccount> findUsersByCompany(UUID companyId, int page, int size) {
|
||||||
|
return userRepository.findUsersByCompany(companyId, page, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countAllUsers() {
|
||||||
|
return userRepository.countAllUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countUsersByCompany(UUID companyId) {
|
||||||
|
return userRepository.countUsersByCompany(companyId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,4 +31,12 @@ public interface UserRepository {
|
|||||||
void deactivateUser(UUID id);
|
void deactivateUser(UUID id);
|
||||||
|
|
||||||
List<UserAccount> findByCompanyIdAndIsActive(UUID companyId, boolean isActive);
|
List<UserAccount> findByCompanyIdAndIsActive(UUID companyId, boolean isActive);
|
||||||
|
|
||||||
|
List<UserAccount> findAllUsers(int page, int size);
|
||||||
|
|
||||||
|
List<UserAccount> findUsersByCompany(UUID companyId, int page, int size);
|
||||||
|
|
||||||
|
long countAllUsers();
|
||||||
|
|
||||||
|
long countUsersByCompany(UUID companyId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.dh7789dev.xpeditis.repository;
|
||||||
|
|
||||||
|
import com.dh7789dev.xpeditis.CompanyRepository;
|
||||||
|
import com.dh7789dev.xpeditis.dao.CompanyDao;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.Company;
|
||||||
|
import com.dh7789dev.xpeditis.entity.CompanyEntity;
|
||||||
|
import com.dh7789dev.xpeditis.mapper.CompanyMapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CompanyJpaRepository implements CompanyRepository {
|
||||||
|
|
||||||
|
private final CompanyDao companyDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Company save(Company company) {
|
||||||
|
CompanyEntity entity = CompanyMapper.companyToCompanyEntity(company);
|
||||||
|
CompanyEntity savedEntity = companyDao.save(entity);
|
||||||
|
log.info("Company saved with ID: {}", savedEntity.getId());
|
||||||
|
return CompanyMapper.companyEntityToCompany(savedEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Company> findById(UUID id) {
|
||||||
|
return companyDao.findById(id)
|
||||||
|
.map(CompanyMapper::companyEntityToCompany);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Company> findByName(String name) {
|
||||||
|
return companyDao.findByName(name)
|
||||||
|
.map(CompanyMapper::companyEntityToCompany);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Company> findAll() {
|
||||||
|
return companyDao.findAll().stream()
|
||||||
|
.map(CompanyMapper::companyEntityToCompany)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean existsByName(String name) {
|
||||||
|
return companyDao.existsByName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteById(UUID id) {
|
||||||
|
companyDao.deleteById(id);
|
||||||
|
log.info("Company deleted with ID: {}", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
package com.dh7789dev.xpeditis.repository;
|
||||||
|
|
||||||
|
import com.dh7789dev.xpeditis.OAuth2Provider;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.GoogleUserInfo;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class GoogleOAuth2Provider implements OAuth2Provider {
|
||||||
|
|
||||||
|
@Value("${application.oauth2.google.user-info-uri:https://www.googleapis.com/oauth2/v2/userinfo}")
|
||||||
|
private String userInfoUri;
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
|
||||||
|
public GoogleOAuth2Provider() {
|
||||||
|
this.restTemplate = new RestTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateToken(String accessToken) {
|
||||||
|
try {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setBearerAuth(accessToken);
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
|
|
||||||
|
ResponseEntity<GoogleUserInfo> response = restTemplate.exchange(
|
||||||
|
userInfoUri,
|
||||||
|
HttpMethod.GET,
|
||||||
|
entity,
|
||||||
|
GoogleUserInfo.class
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.getStatusCode() == HttpStatus.OK;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error validating Google token", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<GoogleUserInfo> getUserInfo(String accessToken) {
|
||||||
|
try {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setBearerAuth(accessToken);
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||||
|
|
||||||
|
ResponseEntity<GoogleUserInfo> response = restTemplate.exchange(
|
||||||
|
userInfoUri,
|
||||||
|
HttpMethod.GET,
|
||||||
|
entity,
|
||||||
|
GoogleUserInfo.class
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||||
|
log.info("Successfully retrieved Google user info for email: {}", response.getBody().getEmail());
|
||||||
|
return Optional.of(response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("Failed to retrieve Google user info: status={}", response.getStatusCode());
|
||||||
|
return Optional.empty();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error retrieving Google user info", e);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package com.dh7789dev.xpeditis.repository;
|
||||||
|
|
||||||
|
import com.dh7789dev.xpeditis.LicenseRepository;
|
||||||
|
import com.dh7789dev.xpeditis.dao.LicenseDao;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.License;
|
||||||
|
import com.dh7789dev.xpeditis.entity.LicenseEntity;
|
||||||
|
import com.dh7789dev.xpeditis.mapper.LicenseMapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LicenseJpaRepository implements LicenseRepository {
|
||||||
|
|
||||||
|
private final LicenseDao licenseDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public License save(License license) {
|
||||||
|
LicenseEntity entity = LicenseMapper.licenseToLicenseEntity(license);
|
||||||
|
LicenseEntity savedEntity = licenseDao.save(entity);
|
||||||
|
log.info("License saved with ID: {}", savedEntity.getId());
|
||||||
|
return LicenseMapper.licenseEntityToLicense(savedEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<License> findById(UUID id) {
|
||||||
|
return licenseDao.findById(id)
|
||||||
|
.map(LicenseMapper::licenseEntityToLicense);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<License> findActiveLicenseByCompanyId(UUID companyId) {
|
||||||
|
return licenseDao.findActiveLicenseByCompanyId(companyId)
|
||||||
|
.map(LicenseMapper::licenseEntityToLicense);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<License> findByCompanyId(UUID companyId) {
|
||||||
|
return licenseDao.findByCompanyId(companyId).stream()
|
||||||
|
.map(LicenseMapper::licenseEntityToLicense)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<License> findByLicenseKey(String licenseKey) {
|
||||||
|
return licenseDao.findByLicenseKey(licenseKey)
|
||||||
|
.map(LicenseMapper::licenseEntityToLicense);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteById(UUID id) {
|
||||||
|
licenseDao.deleteById(id);
|
||||||
|
log.info("License deleted with ID: {}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deactivateLicense(UUID id) {
|
||||||
|
licenseDao.findById(id).ifPresent(license -> {
|
||||||
|
license.setActive(false);
|
||||||
|
licenseDao.save(license);
|
||||||
|
log.info("License deactivated with ID: {}", id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
package com.dh7789dev.xpeditis.repository;
|
||||||
|
|
||||||
|
import com.dh7789dev.xpeditis.UserRepository;
|
||||||
|
import com.dh7789dev.xpeditis.dao.UserDao;
|
||||||
|
import com.dh7789dev.xpeditis.dto.app.UserAccount;
|
||||||
|
import com.dh7789dev.xpeditis.dto.request.ChangePasswordRequest;
|
||||||
|
import com.dh7789dev.xpeditis.entity.UserEntity;
|
||||||
|
import com.dh7789dev.xpeditis.mapper.UserMapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserJpaRepository implements UserRepository {
|
||||||
|
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changePassword(ChangePasswordRequest request, Principal connectedUser) {
|
||||||
|
String username = connectedUser.getName();
|
||||||
|
UserEntity user = userDao.findByUsername(username)
|
||||||
|
.orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
|
||||||
|
// Verify current password
|
||||||
|
if (!passwordEncoder.matches(request.getCurrentPassword(), user.getPassword())) {
|
||||||
|
throw new RuntimeException("Current password is incorrect");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify new password matches confirmation
|
||||||
|
if (!request.getNewPassword().equals(request.getConfirmationPassword())) {
|
||||||
|
throw new RuntimeException("New password and confirmation do not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update password
|
||||||
|
user.setPassword(passwordEncoder.encode(request.getNewPassword()));
|
||||||
|
userDao.save(user);
|
||||||
|
log.info("Password changed successfully for user: {}", username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserAccount save(UserAccount userAccount) {
|
||||||
|
UserEntity entity = UserMapper.userAccountToUserEntity(userAccount);
|
||||||
|
UserEntity savedEntity = userDao.save(entity);
|
||||||
|
return UserMapper.userEntityToUserAccount(savedEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<UserAccount> findById(UUID id) {
|
||||||
|
return userDao.findById(id).map(UserMapper::userEntityToUserAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<UserAccount> findByEmail(String email) {
|
||||||
|
return userDao.findByEmail(email).map(UserMapper::userEntityToUserAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<UserAccount> findByUsername(String username) {
|
||||||
|
return userDao.findByUsername(username).map(UserMapper::userEntityToUserAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<UserAccount> findByGoogleId(String googleId) {
|
||||||
|
return userDao.findByGoogleId(googleId).map(UserMapper::userEntityToUserAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean existsByEmail(String email) {
|
||||||
|
return userDao.existsByEmail(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean existsByUsername(String username) {
|
||||||
|
return userDao.existsByUsername(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteById(UUID id) {
|
||||||
|
userDao.deleteById(id);
|
||||||
|
log.info("User deleted with ID: {}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deactivateUser(UUID id) {
|
||||||
|
UserEntity user = userDao.findById(id)
|
||||||
|
.orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
user.setEnabled(false);
|
||||||
|
userDao.save(user);
|
||||||
|
log.info("User deactivated with ID: {}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserAccount> findByCompanyIdAndIsActive(UUID companyId, boolean isActive) {
|
||||||
|
// This needs to be implemented in UserDao
|
||||||
|
log.warn("findByCompanyIdAndIsActive not yet implemented in UserDao");
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserAccount> findAllUsers(int page, int size) {
|
||||||
|
Pageable pageable = PageRequest.of(page, size);
|
||||||
|
Page<UserEntity> userPage = userDao.findAll(pageable);
|
||||||
|
return userPage.getContent().stream()
|
||||||
|
.map(UserMapper::userEntityToUserAccount)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserAccount> findUsersByCompany(UUID companyId, int page, int size) {
|
||||||
|
// For now, return all users filtered by company (needs DAO method)
|
||||||
|
Pageable pageable = PageRequest.of(page, size);
|
||||||
|
Page<UserEntity> userPage = userDao.findAll(pageable);
|
||||||
|
return userPage.getContent().stream()
|
||||||
|
.filter(user -> user.getCompany() != null && user.getCompany().getId().equals(companyId))
|
||||||
|
.map(UserMapper::userEntityToUserAccount)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countAllUsers() {
|
||||||
|
return userDao.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long countUsersByCompany(UUID companyId) {
|
||||||
|
// For now, count all and filter (needs DAO method for optimization)
|
||||||
|
return userDao.findAll().stream()
|
||||||
|
.filter(user -> user.getCompany() != null && user.getCompany().getId().equals(companyId))
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
}
|
||||||
6
pom.xml
6
pom.xml
@ -41,9 +41,9 @@
|
|||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>23</java.version>
|
<java.version>21</java.version>
|
||||||
<maven.compiler.source>23</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>23</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<org.projectlombok.version>1.18.36</org.projectlombok.version>
|
<org.projectlombok.version>1.18.36</org.projectlombok.version>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user