Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
ID-1714: Admin-API
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasre authored Apr 29, 2022
1 parent cedd2b2 commit d2f91e5
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 59 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

@Slf4j
@ControllerAdvice("no.idporten.im.api")
public class IdentityManagementApiExceptionHandler {
public class ImApiExceptionHandler {

@ExceptionHandler(IdentityManagementApiException.class)
public ResponseEntity<ErrorResponse> handleIMApiException(IdentityManagementApiException e) {
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/no/idporten/im/api/SearchRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotEmpty;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SearchRequest {

@NotEmpty
@JsonProperty("person_identifier")
private String personIdentifier;

@JsonProperty("email")
private String email;

@JsonProperty("mobile")
private String mobile;


}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package no.idporten.im.api.status;
package no.idporten.im.api.admin;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
Expand All @@ -8,14 +8,14 @@

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ChangePersonIdentifierRequest {
public class ChangeIdentifierRequest {

@NotEmpty
@JsonProperty("from_person_identifier")
private String fromPersonIdentifier;
@JsonProperty("old_person_identifier")
private String oldPersonIdentifier;

@NotEmpty
@JsonProperty("to_person_identifier")
private String toPersonIdentifier;
@JsonProperty("new_person_identifier")
private String newPersonIdentifier;

}
138 changes: 138 additions & 0 deletions src/main/java/no/idporten/im/api/admin/ImApiAdminController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package no.idporten.im.api.admin;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import no.idporten.im.IdentityManagementApiException;
import no.idporten.im.api.SearchRequest;
import no.idporten.im.api.UserResource;
import no.idporten.im.spi.IDPortenIdentityManagementUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@Tag(name = "admin-api", description = "User Service Admin API")
@ApiResponses(value = {
@ApiResponse(responseCode = "400", description = "Invalid request", content = @Content(examples = {
@ExampleObject(description = "Error response", value = ImApiAdminController.errorResponseExample)
})),
@ApiResponse(responseCode = "500", description = "Server error", content = @Content(examples = {
@ExampleObject(description = "Error response", value = ImApiAdminController.errorResponseExample)
}))
})
@RestController
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@ConditionalOnBean(type = "no.idporten.im.spi.IDPortenIdentityManagementUserService")
public class ImApiAdminController {

public static final String errorResponseExample = "{\"error\": \"error code\", \"error_description\": \"description of the error\"}";

private final IDPortenIdentityManagementUserService identityManagementUserService;

@Autowired
public ImApiAdminController(IDPortenIdentityManagementUserService identityManagementUserService) {
this.identityManagementUserService = identityManagementUserService;
}

/**
* Search for a user.
*
* @param searchRequest search request
* @return list of found users
*/
@Operation(
summary = "Search for users",
description = "Search for users using external references",
tags = {"admin-api"},
responses = {
@ApiResponse(responseCode = "200", description = "Empty list if no user's are found")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "List of users. Empty list if no users are found")
})
@PostMapping(path = "/im/v1/users/.search", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<UserResource>> searchUser(@Valid @RequestBody SearchRequest searchRequest) {
return ResponseEntity.ok(identityManagementUserService.searchForUser(searchRequest.getPersonIdentifier()));
}

@Operation(
summary = "Retrieve a user",
description = "Retrieve a user by internal id",
tags = {"admin-api"},
parameters = {
@Parameter(in = ParameterIn.PATH, name = "id", required = true, description = "User id")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "User is found"),
@ApiResponse(responseCode = "404", description = "User is not found", content = @Content(examples = {
@ExampleObject(description = "Error response", value = errorResponseExample)
}))
})
@GetMapping(path = "/im/v1/users/{id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserResource> retrieveUser(@PathVariable("id") String id) {
UserResource userResource = identityManagementUserService.lookup(id);
if (userResource == null) {
throw new IdentityManagementApiException("user_not_found", "User not found", HttpStatus.NOT_FOUND);
}
return ResponseEntity.ok(userResource);
}

@Operation(
summary = "Update attributes for a user",
description = "Update user attributes",
tags = {"admin-api"},
parameters = {
@Parameter(in = ParameterIn.PATH, name = "id", required = true, description = "User id")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "User is updated"),
@ApiResponse(responseCode = "404", description = "User is not found")
})
@PatchMapping(path = "/im/v1/users/{id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserResource> updateUserAttributes(@PathVariable("id") String id,
@RequestBody @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Updated attributes", content = @Content(examples = {
@ExampleObject(value = "{\"attribute1\": \"value1\", \"attribute2\": \"value2\"}")
})) UpdateAttributesRequest request) {
return ResponseEntity.ok(identityManagementUserService.updateUserAttributes(id, request));
}

@Operation(
summary = "Update status for a user",
description = "Update user status",
tags = {"admin-api"},
parameters = {
@Parameter(in = ParameterIn.PATH, name = "id", required = true, description = "User id")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "User status is updated"),
@ApiResponse(responseCode = "404", description = "User is not found")
})
@PutMapping(path = "/im/v1/users/{id}/status", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserResource> updateUserStatus(@PathVariable("id") String id, @RequestBody UpdateStatusRequest request) {
return ResponseEntity.ok(identityManagementUserService.updateUserStatus(id, request));
}

@Operation(summary = "Change user identifier", description = "Change user identifier", tags = {"admin-api"})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "User identifier is updated"),
@ApiResponse(responseCode = "404", description = "User is not found")
})
@PutMapping(path = "/im/v1/users/.change-identifier", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserResource> changeIdentifier(@RequestBody ChangeIdentifierRequest request) {
return ResponseEntity.ok(identityManagementUserService.changePersonIdentifier(request));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package no.idporten.im.api.admin;

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class UpdateAttributesRequest {

@JsonIgnore
private Map<String, Object> _attributes = new HashMap<>();

@JsonAnySetter
public void setAttribute(String name, Object value) {
_attributes.put(name, value);
}

@JsonIgnore
public Object getAttribute(String name) {
Objects.requireNonNull(name);
return _attributes.get(name);
}

@JsonIgnore
public String getStringAttribute(String name) {
return (String) getAttribute(name);
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package no.idporten.im.api.status;
package no.idporten.im.api.admin;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import javax.validation.constraints.NotEmpty;

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class UpdateUserStatusRequest {
public class UpdateStatusRequest {

@NotEmpty
@JsonProperty("closed_code")
private String closedCode;

Expand Down
23 changes: 20 additions & 3 deletions src/main/java/no/idporten/im/api/login/ImApiLoginController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package no.idporten.im.api.login;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import no.idporten.im.api.UserResource;
import no.idporten.im.api.SearchRequest;
Expand All @@ -21,6 +25,7 @@
/**
* API for checking user status, creating user at first login, and updating logins.
*/
@Tag(name = "login-api", description = "API for login services")
@Slf4j
@RestController
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
Expand All @@ -35,12 +40,22 @@ public ImApiLoginController(IDPortenIdentityManagementUserService identityManage
}

/**
* Search for a user by person identifier
* Search for a user.
*
* @param searchRequest search request
* @return list of found users
*/
@PostMapping(path = "/im/v1/login/users/search", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(
summary = "Search for users",
description = "Search for users using external references",
tags = {"login-api"},
responses = {
@ApiResponse(responseCode = "200", description = "Empty list if no user's are found")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "List of users. Empty list if no users are found")
})
@PostMapping(path = "/im/v1/login/users/.search", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<UserResource>> searchUser(@Valid @RequestBody SearchRequest searchRequest) {
return ResponseEntity.ok(identityManagementUserService.searchForUser(searchRequest.getPersonIdentifier()));
}
Expand All @@ -51,9 +66,10 @@ public ResponseEntity<List<UserResource>> searchUser(@Valid @RequestBody SearchR
* @param request new user
* @return created user
*/
@Operation(summary = "Create a new user", description = "Create a new user", tags = {"login-api"})
@PostMapping(path = "/im/v1/login/users/", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserResource> createUser(@Valid @RequestBody CreateUserRequest request) {
return ResponseEntity.ok(identityManagementUserService.createUserOnFirstLogin(request));
return ResponseEntity.ok(identityManagementUserService.createUser(request));
}

/**
Expand All @@ -63,6 +79,7 @@ public ResponseEntity<UserResource> createUser(@Valid @RequestBody CreateUserReq
* @param request new user login
* @return updates user
*/
@Operation(summary = "Update user logins", description = "Update user logins with a new login", tags = {"login-api"})
@PostMapping(path = "/im/v1/login/users/{id}/logins", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserResource> updateUserLogins(@PathVariable("id") String userId, @Valid @RequestBody UpdateUserLoginRequest request) {
return ResponseEntity.ok(identityManagementUserService.updateUserLogins(userId, request));
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@


import no.idporten.im.api.*;
import no.idporten.im.api.admin.UpdateAttributesRequest;
import no.idporten.im.api.login.CreateUserRequest;
import no.idporten.im.api.login.UpdateUserLoginRequest;
import no.idporten.im.api.status.ChangePersonIdentifierRequest;
import no.idporten.im.api.status.UpdateUserStatusRequest;
import no.idporten.im.api.admin.ChangeIdentifierRequest;
import no.idporten.im.api.admin.UpdateStatusRequest;

import java.util.List;

Expand All @@ -19,11 +20,12 @@ public interface IDPortenIdentityManagementUserService {
List<UserResource> searchForUser(String pid);

// Login API
UserResource createUserOnFirstLogin(CreateUserRequest request);
UserResource createUser(CreateUserRequest request);
UserResource updateUserLogins(String id, UpdateUserLoginRequest request);

// User status API
UserResource updateUserStatus(String id, UpdateUserStatusRequest request);
UserResource changePersonIdentifier(ChangePersonIdentifierRequest request);
// User admin API
UserResource updateUserAttributes(String id, UpdateAttributesRequest request);
UserResource updateUserStatus(String id, UpdateStatusRequest request);
UserResource changePersonIdentifier(ChangeIdentifierRequest request);

}

0 comments on commit d2f91e5

Please sign in to comment.