Skip to content

Commit

Permalink
avniproject/avni-product#1576 | GET /api/approvalStatuses
Browse files Browse the repository at this point in the history
  • Loading branch information
1t5j0y committed Apr 23, 2024
1 parent e73a382 commit d248223
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.avni.server.dao;

import org.avni.server.dao.sync.SyncEntityName;
import org.avni.server.domain.AddressLevel;
import org.avni.server.domain.EntityApprovalStatus;
import org.avni.server.domain.*;
import org.avni.server.framework.security.UserContextHolder;
import org.joda.time.DateTime;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
Expand All @@ -16,10 +16,7 @@
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Repository;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
Expand All @@ -36,6 +33,35 @@ Page<EntityApprovalStatus> findByLastModifiedDateTimeIsBetweenOrderByLastModifie
@Param("now") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Date now,
Pageable pageable);

default Page<EntityApprovalStatus> findEntityApprovalStatuses(EntityApprovalStatusSearchParams searchParams, Pageable pageable) {

Specification specification = lastModifiedBetween(
CHSEntity.toDate(searchParams.getLastModifiedDateTime() != null ? searchParams.getLastModifiedDateTime() : new DateTime("1900-01-01T00:00:00.000Z")),
CHSEntity.toDate(searchParams.getNow() != null ? searchParams.getNow() : new DateTime()));

if (searchParams.getEntityType() != null) {
specification = specification.and(findByEntityTypeSpec(searchParams.getEntityType()));
}
if (searchParams.getEntityTypeUuid() != null) {
specification = specification.and(findByEntityTypeUuidSpec(searchParams.getEntityTypeUuid()));
}

return findAll(specification, pageable);
}

default Specification<EntityApprovalStatus> findByEntityTypeSpec(String entityType) {
Specification<EntityApprovalStatus> spec = (Root<EntityApprovalStatus> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
return cb.and(cb.equal(root.get("entityType"), entityType));
};
return spec;
}

default Specification<EntityApprovalStatus> findByEntityTypeUuidSpec(String entityTypeUuid) {
Specification<EntityApprovalStatus> spec = (Root<EntityApprovalStatus> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
return cb.and(cb.equal(root.get("entityTypeUuid"), entityTypeUuid));
};
return spec;
}
List<EntityApprovalStatus> findByEntityIdAndEntityTypeAndIsVoidedFalse(Long entityId, EntityApprovalStatus.EntityType entityType);
EntityApprovalStatus findFirstByEntityIdAndEntityTypeAndIsVoidedFalseOrderByStatusDateTimeDesc(Long entityId, EntityApprovalStatus.EntityType entityType);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.avni.server.dao;

import org.joda.time.DateTime;


public class EntityApprovalStatusSearchParams {
private final DateTime lastModifiedDateTime;
private final DateTime now;
private final String entityType;
private final String entityTypeUuid;

public EntityApprovalStatusSearchParams(DateTime lastModifiedDateTime, DateTime now, String entityType, String entityTypeUuid) {
this.lastModifiedDateTime = lastModifiedDateTime;
this.now = now;
this.entityType = entityType;
this.entityTypeUuid = entityTypeUuid;
}

public DateTime getLastModifiedDateTime() {
return lastModifiedDateTime;
}

public DateTime getNow() {
return now;
}

public String getEntityType() {
return entityType;
}

public String getEntityTypeUuid() {
return entityTypeUuid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -180,4 +181,29 @@ public void checkIsAdmin() {
if (!user.isAdmin())
throw AvniAccessException.createForNotAdmin(user);
}

public void checkApprovePrivilegeOnEntityApprovalStatus(String entityType, String entityTypeUuid) {
switch (EntityApprovalStatus.EntityType.valueOf(entityType)) {
case Subject:
this.checkSubjectPrivilege(PrivilegeType.ApproveSubject, entityTypeUuid);
break;
case Encounter:
case ProgramEncounter:
this.checkEncounterPrivilege(PrivilegeType.ApproveEncounter, entityTypeUuid);
break;
case ProgramEnrolment:
this.checkProgramPrivilege(PrivilegeType.ApproveEnrolment, entityTypeUuid);
break;
// TODO: implement when ApproveChecklistitem privileges are enforced
// case ChecklistItem:
}
}

public void checkApprovePrivilegeOnEntityApprovalStatuses(List<EntityApprovalStatus> entityApprovalStatuses) {
Map<List<String>, Long> uniqueEASByTypeAndTypeUuid = entityApprovalStatuses
.stream()
.collect(Collectors.groupingBy(entityApprovalStatus -> Arrays.asList(String.valueOf(entityApprovalStatus.getEntityType()), entityApprovalStatus.getEntityTypeUuid()), Collectors.counting()));

uniqueEASByTypeAndTypeUuid.keySet().forEach(entity -> checkApprovePrivilegeOnEntityApprovalStatus(entity.get(0), entity.get(1)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.avni.server.web.api;

import org.avni.server.dao.EntityApprovalStatusRepository;
import org.avni.server.dao.EntityApprovalStatusSearchParams;
import org.avni.server.domain.EntityApprovalStatus;
import org.avni.server.service.EntityApprovalStatusService;
import org.avni.server.service.accessControl.AccessControlService;
import org.avni.server.web.response.EntityApprovalStatusResponse;
import org.avni.server.web.response.ResponsePage;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;

@RestController
public class EntityApprovalStatusApiController {

private final EntityApprovalStatusRepository entityApprovalStatusRepository;
private final EntityApprovalStatusService entityApprovalStatusService;
private final AccessControlService accessControlService;

@Autowired
public EntityApprovalStatusApiController(EntityApprovalStatusRepository entityApprovalStatusRepository, EntityApprovalStatusService entityApprovalStatusService, AccessControlService accessControlService) {
this.entityApprovalStatusRepository = entityApprovalStatusRepository;
this.entityApprovalStatusService = entityApprovalStatusService;
this.accessControlService = accessControlService;
}

@RequestMapping(value = "/api/approvalStatuses", method = RequestMethod.GET)
@PreAuthorize(value = "hasAnyAuthority('user')")
public ResponsePage getEntityApprovalStatuses(@RequestParam(value = "lastModifiedDateTime", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) DateTime lastModifiedDateTime,
@RequestParam(value = "now", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) DateTime now,
@RequestParam(value = "entityType", required = false) String entityType,
@RequestParam(value = "entityTypeId", required = false) String entityTypeUuid,
Pageable pageable) {

Page<EntityApprovalStatus> entityApprovalStatuses = entityApprovalStatusRepository.findEntityApprovalStatuses(new EntityApprovalStatusSearchParams(lastModifiedDateTime, now, entityType, entityTypeUuid), pageable);
ArrayList<EntityApprovalStatusResponse> entityApprovalStatusResponse = new ArrayList<>();
entityApprovalStatuses.forEach(entityApprovalStatus -> entityApprovalStatusResponse.add(EntityApprovalStatusResponse.fromEntityApprovalStatus(entityApprovalStatus, entityApprovalStatusService.getEntityUuid(entityApprovalStatus))));
accessControlService.checkApprovePrivilegeOnEntityApprovalStatuses(entityApprovalStatuses.getContent());
return new ResponsePage(entityApprovalStatusResponse, entityApprovalStatuses.getNumberOfElements(), entityApprovalStatuses.getTotalPages(), entityApprovalStatuses.getSize());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.avni.server.web.response;

import org.avni.server.domain.EntityApprovalStatus;

import java.util.LinkedHashMap;

public class EntityApprovalStatusResponse extends LinkedHashMap<String, Object> {
public static EntityApprovalStatusResponse fromEntityApprovalStatus(EntityApprovalStatus entityApprovalStatus, String entityUuid) {
EntityApprovalStatusResponse entityApprovalStatusResponse = new EntityApprovalStatusResponse();
entityApprovalStatusResponse.put("Entity ID", entityUuid);
entityApprovalStatusResponse.put("Entity type", entityApprovalStatus.getEntityType());
entityApprovalStatusResponse.put("Entity type ID", entityApprovalStatus.getEntityTypeUuid());
entityApprovalStatusResponse.put("Approval status", entityApprovalStatus.getApprovalStatus().getStatus());
entityApprovalStatusResponse.put("Approval status comment", entityApprovalStatus.getApprovalStatusComment());
entityApprovalStatusResponse.put("Status date time", entityApprovalStatus.getStatusDateTime());

Response.putAudit(entityApprovalStatus, entityApprovalStatusResponse);
return entityApprovalStatusResponse;
}
}
98 changes: 98 additions & 0 deletions avni-server-api/src/main/resources/api/external-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,73 @@ paths:
responses:
"200":
description: successful
/api/entityApprovalStatuses:
get:
tags:
- Entity Approval Status
summary: Get paged list of entity approval statues
description: |
By passing in the appropriate options, you can get the entity approval statuses in set of pages
operationId: entityApprovalStatuses
parameters:
- name: lastModifiedDateTime
in: query
description: "date-time in ISO datetime format. All the entity approval statuses which have been updated since this time will be returned. The value should be specified in the following format - yyyy-MM-dd'T'HH:mm:ss.SSSZ, e.g. \"2000-10-31T01:30:00.000Z\". Defaults to \"1900-01-01T00:00:00.000Z\"."
required: false
style: form
explode: true
schema:
type: string
- name: now
in: query
description: "date-time in ISO datetime format. All the entity approval statuses which have been updated till this time will be returned. The value should be specified in the following format - yyyy-MM-dd'T'HH:mm:ss.SSSZ, e.g. \"2000-10-31T01:30:00.000Z\". Defaults to current time."
required: false
style: form
explode: true
schema:
type: string
- name: entityType
in: query
description: "Allows filtering results by entity type name"
required: false
style: form
explode: true
schema:
type: string
- name: entityTypeId
in: query
description: "Allows filtering results by entity type id"
required: false
style: form
explode: true
schema:
type: string
example: "{\"Diagnosis\": \"Diabetes\", \"Blood Group\": \"B+\"}"
- name: auth-token
in: header
required: false
style: simple
explode: false
schema:
type: string
description: token provided by cognito/keycloak
- name: version
in: query
description: "Version of the API to be called"
required: false
explode: false
schema:
type: string
default: 1
responses:
"200":
description: "successful, a page of entity approval statuses"
content:
application/json:
schema:
$ref: '#/components/schemas/inline_response_200_eas'
"400":
description: bad input parameter
components:
schemas:
Subject:
Expand Down Expand Up @@ -1796,6 +1863,29 @@ components:
description: "id of locations"
items:
type: number
EntityApprovalStatusBody:
type: object
properties:
Entity ID:
type: string
description: ID of the entity for which the approval status is being returned
Entity type:
type: string
description: Type of the entity for which the approval status is being returned i.e. Subject / Encounter etc
Entity type ID:
type: string
description: ID of the entity type for which the approval status is being returned
Approval status:
type: string
description: Approval status for the entity
Approval status comment:
type: string
description: Comments on the approval status for the entity
Status date time:
type: string
description: Date/Time when the approval status was set
audit:
$ref: '#/components/schemas/Audit'
inline_response_200:
properties:
content:
Expand Down Expand Up @@ -1840,3 +1930,11 @@ components:
$ref: '#/components/schemas/Location'
allOf:
- $ref: '#/components/schemas/ResponsePage'
inline_response_200_eas:
properties:
content:
type: array
items:
$ref: '#/components/schemas/EntityApprovalStatusBody'
allOf:
- $ref: '#/components/schemas/ResponsePage'

0 comments on commit d248223

Please sign in to comment.