-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #689 from HNG-12/teibeina-add-members-to-org
feat: implement add users to an organisation.
- Loading branch information
Showing
6 changed files
with
306 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
src/main/java/hng_java_boilerplate/organisation/dto/AddUserRequestDTO.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package hng_java_boilerplate.organisation.dto; | ||
|
||
import jakarta.validation.constraints.NotEmpty; | ||
import jakarta.validation.constraints.Size; | ||
import lombok.Builder; | ||
|
||
import java.util.List; | ||
|
||
@Builder | ||
public record AddUserRequestDTO( | ||
@NotEmpty(message = "User ID cannot be empty") | ||
@Size(min = 1, message = "Provide a valid user ID") | ||
List<String> user_ids | ||
) { | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/hng_java_boilerplate/organisation/dto/AddUserResponseDTO.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package hng_java_boilerplate.organisation.dto; | ||
|
||
import hng_java_boilerplate.organisation.interfaces.AddUserResponse; | ||
import lombok.Builder; | ||
|
||
import java.util.List; | ||
|
||
@Builder | ||
public record AddUserResponseDTO( | ||
String status, | ||
String message, | ||
String organization_id, | ||
List<String> users_added_to_organisation, | ||
Integer status_code | ||
) implements AddUserResponse { | ||
} |
4 changes: 4 additions & 0 deletions
4
src/main/java/hng_java_boilerplate/organisation/interfaces/AddUserResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package hng_java_boilerplate.organisation.interfaces; | ||
|
||
public interface AddUserResponse { | ||
} |
70 changes: 70 additions & 0 deletions
70
src/main/java/hng_java_boilerplate/organisation/service/AddUsersToOrganisationService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package hng_java_boilerplate.organisation.service; | ||
|
||
import hng_java_boilerplate.exception.ConflictException; | ||
import hng_java_boilerplate.exception.NotFoundException; | ||
import hng_java_boilerplate.exception.UnAuthorizedException; | ||
import hng_java_boilerplate.organisation.dto.AddUserRequestDTO; | ||
import hng_java_boilerplate.organisation.dto.AddUserResponseDTO; | ||
import hng_java_boilerplate.organisation.entity.Organisation; | ||
import hng_java_boilerplate.organisation.interfaces.AddUserResponse; | ||
import hng_java_boilerplate.organisation.repository.OrganisationRepository; | ||
import hng_java_boilerplate.user.entity.User; | ||
import hng_java_boilerplate.user.repository.UserRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AddUsersToOrganisationService { | ||
private final OrganisationRepository organisationRepository; | ||
private final UserRepository userRepository; | ||
|
||
@Transactional | ||
public AddUserResponse addUserToOrganisation( | ||
String organisationId, | ||
AddUserRequestDTO orgRequest, | ||
Authentication authenticatedUser | ||
) { | ||
Organisation organisation = organisationRepository.findById(organisationId). | ||
orElseThrow(() -> new NotFoundException("Organisation with id " + organisationId + " does not exist")); | ||
|
||
User user = (User) authenticatedUser.getPrincipal(); | ||
|
||
if (!organisation.getOwner().equals(user.getId())) { | ||
throw new UnAuthorizedException("User is not owner of the organisation"); | ||
} | ||
|
||
List<String> addedUserIds = new ArrayList<>(); | ||
|
||
for (String userId : orgRequest.user_ids()) { | ||
if (organisation.getUsers().stream().anyMatch(user1 -> user1.getId().equals(userId))) { | ||
throw new ConflictException("User with id " + userId + " is already in the organisation"); | ||
} | ||
|
||
var userExists = userRepository.findById(userId); | ||
if (userExists.isEmpty()) { | ||
throw new NotFoundException("User with id " + userId + " does not exist"); | ||
} | ||
|
||
organisation.getUsers().add(userExists.get()); | ||
userExists.get().getOrganisations().add(organisation); | ||
addedUserIds.add(userId); | ||
} | ||
|
||
organisationRepository.save(organisation); | ||
|
||
return AddUserResponseDTO.builder() | ||
.status("success") | ||
.message("Users added to organisation") | ||
.organization_id(organisation.getId()) | ||
.users_added_to_organisation(addedUserIds) | ||
.status_code(HttpStatus.OK.value()) | ||
.build(); | ||
} | ||
} |
185 changes: 185 additions & 0 deletions
185
...est/java/hng_java_boilerplate/organisation/service/AddUsersToOrganisationServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package hng_java_boilerplate.organisation.service; | ||
|
||
import hng_java_boilerplate.exception.ConflictException; | ||
import hng_java_boilerplate.exception.NotFoundException; | ||
import hng_java_boilerplate.exception.UnAuthorizedException; | ||
import hng_java_boilerplate.organisation.dto.AddUserRequestDTO; | ||
import hng_java_boilerplate.organisation.dto.AddUserResponseDTO; | ||
import hng_java_boilerplate.organisation.entity.Organisation; | ||
import hng_java_boilerplate.organisation.repository.OrganisationRepository; | ||
import hng_java_boilerplate.user.entity.User; | ||
import hng_java_boilerplate.user.repository.UserRepository; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
import org.springframework.security.core.Authentication; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.mockito.Mockito.*; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
public class AddUsersToOrganisationServiceTest { | ||
|
||
@Mock | ||
private OrganisationRepository organisationRepository; | ||
|
||
@Mock | ||
private UserRepository userRepository; | ||
|
||
@Mock | ||
private Authentication authenticatedUser; | ||
|
||
@InjectMocks | ||
private AddUsersToOrganisationService addUsersToOrganisationService; | ||
|
||
private AddUserRequestDTO orgRequest; | ||
private User user; | ||
|
||
@Test | ||
void testAddUserToOrganisation_OrganisationNotFound() { | ||
String organisationId = "b1e009c5-a197-42f9-b9a3-98fc357b5f08"; | ||
AddUserRequestDTO orgRequest = new AddUserRequestDTO(List.of("user1", "user2", "user3")); | ||
|
||
when(organisationRepository.findById(organisationId)).thenReturn(Optional.empty()); | ||
|
||
NotFoundException exception = assertThrows(NotFoundException.class, () -> | ||
addUsersToOrganisationService.addUserToOrganisation(organisationId, orgRequest, authenticatedUser)); | ||
assertEquals("Organisation with id " + organisationId + " does not exist", exception.getMessage()); | ||
|
||
verify(organisationRepository).findById(organisationId); | ||
verifyNoMoreInteractions(organisationRepository); | ||
verifyNoInteractions(userRepository); | ||
verifyNoInteractions(authenticatedUser); | ||
} | ||
|
||
@Test | ||
void testAddUserToOrganisation_UserNotOwner() { | ||
String organisationId = "b1e009c5-a197-42f9-b9a3-98fc357b5f08"; | ||
AddUserRequestDTO orgRequest = new AddUserRequestDTO(List.of("user1", "user2", "user3")); | ||
User activeUser = new User(); | ||
activeUser.setId("user-123"); | ||
|
||
Organisation organisation = new Organisation(); | ||
organisation.setOwner("user-456"); | ||
|
||
when(organisationRepository.findById(organisationId)).thenReturn(Optional.of(organisation)); | ||
when(authenticatedUser.getPrincipal()).thenReturn(activeUser); | ||
|
||
UnAuthorizedException exception = assertThrows(UnAuthorizedException.class, () -> | ||
addUsersToOrganisationService.addUserToOrganisation(organisationId, orgRequest, authenticatedUser)); | ||
assertEquals("User is not owner of the organisation", exception.getMessage()); | ||
|
||
verify(organisationRepository).findById(organisationId); | ||
verify(authenticatedUser).getPrincipal(); | ||
verifyNoMoreInteractions(organisationRepository); | ||
verifyNoMoreInteractions(authenticatedUser); | ||
verifyNoInteractions(userRepository); | ||
} | ||
|
||
@Test | ||
void testAddUserToOrganisation_UserAlreadyInOrganisation() { | ||
String organisationId = "b1e009c5-a197-42f9-b9a3-98fc357b5f08"; | ||
AddUserRequestDTO orgRequest = new AddUserRequestDTO(List.of("user1", "user2", "user3")); | ||
User activeUser = new User(); | ||
activeUser.setId("user-123"); | ||
|
||
User existingUser = new User(); | ||
existingUser.setId("user1"); | ||
|
||
Organisation organisation = new Organisation(); | ||
organisation.setId(organisationId); | ||
organisation.setOwner("user-123"); | ||
organisation.setUsers(List.of(existingUser)); | ||
|
||
when(organisationRepository.findById(organisationId)).thenReturn(Optional.of(organisation)); | ||
when(authenticatedUser.getPrincipal()).thenReturn(activeUser); | ||
|
||
ConflictException exception = assertThrows(ConflictException.class, () -> | ||
addUsersToOrganisationService.addUserToOrganisation(organisationId, orgRequest, authenticatedUser)); | ||
assertEquals("User with id user1 is already in the organisation", exception.getMessage()); | ||
|
||
verify(organisationRepository).findById(organisationId); | ||
verify(authenticatedUser).getPrincipal(); | ||
verifyNoMoreInteractions(organisationRepository); | ||
verifyNoMoreInteractions(authenticatedUser); | ||
verifyNoInteractions(userRepository); | ||
} | ||
|
||
@Test | ||
void testAddUserToOrganisation_UserDoesNotExist() { | ||
String organisationId = "b1e009c5-a197-42f9-b9a3-98fc357b5f08"; | ||
AddUserRequestDTO orgRequest = new AddUserRequestDTO(List.of("user2")); | ||
User activeUser = new User(); | ||
activeUser.setId("user-123"); | ||
|
||
Organisation organisation = new Organisation(); | ||
organisation.setId(organisationId); | ||
organisation.setOwner("user-123"); | ||
organisation.setUsers(new ArrayList<>()); | ||
|
||
when(organisationRepository.findById(organisationId)).thenReturn(Optional.of(organisation)); | ||
when(authenticatedUser.getPrincipal()).thenReturn(activeUser); | ||
when(userRepository.findById("user2")).thenReturn(Optional.empty()); | ||
|
||
NotFoundException exception = assertThrows(NotFoundException.class, () -> | ||
addUsersToOrganisationService.addUserToOrganisation(organisationId, orgRequest, authenticatedUser)); | ||
assertEquals("User with id user2 does not exist", exception.getMessage()); | ||
|
||
verify(organisationRepository).findById(organisationId); | ||
verify(authenticatedUser).getPrincipal(); | ||
verify(userRepository).findById("user2"); | ||
verifyNoMoreInteractions(organisationRepository); | ||
verifyNoMoreInteractions(authenticatedUser); | ||
verifyNoMoreInteractions(userRepository); | ||
} | ||
|
||
@Test | ||
void testAddUserToOrganisation_Successful() { | ||
String organisationId = "b1e009c5-a197-42f9-b9a3-98fc357b5f08"; | ||
AddUserRequestDTO orgRequest = new AddUserRequestDTO(List.of("user1", "user2")); | ||
User activeUser = new User(); | ||
activeUser.setId("user-123"); | ||
|
||
Organisation organisation = new Organisation(); | ||
organisation.setId(organisationId); | ||
organisation.setOwner("user-123"); | ||
organisation.setUsers(new ArrayList<>()); | ||
|
||
User user1 = new User(); | ||
user1.setId("user1"); | ||
user1.setOrganisations(new ArrayList<>()); | ||
|
||
User user2 = new User(); | ||
user2.setId("user2"); | ||
user2.setOrganisations(new ArrayList<>()); | ||
|
||
when(organisationRepository.findById(organisationId)).thenReturn(Optional.of(organisation)); | ||
when(authenticatedUser.getPrincipal()).thenReturn(activeUser); | ||
when(userRepository.findById("user1")).thenReturn(Optional.of(user1)); | ||
when(userRepository.findById("user2")).thenReturn(Optional.of(user2)); | ||
|
||
var response = (AddUserResponseDTO) addUsersToOrganisationService.addUserToOrganisation(organisationId, | ||
orgRequest, authenticatedUser); | ||
|
||
assertEquals("success", response.status()); | ||
assertEquals("Users added to organisation", response.message()); | ||
assertEquals(organisationId, response.organization_id()); | ||
assertEquals(List.of("user1", "user2"), response.users_added_to_organisation()); | ||
assertEquals(200, response.status_code()); | ||
|
||
verify(organisationRepository).findById(organisationId); | ||
verify(authenticatedUser).getPrincipal(); | ||
verify(userRepository).findById("user1"); | ||
verify(userRepository).findById("user2"); | ||
verify(organisationRepository).save(organisation); | ||
verifyNoMoreInteractions(organisationRepository); | ||
verifyNoMoreInteractions(authenticatedUser); | ||
verifyNoMoreInteractions(userRepository); | ||
} | ||
} |