Skip to content

Commit 304088f

Browse files
committed
Merge branch 'main' into health_status
2 parents d5ce385 + a7dec38 commit 304088f

File tree

12 files changed

+339
-43
lines changed

12 files changed

+339
-43
lines changed

Diff for: java/claim/src/main/java/dev/sunbirdrc/claim/contants/AttributeNames.java

+3
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ public class AttributeNames {
99
public static final String ENTITY = "ENTITY";
1010
public static final String LOWERCASE_ENTITY = "entity";;
1111
public static final String ATTESTOR_INFO = "attestorInfo";
12+
public static final String CONTENT = "content";
13+
public static final String TOTAL_PAGES = "totalPages";
14+
public static final String TOTAL_ELEMENTS = "totalElements";
1215
}

Diff for: java/claim/src/main/java/dev/sunbirdrc/claim/controller/ClaimsController.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
import org.slf4j.Logger;
1010
import org.slf4j.LoggerFactory;
1111
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.data.domain.Pageable;
13+
import org.springframework.data.web.PagedResourcesAssembler;
1214
import org.springframework.http.HttpHeaders;
1315
import org.springframework.http.HttpStatus;
1416
import org.springframework.http.ResponseEntity;
1517
import org.springframework.stereotype.Controller;
1618
import org.springframework.web.bind.annotation.*;
1719

18-
import java.util.List;
20+
import java.util.Map;
1921
import java.util.Optional;
2022

2123
import static dev.sunbirdrc.claim.contants.AttributeNames.ATTESTOR_INFO;
@@ -35,11 +37,11 @@ public ClaimsController(ClaimService claimService, ClaimsAuthorizer claimsAuthor
3537
}
3638

3739
@RequestMapping(value = "/api/v1/getClaims", method = RequestMethod.POST)
38-
public ResponseEntity<List<Claim>> getClaims(@RequestHeader HttpHeaders headers,
39-
@RequestBody JsonNode requestBody) {
40+
public ResponseEntity<Map<String, Object>> getClaims(@RequestHeader HttpHeaders headers,
41+
@RequestBody JsonNode requestBody, Pageable pageable) {
4042
String entity = requestBody.get(LOWERCASE_ENTITY).asText();
4143
JsonNode attestorNode = requestBody.get(ATTESTOR_INFO);
42-
List<Claim> claims = claimService.findClaimsForAttestor(entity, attestorNode);
44+
Map<String, Object> claims = claimService.findClaimsForAttestor(entity, attestorNode, pageable);
4345
return new ResponseEntity<>(claims, HttpStatus.OK);
4446
}
4547

Diff for: java/claim/src/main/java/dev/sunbirdrc/claim/service/ClaimService.java

+19-7
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@
1414
import org.slf4j.Logger;
1515
import org.slf4j.LoggerFactory;
1616
import org.springframework.beans.factory.annotation.Autowired;
17+
import org.springframework.data.domain.Pageable;
1718
import org.springframework.stereotype.Service;
1819

19-
import java.util.Date;
20-
import java.util.List;
21-
import java.util.Optional;
20+
import java.util.*;
2221
import java.util.stream.Collectors;
2322

24-
import static dev.sunbirdrc.claim.contants.AttributeNames.ATTESTOR_INFO;
25-
import static dev.sunbirdrc.claim.contants.AttributeNames.NOTES;
23+
import static dev.sunbirdrc.claim.contants.AttributeNames.*;
2624
import static dev.sunbirdrc.claim.contants.ErrorMessages.*;
2725
import static dev.sunbirdrc.registry.middleware.util.Constants.USER_ID;
2826

@@ -55,14 +53,28 @@ public List<Claim> findAll() {
5553
return claimRepository.findAll();
5654
}
5755

58-
public List<Claim> findClaimsForAttestor(String entity, JsonNode attestorNode) {
56+
public Map<String, Object> findClaimsForAttestor(String entity, JsonNode attestorNode, Pageable pageable) {
5957
List<Claim> claims = claimRepository.findByAttestorEntity(entity);
6058
logger.info("Found {} claims to process", claims.size());
61-
return claims.stream()
59+
List<Claim> claimsToAttestor = claims.stream()
6260
.filter(claim -> claimsAuthorizer.isAuthorizedAttestor(claim, attestorNode))
6361
.collect(Collectors.toList());
62+
return toMap(claimsToAttestor, pageable);
6463
}
6564

65+
private Map<String, Object> toMap(List<Claim> claims, Pageable pageable) {
66+
Map<String, Object> response = new HashMap<>();
67+
response.put(TOTAL_PAGES, (int)(Math.ceil(claims.size() * 1.0/pageable.getPageSize())));
68+
response.put(TOTAL_ELEMENTS, claims.size());
69+
int start = (int) pageable.getOffset();
70+
int end = Math.min((start + pageable.getPageSize()), claims.size());
71+
if(start > claims.size()) {
72+
response.put(CONTENT, new ArrayList<>());
73+
return response;
74+
}
75+
response.put(CONTENT, claims.subList(start, end));
76+
return response;
77+
}
6678
public Claim attestClaim(String claimId, JsonNode requestBody) {
6779
Claim claim = findById(claimId).orElseThrow(() -> new ResourceNotFoundException(CLAIM_NOT_FOUND));
6880
logger.info("Processing claim {}", claim.toString());

Diff for: java/claim/src/test/java/dev/sunbirdrc/claim/service/ClaimServiceTest.java

+55-7
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
import org.junit.runner.RunWith;
1717
import org.mockito.Mock;
1818
import org.mockito.junit.MockitoJUnitRunner;
19+
import org.springframework.data.domain.Page;
20+
import org.springframework.data.domain.PageImpl;
21+
import org.springframework.data.domain.PageRequest;
22+
import org.springframework.data.domain.Pageable;
1923

20-
import java.util.Arrays;
21-
import java.util.List;
22-
import java.util.Optional;
24+
import java.util.*;
2325

24-
import static dev.sunbirdrc.claim.contants.AttributeNames.ATTESTOR_INFO;
25-
import static dev.sunbirdrc.claim.contants.AttributeNames.NOTES;
26+
import static dev.sunbirdrc.claim.contants.AttributeNames.*;
2627
import static dev.sunbirdrc.claim.model.ClaimStatus.CLOSED;
2728
import static dev.sunbirdrc.claim.model.ClaimStatus.OPEN;
2829
import static org.junit.Assert.assertEquals;
@@ -52,15 +53,62 @@ public void shouldReturnOnlyAuthorizedClaims() {
5253
Claim claim2 = getClaim("2");
5354
Claim claim3 = getClaim("3");
5455
List<Claim> allClaimsForEntity = Arrays.asList(claim1, claim2, claim3);
56+
Pageable pageable = PageRequest.of(0, 3);
5557
String entity = "Teacher";
5658
JsonNode dummyNode = new ObjectMapper().nullNode();
5759
when(claimRepository.findByAttestorEntity(entity)).thenReturn(allClaimsForEntity);
5860
when(claimsAuthorizer.isAuthorizedAttestor(claim1, dummyNode)).thenReturn(true);
5961
when(claimsAuthorizer.isAuthorizedAttestor(claim2, dummyNode)).thenReturn(false);
6062
when(claimsAuthorizer.isAuthorizedAttestor(claim3, dummyNode)).thenReturn(true);
63+
Map<String, Object> actualClaims = new HashMap<>();
64+
actualClaims.put(CONTENT, Arrays.asList(claim1, claim3));
65+
actualClaims.put(TOTAL_PAGES, 1);
66+
actualClaims.put(TOTAL_ELEMENTS, 2);
67+
assertEquals(claimService.findClaimsForAttestor(entity, dummyNode, pageable), actualClaims);
68+
}
6169

62-
List<Claim> actualClaims = Arrays.asList(claim1, claim3);
63-
assertEquals(claimService.findClaimsForAttestor(entity, dummyNode), actualClaims);
70+
@Test
71+
public void shouldReturnAppropriateClaimsInPaginationFormat() {
72+
Claim claim1 = getClaim("1");
73+
Claim claim2 = getClaim("2");
74+
Claim claim3 = getClaim("3");
75+
Claim claim4 = getClaim("4");
76+
List<Claim> allClaimsForEntity = Arrays.asList(claim1, claim2, claim3, claim4);
77+
Pageable pageable = PageRequest.of(1, 2);
78+
String entity = "Teacher";
79+
JsonNode dummyNode = new ObjectMapper().nullNode();
80+
when(claimRepository.findByAttestorEntity(entity)).thenReturn(allClaimsForEntity);
81+
when(claimsAuthorizer.isAuthorizedAttestor(claim1, dummyNode)).thenReturn(true);
82+
when(claimsAuthorizer.isAuthorizedAttestor(claim2, dummyNode)).thenReturn(true);
83+
when(claimsAuthorizer.isAuthorizedAttestor(claim3, dummyNode)).thenReturn(true);
84+
when(claimsAuthorizer.isAuthorizedAttestor(claim4, dummyNode)).thenReturn(true);
85+
Map<String, Object> actualClaims = new HashMap<>();
86+
actualClaims.put(CONTENT, Arrays.asList(claim3, claim4));
87+
actualClaims.put(TOTAL_PAGES, 2);
88+
actualClaims.put(TOTAL_ELEMENTS, 4);
89+
assertEquals(claimService.findClaimsForAttestor(entity, dummyNode, pageable), actualClaims);
90+
}
91+
92+
@Test
93+
public void shouldReturnEmptyClaimsIfOffsetGreaterThanClaimSize() {
94+
Claim claim1 = getClaim("1");
95+
Claim claim2 = getClaim("2");
96+
Claim claim3 = getClaim("3");
97+
Claim claim4 = getClaim("4");
98+
List<Claim> allClaimsForEntity = Arrays.asList(claim1, claim2, claim3, claim4);
99+
Pageable pageable = PageRequest.of(2, 2);
100+
String entity = "Teacher";
101+
JsonNode dummyNode = new ObjectMapper().nullNode();
102+
when(claimRepository.findByAttestorEntity(entity)).thenReturn(allClaimsForEntity);
103+
when(claimsAuthorizer.isAuthorizedAttestor(claim1, dummyNode)).thenReturn(true);
104+
when(claimsAuthorizer.isAuthorizedAttestor(claim2, dummyNode)).thenReturn(true);
105+
when(claimsAuthorizer.isAuthorizedAttestor(claim3, dummyNode)).thenReturn(true);
106+
when(claimsAuthorizer.isAuthorizedAttestor(claim4, dummyNode)).thenReturn(true);
107+
Map<String, Object> actualClaims = new HashMap<>();
108+
actualClaims.put(CONTENT, new ArrayList<>());
109+
actualClaims.put(TOTAL_PAGES, 2);
110+
actualClaims.put(TOTAL_ELEMENTS, 4);
111+
assertEquals(claimService.findClaimsForAttestor(entity, dummyNode, pageable), actualClaims);
64112
}
65113

66114
@Test(expected = ResourceNotFoundException.class)

Diff for: java/middleware/registry-middleware/keycloak/src/main/java/dev/sunbirdrc/keycloak/KeycloakAdminUtil.java

+26-19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import dev.sunbirdrc.pojos.ComponentHealthInfo;
44
import dev.sunbirdrc.pojos.HealthIndicator;
5+
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
56
import org.keycloak.OAuth2Constants;
67
import org.keycloak.admin.client.Keycloak;
78
import org.keycloak.admin.client.KeycloakBuilder;
@@ -53,7 +54,8 @@ public KeycloakAdminUtil(
5354
@Value("${keycloak-user.default-password:}") String defaultPassword,
5455
@Value("${keycloak-user.set-default-password:false}") boolean setDefaultPassword,
5556
@Value("${keycloak.auth-server-url:}") String authURL,
56-
@Value("${keycloak-user.email-actions:}") List<String> emailActions) {
57+
@Value("${keycloak-user.email-actions:}") List<String> emailActions,
58+
@Value("${httpConnection.maxConnections:5}") int httpMaxConnections) {
5759
this.authenticationEnabled = authenticationEnabled;
5860
this.realm = realm;
5961
this.adminClientSecret = adminClientSecret;
@@ -62,16 +64,20 @@ public KeycloakAdminUtil(
6264
this.defaultPassword = defaultPassword;
6365
this.setDefaultPassword = setDefaultPassword;
6466
this.emailActions = emailActions;
65-
this.keycloak = buildKeycloak();
67+
this.keycloak = buildKeycloak(httpMaxConnections);
6668
}
6769

68-
private Keycloak buildKeycloak() {
70+
private Keycloak buildKeycloak(int httpMaxConnections) {
6971
return KeycloakBuilder.builder()
7072
.serverUrl(authURL)
7173
.realm(realm)
7274
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
7375
.clientId(adminClientId)
7476
.clientSecret(adminClientSecret)
77+
.resteasyClient(
78+
new ResteasyClientBuilder()
79+
.connectionPoolSize(httpMaxConnections).build()
80+
)
7581
.build();
7682
}
7783

@@ -81,22 +87,23 @@ public String createUser(String entityName, String userName, String email, Strin
8187
GroupRepresentation entityGroup = createGroupRepresentation(entityName);
8288
keycloak.realm(realm).groups().add(entityGroup);
8389
UsersResource usersResource = keycloak.realm(realm).users();
84-
Response response = usersResource.create(newUser);
85-
if (response.getStatus() == 201) {
86-
logger.info("Response | Status: {} | Status Info: {}", response.getStatus(), response.getStatusInfo());
87-
logger.info("User ID path" + response.getLocation().getPath());
88-
String userID = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");
89-
logger.info("User ID : " + userID);
90-
if(!emailActions.isEmpty())
91-
usersResource.get(userID).executeActionsEmail(emailActions);
92-
return userID;
93-
} else if (response.getStatus() == 409) {
94-
logger.info("UserID: {} exists", userName);
95-
return updateExistingUserAttributes(entityName, userName, email, mobile);
96-
} else if (response.getStatus() == 500) {
97-
throw new OwnerCreationException("Keycloak user creation error");
98-
}else {
99-
throw new OwnerCreationException("Username already invited / registered");
90+
try (Response response = usersResource.create(newUser)) {
91+
if (response.getStatus() == 201) {
92+
logger.info("Response | Status: {} | Status Info: {}", response.getStatus(), response.getStatusInfo());
93+
logger.info("User ID path" + response.getLocation().getPath());
94+
String userID = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");
95+
logger.info("User ID : " + userID);
96+
if (!emailActions.isEmpty())
97+
usersResource.get(userID).executeActionsEmail(emailActions);
98+
return userID;
99+
} else if (response.getStatus() == 409) {
100+
logger.info("UserID: {} exists", userName);
101+
return updateExistingUserAttributes(entityName, userName, email, mobile);
102+
} else if (response.getStatus() == 500) {
103+
throw new OwnerCreationException("Keycloak user creation error");
104+
} else {
105+
throw new OwnerCreationException("Username already invited / registered");
106+
}
100107
}
101108
}
102109

Diff for: java/registry/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,10 @@
420420
<version>1.6-beta-2</version>
421421
<scope>test</scope>
422422
</dependency>
423+
<dependency>
424+
<groupId>org.springframework.data</groupId>
425+
<artifactId>spring-data-commons</artifactId>
426+
</dependency>
423427

424428
</dependencies>
425429

Diff for: java/registry/src/main/java/dev/sunbirdrc/registry/controller/RegistryClaimsController.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.jetbrains.annotations.NotNull;
1717
import org.slf4j.Logger;
1818
import org.slf4j.LoggerFactory;
19+
import org.springframework.data.domain.Pageable;
1920
import org.springframework.http.HttpStatus;
2021
import org.springframework.http.ResponseEntity;
2122
import org.springframework.web.bind.annotation.*;
@@ -42,11 +43,11 @@ public RegistryClaimsController(ClaimRequestClient claimRequestClient,
4243
}
4344

4445
@RequestMapping(value = "/api/v1/{entityName}/claims", method = RequestMethod.GET)
45-
public ResponseEntity<Object> getAllClaims(@PathVariable String entityName,
46+
public ResponseEntity<Object> getAllClaims(@PathVariable String entityName, Pageable pageable,
4647
HttpServletRequest request) {
4748
try {
4849
JsonNode result = registryHelper.getRequestedUserDetails(request, entityName);
49-
JsonNode claims = claimRequestClient.getClaims(result.get(entityName).get(0), entityName);
50+
JsonNode claims = claimRequestClient.getClaims(result.get(entityName).get(0), pageable, entityName);
5051
logger.info("Received {} claims", claims.size());
5152
return new ResponseEntity<>(claims, HttpStatus.OK);
5253
} catch (Exception e) {

Diff for: java/registry/src/main/java/dev/sunbirdrc/registry/controller/RegistryEntityController.java

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.sunbirdrc.registry.controller;
22

3+
import com.fasterxml.jackson.core.JsonProcessingException;
34
import com.fasterxml.jackson.databind.JsonNode;
45
import com.fasterxml.jackson.databind.node.ArrayNode;
56
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
@@ -10,6 +11,7 @@
1011
import dev.sunbirdrc.pojos.ResponseParams;
1112
import dev.sunbirdrc.registry.dao.NotFoundException;
1213
import dev.sunbirdrc.registry.entities.AttestationPolicy;
14+
import dev.sunbirdrc.registry.exception.AttestationNotFoundException;
1315
import dev.sunbirdrc.registry.exception.RecordNotFoundException;
1416
import dev.sunbirdrc.registry.exception.UnAuthorizedException;
1517
import dev.sunbirdrc.registry.middleware.MiddlewareHaltException;
@@ -115,7 +117,7 @@ public ResponseEntity<Object> deleteEntity(
115117
logger.info("Deleting entityType {} with Id {}", entityName, entityId);
116118
if (registryHelper.doesDeleteRequiresAuthorization(entityName)) {
117119
try {
118-
userId = registryHelper.authorizeDeleteEntity(request, entityName, entityId);
120+
userId = registryHelper.authorize(entityName, entityId, request);
119121
} catch (Exception e) {
120122
return createUnauthorizedExceptionResponse(e);
121123
}
@@ -342,6 +344,20 @@ private String getNotes(JsonNode requestBody) {
342344
return notes;
343345
}
344346

347+
private JsonNode getAttestationNode(String attestationId, JsonNode node) throws AttestationNotFoundException, JsonProcessingException {
348+
Iterator<JsonNode> iterator = node.iterator();
349+
JsonNode attestationNode = null;
350+
while(iterator.hasNext()) {
351+
attestationNode = iterator.next();
352+
if (attestationNode.get(uuidPropertyName).toString().equals(attestationId)) {
353+
break;
354+
}
355+
}
356+
if(attestationNode.get(OSSystemFields._osAttestedData.name()) == null) throw new AttestationNotFoundException();
357+
attestationNode = objectMapper.readTree(attestationNode.get(OSSystemFields._osAttestedData.name()).asText());
358+
return attestationNode;
359+
}
360+
345361
@RequestMapping(value = "/partner/api/v1/{entityName}", method = RequestMethod.GET)
346362
public ResponseEntity<Object> getEntityWithConsent(
347363
@PathVariable String entityName,
@@ -659,4 +675,28 @@ public ResponseEntity<Object> getSignedEntityByToken(@PathVariable String entity
659675
}
660676
return new ResponseEntity<>(response, HttpStatus.OK);
661677
}
678+
679+
@GetMapping(value = "/api/v1/{entityName}/{entityId}/attestation/{attestationName}/{attestationId}",
680+
produces = {MediaType.APPLICATION_PDF_VALUE, MediaType.TEXT_HTML_VALUE, Constants.SVG_MEDIA_TYPE})
681+
public ResponseEntity<Object> getAttestationCertificate(HttpServletRequest request, @PathVariable String entityName, @PathVariable String entityId,
682+
@PathVariable String attestationName, @PathVariable String attestationId) {
683+
try {
684+
String readerUserId = getUserId(entityName, request);
685+
JsonNode node = registryHelper.readEntity(readerUserId, entityName, entityId, false, null, false)
686+
.get(entityName).get(attestationName);
687+
JsonNode attestationNode = getAttestationNode(attestationId, node);
688+
return new ResponseEntity<>(certificateService.getCertificate(attestationNode,
689+
entityName,
690+
entityId,
691+
request.getHeader(HttpHeaders.ACCEPT),
692+
getTemplateUrlFromRequest(request, entityName)
693+
), HttpStatus.OK);
694+
} catch (AttestationNotFoundException e) {
695+
logger.error(e.getMessage());
696+
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
697+
} catch (Exception e) {
698+
e.printStackTrace();
699+
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
700+
}
701+
}
662702
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package dev.sunbirdrc.registry.exception;
2+
3+
public class AttestationNotFoundException extends Exception {
4+
5+
public AttestationNotFoundException() {
6+
super();
7+
}
8+
}

Diff for: java/registry/src/main/java/dev/sunbirdrc/registry/helper/RegistryHelper.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -812,9 +812,16 @@ private JsonNode getUserInfoFromRegistry(HttpServletRequest request, String enti
812812

813813
public String authorize(String entityName, String entityId, HttpServletRequest request) throws Exception {
814814
String userIdFromRequest = getUserId(request, entityName);
815+
if (getManageRoles(entityName).size() > 0) {
816+
try {
817+
return authorizeManageEntity(request, entityName);
818+
} catch (Exception e) {
819+
logger.error("Exception while authorizing roles", e);
820+
}
821+
}
815822
JsonNode response = readEntity(userIdFromRequest, entityName, entityId, false, null, false);
816823
JsonNode entityFromDB = response.get(entityName);
817-
if (!isOwner(entityFromDB, userIdFromRequest)) {
824+
if (doesEntityContainOwnershipAttributes(entityName) && !isOwner(entityFromDB, userIdFromRequest)) {
818825
throw new Exception(UNAUTHORIZED_OPERATION_MESSAGE);
819826
}
820827
return userIdFromRequest;

0 commit comments

Comments
 (0)