Skip to content

Commit

Permalink
AYS-640 | Create and Update Role Flows Have Been Fixed with Same Name…
Browse files Browse the repository at this point in the history
… for Different Institutions (#422)
  • Loading branch information
agitrubard authored Jan 2, 2025
1 parent f4b920f commit baaecd3
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 205 deletions.
9 changes: 5 additions & 4 deletions src/main/java/org/ays/auth/port/AysRoleReadPort.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ public interface AysRoleReadPort {
List<AysRole> findAllByIds(Set<String> ids);

/**
* Retrieves a role by its name.
* Retrieves a role by its name and institution ID.
*
* @param name The name of the role to retrieve.
* @return An optional containing the role if found, otherwise empty.
* @param name The name of the role to retrieve.
* @param institutionId The ID of the institution to which the role belongs.
* @return An {@link Optional} containing the role if found, otherwise empty.
*/
Optional<AysRole> findByName(String name);
Optional<AysRole> findByNameAndInstitutionId(String name, String institutionId);

/**
* Checks if any users are assigned to a role identified by its ID.
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/ays/auth/port/adapter/AysRoleAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ public List<AysRole> findAllByIds(Set<String> ids) {


/**
* Retrieves an {@link AysRole} by its name.
* Retrieves an {@link AysRole} by its name and institution ID.
*
* @param name The name of the role to retrieve.
* @return An optional containing the {@link AysRole} if found, otherwise empty.
* @param name The name of the role to retrieve.
* @param institutionId The ID of the institution to which the role belongs.
* @return An {@link Optional} containing the {@link AysRole} if found, otherwise empty.
*/
@Override
public Optional<AysRole> findByName(final String name) {
final Optional<AysRoleEntity> roleEntity = roleRepository.findByName(name);
public Optional<AysRole> findByNameAndInstitutionId(final String name, final String institutionId) {
final Optional<AysRoleEntity> roleEntity = roleRepository.findByNameAndInstitutionId(name, institutionId);
return roleEntity.map(roleEntityToDomainMapper::map);
}

Expand Down
9 changes: 5 additions & 4 deletions src/main/java/org/ays/auth/repository/AysRoleRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ public interface AysRoleRepository extends JpaRepository<AysRoleEntity, String>,
List<AysRoleEntity> findAllByInstitutionIdAndStatus(String institutionId, AysRoleStatus status);

/**
* Finds a {@link AysRoleEntity} by the given role name.
* Finds a {@link AysRoleEntity} by its name and institution ID.
*
* @param name the name of the role
* @return an {@link Optional} containing the {@link AysRoleEntity} if found, or empty if not found
* @param name The name of the role.
* @param institutionId The ID of the institution to which the role belongs.
* @return An {@link Optional} containing the {@link AysRoleEntity} if found, otherwise empty.
*/
Optional<AysRoleEntity> findByName(String name);
Optional<AysRoleEntity> findByNameAndInstitutionId(String name, String institutionId);

/**
* Checks if any users are assigned to the role identified by the given role ID.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,31 @@ class AysRoleCreateServiceImpl implements AysRoleCreateService {
/**
* Creates a new role based on the provided create request.
* <p>
* This method validates the uniqueness of the role name, checks the existence of permissions,
* and saves the new role with the associated permissions.
* This method performs the following steps:
* <ul>
* <li>Validates the uniqueness of the role name within the institution.</li>
* <li>Checks if the provided permission IDs exist.</li>
* <li>Ensures the user has the appropriate authority to assign permissions, especially super permissions.</li>
* <li>Saves the new role with its associated permissions.</li>
* </ul>
* </p>
*
* @param createRequest the request object containing the role name and permission IDs
* @throws AysRoleAlreadyExistsByNameException if a role with the same name already exists
* @throws AysPermissionNotExistException if any of the specified permission IDs do not exist
* @throws AysUserNotSuperAdminException if the current user is not authorized to assign super permissions
* @param createRequest The request object containing the role name and permission IDs.
* @throws AysRoleAlreadyExistsByNameException If a role with the same name already exists in the institution.
* @throws AysPermissionNotExistException If any of the specified permission IDs do not exist.
* @throws AysUserNotSuperAdminException If the current user is not authorized to assign super permissions.
*/
@Override
public void create(final AysRoleCreateRequest createRequest) {

this.checkExistingRoleName(createRequest.getName());
final String institutionId = identity.getInstitutionId();
this.checkExistingRoleName(createRequest.getName(), institutionId);

final List<AysPermission> permissions = this.checkExistingPermissionsAndGet(createRequest.getPermissionIds());

final AysRole role = AysRole.builder()
.name(createRequest.getName())
.institution(Institution.builder().id(identity.getInstitutionId()).build())
.institution(Institution.builder().id(institutionId).build())
.permissions(permissions)
.status(AysRoleStatus.ACTIVE)
.build();
Expand All @@ -68,25 +74,35 @@ public void create(final AysRoleCreateRequest createRequest) {
}

/**
* Checks if a role with the specified name already exists.
* Checks if a role with the specified name already exists within the institution.
*
* @param name the name of the role to check
* @throws AysRoleAlreadyExistsByNameException if a role with the same name already exists
* @param name The name of the role to check.
* @param institutionId The ID of the institution where the role is being created.
* @throws AysRoleAlreadyExistsByNameException If a role with the same name already exists in the institution.
*/
private void checkExistingRoleName(final String name) {
roleReadPort.findByName(name).ifPresent(role -> {
throw new AysRoleAlreadyExistsByNameException(name);
});
private void checkExistingRoleName(final String name, final String institutionId) {
roleReadPort.findByNameAndInstitutionId(name, institutionId)
.ifPresent(role -> {
throw new AysRoleAlreadyExistsByNameException(name);
});
}

/**
* Checks the existence of permissions based on the provided permission IDs.
* Verifies if all permission IDs exist and validates super admin restrictions.
* Checks the existence of permissions based on the provided permission IDs
* and ensures that the user has the authority to assign the permissions.
* <p>
* This method performs the following steps:
* <ul>
* <li>Retrieves all permissions corresponding to the provided IDs.</li>
* <li>Validates that all requested permissions exist in the system.</li>
* <li>Ensures that super permissions can only be assigned by super admins.</li>
* </ul>
* </p>
*
* @param permissionIds the set of permission IDs to check
* @return the list of permissions corresponding to the provided IDs
* @throws AysPermissionNotExistException if any of the permission IDs do not exist
* @throws AysUserNotSuperAdminException if the current user is not authorized to assign super permissions
* @param permissionIds The set of permission IDs to check.
* @return A list of {@link AysPermission} objects corresponding to the provided IDs.
* @throws AysPermissionNotExistException If any of the permission IDs do not exist.
* @throws AysUserNotSuperAdminException If the current user is not authorized to assign super permissions.
*/
private List<AysPermission> checkExistingPermissionsAndGet(final Set<String> permissionIds) {
final List<AysPermission> permissions = permissionReadPort.findAllByIds(permissionIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,34 @@ class AysRoleUpdateServiceImpl implements AysRoleUpdateService {
/**
* Updates an existing role identified by its ID.
* <p>
* This method performs checks to ensure the role name is unique and validates the existence of provided permissions.
* It also verifies that the role belongs to the same institution as the current user's institution.
* This method performs the following steps:
* <ul>
* <li>Ensures the role exists and belongs to the same institution as the current user.</li>
* <li>Validates the uniqueness of the role name within the institution.</li>
* <li>Checks if the provided permissions exist and validates the user's authorization for assigning super permissions.</li>
* <li>Updates the role's attributes such as name and permissions, and persists the changes.</li>
* </ul>
* </p>
*
* @param id The ID of the role to update.
* @param updateRequest The request object containing updated data for the role.
* @throws AysRoleAlreadyExistsByNameException if a role with the same name already exists, excluding the current role ID.
* @throws AysPermissionNotExistException if any of the permission IDs provided do not exist.
* @throws AysPermissionNotExistException if any of the specified permission IDs do not exist.
* @throws AysUserNotSuperAdminException if the current user does not have super admin privileges required for assigning super permissions.
* @throws AysRoleNotExistByIdException if the role with the given ID does not exist or does not belong to the current user's institution.
*/
@Override
public void update(final String id,
final AysRoleUpdateRequest updateRequest) {

final String institutionId = identity.getInstitutionId();
final AysRole role = roleReadPort.findById(id)
.filter(roleFromDatabase -> identity.getInstitutionId().equals(roleFromDatabase.getInstitution().getId()))
.filter(roleFromDatabase -> institutionId.equals(roleFromDatabase.getInstitution().getId()))
.orElseThrow(() -> new AysRoleNotExistByIdException(id));

final boolean isRoleNameChanged = !role.getName().equals(updateRequest.getName());
if (isRoleNameChanged) {
this.checkExistingRoleNameByWithoutId(id, updateRequest.getName());
this.checkExistingRoleNameByWithoutId(id, updateRequest.getName(), institutionId);
}

final Set<String> existingPermissionIds = role.getPermissions().stream()
Expand All @@ -86,13 +92,18 @@ public void update(final String id,

/**
* Checks the existence of another role with the same name, excluding the current role ID.
* <p>
* This method ensures that the role name is unique within the institution for all roles
* except the one being updated.
* </p>
*
* @param id The ID of the role being updated.
* @param name The name to check for uniqueness.
* @param id The ID of the role being updated.
* @param name The name to check for uniqueness.
* @param institutionId The ID of the institution to which the role belongs.
* @throws AysRoleAlreadyExistsByNameException if a role with the same name already exists, excluding the current role ID.
*/
private void checkExistingRoleNameByWithoutId(final String id, final String name) {
roleReadPort.findByName(name)
private void checkExistingRoleNameByWithoutId(final String id, final String name, final String institutionId) {
roleReadPort.findByNameAndInstitutionId(name, institutionId)
.filter(role -> !id.equals(role.getId()))
.ifPresent(role -> {
throw new AysRoleAlreadyExistsByNameException(name);
Expand All @@ -102,14 +113,17 @@ private void checkExistingRoleNameByWithoutId(final String id, final String name
/**
* Validates the specified permission IDs and checks user authorization.
* <p>
* This method verifies if all permission IDs exist in the system and checks if the user
* has appropriate access level for super permissions. Only super admin users can assign
* super permissions.
* This method performs the following steps:
* <ul>
* <li>Verifies if all provided permission IDs exist in the system.</li>
* <li>Ensures only super admin users can assign super permissions.</li>
* <li>Throws appropriate exceptions for missing permissions or unauthorized access attempts.</li>
* </ul>
* </p>
*
* @param permissionIds the set of permission IDs to validate
* @throws AysPermissionNotExistException if any of the specified permissions do not exist
* @throws AysUserNotSuperAdminException if a non-super admin user attempts to assign super permissions
* @param permissionIds the set of permission IDs to validate.
* @throws AysPermissionNotExistException if any of the specified permissions do not exist.
* @throws AysUserNotSuperAdminException if a non-super admin user attempts to assign super permissions.
*/
private void validatePermissions(final Set<String> permissionIds) {

Expand Down
Loading

0 comments on commit baaecd3

Please sign in to comment.