Skip to content

Commit

Permalink
feat(User): Add new endpoints to get/update requesting user profile
Browse files Browse the repository at this point in the history
  • Loading branch information
hoangnt2 committed Jan 9, 2024
1 parent e6ccf98 commit bcd600c
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 2 deletions.
33 changes: 32 additions & 1 deletion rest/resource-server/src/docs/asciidoc/users.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,35 @@ include::{snippets}/should_document_create_user/response-fields.adoc[]
include::{snippets}/should_document_create_user/curl-request.adoc[]

===== Example response
include::{snippets}/should_document_create_user/http-response.adoc[]
include::{snippets}/should_document_create_user/http-response.adoc[]

[[resources-user-get-profile]]
==== Get requesting user's profile

A `GET` request will get requesting user's profile.

===== Response structure
include::{snippets}/should_document_get_user_profile/response-fields.adoc[]

===== Example request
include::{snippets}/should_document_get_user_profile/curl-request.adoc[]

===== Example response
include::{snippets}/should_document_get_user_profile/http-response.adoc[]

[[resources-user-update-profile]]
==== Update requesting user's profile

A `PATCH` request will update requesting user's profile.

===== Request structure
include::{snippets}/should_document_update_user_profile/request-fields.adoc[]

===== Response structure
include::{snippets}/should_document_update_user_profile/response-fields.adoc[]

===== Example request
include::{snippets}/should_document_update_user_profile/curl-request.adoc[]

===== Example response
include::{snippets}/should_document_update_user_profile/http-response.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,6 @@ static abstract class EmbeddedProjectMixin extends ProjectMixin {
"id",
"revision",
"setPassword",
"wantsMailNotification",
"setWantsMailNotification",
"setId",
"setRevision",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,32 @@ public Package updatePackage(Package packageToUpdate, Package requestBodyPackage
return packageToUpdate;
}

public User updateUserProfile(User userToUpdate, Map<String, Object> requestBodyUser, ImmutableSet<User._Fields> setOfUserProfileFields) {
for (User._Fields field : setOfUserProfileFields) {
Object fieldValue = requestBodyUser.get(field.getFieldName());
if (fieldValue != null) {
switch (field) {
case NOTIFICATION_PREFERENCES:
Object wantNotification = requestBodyUser.get(User._Fields.WANTS_MAIL_NOTIFICATION.getFieldName());
if (wantNotification == null) {
if (userToUpdate.isWantsMailNotification()) {
userToUpdate.setFieldValue(field, fieldValue);
}
} else {
if (Boolean.TRUE.equals(wantNotification)) {
userToUpdate.setFieldValue(field, fieldValue);
}
}
break;
default:
userToUpdate.setFieldValue(field, fieldValue);
break;
}
}
}
return userToUpdate;
}

public Component convertToComponent(ComponentDTO componentDTO) {
Component component = new Component();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,9 @@ private UserService.Iface getThriftUserClient() throws TTransportException {
TProtocol protocol = new TCompactProtocol(thriftClient);
return new UserService.Client(protocol);
}

public void updateUser(User sw360User) throws TException {
UserService.Iface sw360UserClient = getThriftUserClient();
sw360UserClient.updateUser(sw360User);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
package org.eclipse.sw360.rest.resourceserver.user;

import com.google.common.collect.ImmutableSet;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.Operation;
Expand Down Expand Up @@ -47,6 +48,7 @@
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;

Expand All @@ -70,6 +72,10 @@ public class UserController implements RepresentationModelProcessor<RepositoryLi
@NonNull
private final RestControllerHelper restControllerHelper;

private static final ImmutableSet<User._Fields> setOfUserProfileFields = ImmutableSet.<User._Fields>builder()
.add(User._Fields.WANTS_MAIL_NOTIFICATION)
.add(User._Fields.NOTIFICATION_PREFERENCES).build();

@Operation(
summary = "List all of the service's users.",
description = "List all of the service's users.",
Expand Down Expand Up @@ -165,6 +171,33 @@ public ResponseEntity<EntityModel<User>> createUser(
return ResponseEntity.created(location).body(halResource);
}

@Operation(
summary = "Get user's profile.",
description = "Get user's profile.",
tags = {"Users"}
)
@GetMapping(value = USERS_URL + "/profile")
public ResponseEntity<HalResource<User>> getUserProfile() {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
HalResource<User> halUserResource = new HalResource<>(sw360User);
return ResponseEntity.ok(halUserResource);
}

@Operation(
summary = "Update user's profile.",
description = "Update user's profile.",
tags = {"Users"}
)
@PatchMapping(value = USERS_URL + "/profile")
public ResponseEntity<HalResource<User>> updateUserProfile(
@RequestBody Map<String, Object> userProfile
) throws TException {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
sw360User = restControllerHelper.updateUserProfile(sw360User, userProfile, setOfUserProfileFields);
userService.updateUser(sw360User);
HalResource<User> halUserResource = new HalResource<>(sw360User);
return ResponseEntity.ok(halUserResource);
}
@Override
public RepositoryLinksResource process(RepositoryLinksResource resource) {
resource.add(linkTo(UserController.class).slash("api/users").withRel("users"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ public void should_document_get_components_with_all_details() throws Exception {

subsectionWithPath("_embedded.sw360:components.[]homepage").description("The homepage url of the component").optional(),
subsectionWithPath("_embedded.sw360:components.[]_embedded.createdBy.email").description("The email of user who created this Component").optional(),
subsectionWithPath("_embedded.sw360:components.[]_embedded.createdBy.wantsMailNotification").description("Does user want to be notified via mail?").optional(),
subsectionWithPath("_embedded.sw360:components.[]_embedded.createdBy.deactivated").description("The user is activated or deactivated").optional(),
subsectionWithPath("_embedded.sw360:components.[]_embedded.createdBy._links").description("Self <<resources-index-links,Links>> to Component resource").optional(),
subsectionWithPath("_embedded.sw360:components.[]_embedded.sw360:attachments.[]filename").description("Attached file name").optional(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
Expand Down Expand Up @@ -71,6 +72,29 @@ public void before() throws TException {
userGroups2.add(UserGroup.SECURITY_ADMIN);
secondaryDepartmentsAndRoles.put("DEPARTMENT1", userGroups1);
secondaryDepartmentsAndRoles.put("DEPARTMENT2", userGroups2);

Map<String, Boolean> notificationPreferences = new HashMap<>();
notificationPreferences.put("releaseCONTRIBUTORS", true);
notificationPreferences.put("componentCREATED_BY", true);
notificationPreferences.put("releaseCREATED_BY", true);
notificationPreferences.put("moderationREQUESTING_USER", true);
notificationPreferences.put("projectPROJECT_OWNER", true);
notificationPreferences.put("moderationMODERATORS", true);
notificationPreferences.put("releaseSUBSCRIBERS", true);
notificationPreferences.put("componentMODERATORS", true);
notificationPreferences.put("projectMODERATORS", true);
notificationPreferences.put("projectROLES", true);
notificationPreferences.put("releaseROLES", true);
notificationPreferences.put("componentROLES", true);
notificationPreferences.put("projectLEAD_ARCHITECT", true);
notificationPreferences.put("componentCOMPONENT_OWNER", true);
notificationPreferences.put("projectSECURITY_RESPONSIBLES", true);
notificationPreferences.put("clearingREQUESTING_USER", true);
notificationPreferences.put("projectCONTRIBUTORS", true);
notificationPreferences.put("componentSUBSCRIBERS", true);
notificationPreferences.put("projectPROJECT_RESPONSIBLE", true);
notificationPreferences.put("releaseMODERATORS", true);

user = new User();
user.setEmail("[email protected]");
user.setId("4784587578e87989");
Expand All @@ -82,6 +106,7 @@ public void before() throws TException {
user.setWantsMailNotification(true);
user.setFormerEmailAddresses(Sets.newHashSet("[email protected]"));
user.setSecondaryDepartmentsAndRoles(secondaryDepartmentsAndRoles);
user.setNotificationPreferences(notificationPreferences);
userList.add(user);

given(this.userServiceMock.getUserByEmail("[email protected]")).willReturn(user);
Expand All @@ -90,6 +115,7 @@ public void before() throws TException {
when(this.userServiceMock.addUser(any())).then(
invocation -> new User("[email protected]", "DEPARTMENT").setId("1234567890").setFullname("FTest lTest")
.setGivenname("FTest").setLastname("lTest").setUserGroup(UserGroup.USER));
given(this.userServiceMock.getUserByEmailOrExternalId(any())).willReturn(user);

User user2 = new User();
user2.setEmail("[email protected]");
Expand All @@ -104,6 +130,8 @@ public void before() throws TException {
userList.add(user2);

given(this.userServiceMock.getAllUsers()).willReturn(userList);
User userWithTokens = new User("[email protected]", "sw360").setId("123456789");
given(this.userServiceMock.getUserByEmailOrExternalId(any())).willReturn(user);
}

@Test
Expand Down Expand Up @@ -176,6 +204,7 @@ public void should_document_create_user() throws Exception {
subsectionWithPath("givenName").description("The given name of the user"),
subsectionWithPath("lastName").description("The last name of the user"),
subsectionWithPath("deactivated").description("Is user deactivated"),
fieldWithPath("wantsMailNotification").description("Does user want to be notified via mail?"),
subsectionWithPath("_links").description("<<resources-user-get,User>> to user resource")
)));
}
Expand All @@ -201,6 +230,8 @@ public void should_document_get_user_by_id() throws Exception {
subsectionWithPath("secondaryDepartmentsAndRoles").description("The user's secondary departments and roles"),
fieldWithPath("formerEmailAddresses").description("The user's former email addresses"),
fieldWithPath("deactivated").description("Is user deactivated"),
fieldWithPath("wantsMailNotification").description("Does user want to be notified via mail?"),
subsectionWithPath("notificationPreferences").description("User's notification preferences"),
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}
Expand All @@ -226,6 +257,89 @@ public void should_document_get_user() throws Exception {
subsectionWithPath("secondaryDepartmentsAndRoles").description("The user's secondary departments and roles"),
fieldWithPath("formerEmailAddresses").description("The user's former email addresses"),
fieldWithPath("deactivated").description("Is user deactivated"),
fieldWithPath("wantsMailNotification").description("Does user want to be notified via mail?"),
subsectionWithPath("notificationPreferences").description("User's notification preferences"),
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}

@Test
public void should_document_get_user_profile() throws Exception {
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);
mockMvc.perform(get("/api/users/profile")
.header("Authorization", "Bearer " + accessToken)
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk())
.andDo(this.documentationHandler.document(
responseFields(
fieldWithPath("email").description("The user's email"),
fieldWithPath("userGroup").description("The user group, possible values are: " + Arrays.asList(UserGroup.values())),
fieldWithPath("fullName").description("The users's full name"),
fieldWithPath("givenName").description("The user's given name"),
fieldWithPath("lastName").description("The user's last name"),
fieldWithPath("department").description("The user's company department"),
subsectionWithPath("secondaryDepartmentsAndRoles").description("The user's secondary departments and roles"),
fieldWithPath("formerEmailAddresses").description("The user's former email addresses"),
fieldWithPath("deactivated").description("Is user deactivated"),
fieldWithPath("wantsMailNotification").description("Does user want to be notified via mail?"),
subsectionWithPath("notificationPreferences").description("User's notification preferences"),
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}

@Test
public void should_document_update_user_profile() throws Exception {
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);

Map<String, Boolean> notificationPreferences = new HashMap<>();
notificationPreferences.put("releaseCONTRIBUTORS", true);
notificationPreferences.put("componentCREATED_BY", false);
notificationPreferences.put("releaseCREATED_BY", false);
notificationPreferences.put("moderationREQUESTING_USER", false);
notificationPreferences.put("projectPROJECT_OWNER", true);
notificationPreferences.put("moderationMODERATORS", false);
notificationPreferences.put("releaseSUBSCRIBERS", true);
notificationPreferences.put("componentMODERATORS", true);
notificationPreferences.put("projectMODERATORS", false);
notificationPreferences.put("projectROLES", false);
notificationPreferences.put("releaseROLES", true);
notificationPreferences.put("componentROLES", true);
notificationPreferences.put("projectLEAD_ARCHITECT", false);
notificationPreferences.put("componentCOMPONENT_OWNER", true);
notificationPreferences.put("projectSECURITY_RESPONSIBLES", true);
notificationPreferences.put("clearingREQUESTING_USER", true);
notificationPreferences.put("projectCONTRIBUTORS", true);
notificationPreferences.put("componentSUBSCRIBERS", true);
notificationPreferences.put("projectPROJECT_RESPONSIBLE", false);
notificationPreferences.put("releaseMODERATORS", false);

Map<String, Object> updatedProfile = new HashMap<>();
updatedProfile.put("wantsMailNotification", true);
updatedProfile.put("notificationPreferences", notificationPreferences);

mockMvc.perform(patch("/api/users/profile")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaTypes.HAL_JSON)
.content(this.objectMapper.writeValueAsString(updatedProfile))
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk())
.andDo(this.documentationHandler.document(
requestFields(
fieldWithPath("wantsMailNotification").description("Does user want to be notified via mail?"),
subsectionWithPath("notificationPreferences").description("User's notification preferences")
),
responseFields(
fieldWithPath("email").description("The user's email"),
fieldWithPath("userGroup").description("The user group, possible values are: " + Arrays.asList(UserGroup.values())),
fieldWithPath("fullName").description("The users's full name"),
fieldWithPath("givenName").description("The user's given name"),
fieldWithPath("lastName").description("The user's last name"),
fieldWithPath("department").description("The user's company department"),
fieldWithPath("deactivated").description("Is user deactivated"),
subsectionWithPath("secondaryDepartmentsAndRoles").description("The user's secondary departments and roles"),
fieldWithPath("formerEmailAddresses").description("The user's former email addresses"),
fieldWithPath("wantsMailNotification").description("Does user want to be notified via mail?"),
subsectionWithPath("notificationPreferences").description("User's notification preferences"),
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}
Expand Down

0 comments on commit bcd600c

Please sign in to comment.