diff --git a/src/main/java/org/example/crm/controller/DeveloperController.java b/src/main/java/org/example/crm/controller/DeveloperController.java new file mode 100644 index 0000000..5c20c6d --- /dev/null +++ b/src/main/java/org/example/crm/controller/DeveloperController.java @@ -0,0 +1,23 @@ +package org.example.crm.controller; + +import lombok.RequiredArgsConstructor; +import org.example.crm.entity.dto.user.AdminUserCreateDto; +import org.example.crm.entity.dto.user.UserCreateDto; +import org.example.crm.entity.dto.user.UserDto; +import org.example.crm.service.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@PreAuthorize("hasRole('DEVELOPER')") +@RequestMapping("/api/v1/developer") +public class DeveloperController { + final UserService userService; + + @PostMapping("/create-super-admin") + public ResponseEntity createSuperAdmin(@RequestParam String organizationId, @RequestBody AdminUserCreateDto userCreateDto) { + return ResponseEntity.status(201).body(userService.createSuperAdmin(organizationId, userCreateDto)); + } +} diff --git a/src/main/java/org/example/crm/controller/UserController.java b/src/main/java/org/example/crm/controller/UserController.java index 784a313..0300520 100644 --- a/src/main/java/org/example/crm/controller/UserController.java +++ b/src/main/java/org/example/crm/controller/UserController.java @@ -63,4 +63,5 @@ public ResponseEntity delete(@PathVariable String id) { userService.delete(id); return ResponseEntity.noContent().build(); } + } \ No newline at end of file diff --git a/src/main/java/org/example/crm/entity/dto/user/AdminUserCreateDto.java b/src/main/java/org/example/crm/entity/dto/user/AdminUserCreateDto.java new file mode 100644 index 0000000..f54fd70 --- /dev/null +++ b/src/main/java/org/example/crm/entity/dto/user/AdminUserCreateDto.java @@ -0,0 +1,10 @@ +package org.example.crm.entity.dto.user; + + +public record AdminUserCreateDto( + String fullName, + String phone, + String password, + String branchId +) { +} diff --git a/src/main/java/org/example/crm/exceptions/ErrorType.java b/src/main/java/org/example/crm/exceptions/ErrorType.java index 6f1e5ff..9c1539e 100644 --- a/src/main/java/org/example/crm/exceptions/ErrorType.java +++ b/src/main/java/org/example/crm/exceptions/ErrorType.java @@ -60,13 +60,15 @@ public enum ErrorType { PERMISSION_ONLY_FOR_ADMINISTRATOR("permission.only.for.administrator"), ZERO_ON_BALANCE("zero.on.balance"), ENROLLMENT_ALREADY_EXISTS("enrollment.already.exists"), - STUDENT_ALREADY_ENROLLED_TO_THIS_GROUP("student.already.enrolled.to.this.group"), COURSE_NOT_FOUND("course.not.found"), + STUDENT_ALREADY_ENROLLED_TO_THIS_GROUP("student.already.enrolled.to.this.group"), + COURSE_NOT_FOUND("course.not.found"), COURSE_ALREADY_EXISTS("course.already.exists"), INVALID_INPUT("invalid.input"), TRANSACTION_NOT_FOUND("transaction.not.found"), INVOICE_ALREADY_CREATED("invoice.already.created"), INVOICE_ALREADY_PAID("invoice.already.paid"), - INVOICE_REQUIRED("invoice.required"); + INVOICE_REQUIRED("invoice.required"), + WRONG_ORGANIZATION("wrong.organization"),; private final String key; diff --git a/src/main/java/org/example/crm/initializer/DataInitializer.java b/src/main/java/org/example/crm/initializer/DataInitializer.java index 297446d..c38aee5 100644 --- a/src/main/java/org/example/crm/initializer/DataInitializer.java +++ b/src/main/java/org/example/crm/initializer/DataInitializer.java @@ -13,10 +13,12 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Arrays; @Component @RequiredArgsConstructor -////implements CommandLineRunner +//implements CommandLineRunner public class DataInitializer { final UserRepository userRepository; @@ -29,9 +31,10 @@ public class DataInitializer { final AttendanceRepository attendanceRepository; final OrganizationRepository organizationRepository; final PasswordEncoder passwordEncoder; + final BranchRepository branchRepository; final EntityManager entityManager; - static Organization organization = new Organization("org", "phone", "email", "website"); -// + Organization organization = new Organization("org", "phone", "email", "website"); + // @Override @Transactional @@ -49,9 +52,12 @@ public void run(String... args) { developer.setPassword(encodedPassword); developer.setRole(Role.DEVELOPER); developer.setFullName("developer"); + developer.setPermissions(new ArrayList<>(Arrays.asList(AdministratorPermission.EMPLOYEE_MANAGEMENT, AdministratorPermission.INVOICE_MANAGEMENT, + AdministratorPermission.LEAD_MANAGEMENT,AdministratorPermission.STUDENT_MANAGEMENT,AdministratorPermission.TEACHER_MANAGEMENT))); userRepository.save(developer); + User adminUser = new User(); adminUser.setOrganizationId(organization.getId()); adminUser.setFullName("Admin John"); @@ -115,6 +121,19 @@ public void run(String... args) { studentUser4.setBirthDate(LocalDate.of(2012, 1, 30)); userRepository.save(studentUser4); + + // ============ BRANCHES ============ + Branch branch1 = new Branch(); + branch1.setOrganizationId(organization.getId()); + branch1.setName("Main Branch"); + branch1.setAddress("123 Main St"); + branch1.setLongitude(40.7128); + branch1.setLatitude(-74.0060); + branch1.setGoogleMapsUrl("https://www.google.com/maps/place/123+Main+St"); + branch1.setGooglePlaceId("ChIJd8BlQ2BZwokRAFUEcm_qrcA"); + branchRepository.save(branch1); + + // ============ TEACHERS ============ Teacher teacher1 = new Teacher(); teacher1.setOrganizationId(organization.getId()); diff --git a/src/main/java/org/example/crm/mapper/UserMapper.java b/src/main/java/org/example/crm/mapper/UserMapper.java index aeb7539..77cea92 100644 --- a/src/main/java/org/example/crm/mapper/UserMapper.java +++ b/src/main/java/org/example/crm/mapper/UserMapper.java @@ -1,6 +1,7 @@ package org.example.crm.mapper; import org.example.crm.annotation.IgnoreAuditFields; +import org.example.crm.entity.dto.user.AdminUserCreateDto; import org.example.crm.entity.dto.user.UserCreateDto; import org.example.crm.entity.dto.user.UserDto; import org.example.crm.entity.dto.user.UserUpdateDto; @@ -25,4 +26,8 @@ public abstract class UserMapper { @Mapping(target = "birthDate", ignore = true) @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public abstract void mapUpdate(@MappingTarget User user, UserUpdateDto updateDto); + + @IgnoreAuditFields + @Mapping(target = "branch", ignore = true) + public abstract User toEntity(AdminUserCreateDto userCreateDto); } \ No newline at end of file diff --git a/src/main/java/org/example/crm/service/AuthService.java b/src/main/java/org/example/crm/service/AuthService.java index cb35bf9..12c3f46 100644 --- a/src/main/java/org/example/crm/service/AuthService.java +++ b/src/main/java/org/example/crm/service/AuthService.java @@ -19,6 +19,7 @@ import org.example.crm.exceptions.ErrorType; import org.example.crm.exceptions.RestException; import org.example.crm.mapper.UserMapper; +import org.example.crm.repository.OrganizationRepository; import org.example.crm.repository.UserRepository; import org.example.crm.validator.UserValidator; import org.springframework.beans.factory.annotation.Value; @@ -42,6 +43,7 @@ public class AuthService { private final JwtUtils jwtUtils; private final UserMapper userMapper; private final UserValidator userValidator; + final OrganizationRepository organizationRepository; @Value("${jwt.refresh.token.expire.date:86400}") private Long refreshTokenExpiration; @@ -58,6 +60,11 @@ public LoginResponse getLoginResponseResponseEntity(@Valid LoginRequest request, if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { throw new RestException(ErrorType.INVALID_PHONE_NUMBER_OR_PASSWORD, ErrorCodes.BadRequest); } + + boolean b = organizationRepository.existsById(request.getOrganizationId()); + if (!b) { + throw new RestException(ErrorType.ORGANIZATION_NOT_FOUND, ErrorCodes.NotFound); + } Map claims = jwtUtils.prepareClaims(user, request.getOrganizationId()); TokenDto accessToken = jwtUtils.generateToken(user.getPhone(), claims, "access"); TokenDto refreshToken = jwtUtils.generateToken(user.getPhone(), claims, "refresh"); diff --git a/src/main/java/org/example/crm/service/UserService.java b/src/main/java/org/example/crm/service/UserService.java index f918a1b..3bb5fae 100644 --- a/src/main/java/org/example/crm/service/UserService.java +++ b/src/main/java/org/example/crm/service/UserService.java @@ -1,9 +1,8 @@ package org.example.crm.service; -import org.example.crm.entity.dto.user.UserCreateDto; -import org.example.crm.entity.dto.user.UserCreatedResponseDto; -import org.example.crm.entity.dto.user.UserDto; -import org.example.crm.entity.dto.user.UserUpdateDto; +import org.example.crm.entity.dto.user.*; +import org.example.crm.entity.enums.AdministratorPermission; +import org.example.crm.entity.enums.Role; import org.example.crm.exceptions.ErrorCodes; import org.example.crm.exceptions.ErrorType; import org.example.crm.entity.model.Branch; @@ -22,6 +21,8 @@ import org.springframework.stereotype.Service; import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; @Service public class UserService extends AbstractService< @@ -114,4 +115,32 @@ public static String generatePassword(int length) { return password.toString(); } + + public UserDto createSuperAdmin(String organizationId, AdminUserCreateDto userCreateDto) { + + String userOrganization = validator.authenticateAndGetOrganizationId(); + organizationValidator.validateAndGetId(organizationId); + if (!userOrganization.equals(organizationId)) { + throw new RestException(ErrorType.WRONG_ORGANIZATION, ErrorCodes.BadRequest); + } + validator.validate(userCreateDto); + User entity = mapper.toEntity(userCreateDto); + entity.setOrganizationId(organizationId); + entity.setPassword(passwordEncoder.encode(userCreateDto.password())); + Branch branch = branchValidator.validateIdAndGet(userCreateDto.branchId()); + entity.setBranch(branch); + entity.setRole(Role.SUPER_ADMIN); + entity.setPermissions(new ArrayList<>(Arrays.asList(AdministratorPermission.EMPLOYEE_MANAGEMENT, AdministratorPermission.INVOICE_MANAGEMENT, + AdministratorPermission.LEAD_MANAGEMENT,AdministratorPermission.STUDENT_MANAGEMENT,AdministratorPermission.TEACHER_MANAGEMENT))); + User save = repository.save(entity); + return new UserDto( + save.getId(), + userCreateDto.branchId(), + null, + save.getFullName(), + save.getPhone(), + null, + save.getRole() + ); + } } diff --git a/src/main/java/org/example/crm/validator/UserValidator.java b/src/main/java/org/example/crm/validator/UserValidator.java index 9559457..b53a356 100644 --- a/src/main/java/org/example/crm/validator/UserValidator.java +++ b/src/main/java/org/example/crm/validator/UserValidator.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.example.crm.config.CustomUserDetails; +import org.example.crm.entity.dto.user.AdminUserCreateDto; import org.example.crm.entity.dto.user.UserCreateDto; import org.example.crm.entity.enums.AdministratorPermission; import org.example.crm.entity.enums.Role; @@ -86,4 +87,10 @@ public void validateIfCurrentUser(User user, String id) { throw new RestException(ErrorType.FORBIDDEN, ErrorCodes.Forbidden); } } + + public void validate(AdminUserCreateDto userCreateDto) { + if (repository.existsByPhone(userCreateDto.phone())) { + throw new RestException(ErrorType.USER_ALREADY_EXISTS, ErrorCodes.BadRequest); + } + } }