From 193941a703133f3ad8b889939bd1ce801158e13e Mon Sep 17 00:00:00 2001 From: ojwanganto Date: Wed, 3 Jul 2024 23:44:52 +0300 Subject: [PATCH] Initial work to support CRUD through REST --- api/pom.xml | 4 + .../impl/api/DataFilterDefaultResponse.java | 66 ++++++++++ .../api/EntityBasisMapResponseMapper.java | 99 ++++++++++++++ .../impl/api/EntityBasisMapSearchRequest.java | 56 ++++++++ .../db/hibernate/HibernateDataFilterDAO.java | 14 +- .../impl/api/impl/DataFilterServiceImpl.java | 2 +- omod/pom.xml | 5 + .../web/controller/DataFilterController.java | 123 ++++++++++++++++++ omod/src/main/resources/config.xml | 3 + pom.xml | 13 ++ rest-endpoint-draft-readme.txt | 93 +++++++++++++ 11 files changed, 467 insertions(+), 11 deletions(-) create mode 100644 api/src/main/java/org/openmrs/module/datafilter/impl/api/DataFilterDefaultResponse.java create mode 100644 api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapResponseMapper.java create mode 100644 api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapSearchRequest.java create mode 100644 omod/src/main/java/org/openmrs/module/datafilter/web/controller/DataFilterController.java create mode 100644 rest-endpoint-draft-readme.txt diff --git a/api/pom.xml b/api/pom.xml index 1a71083..8ed138b 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -25,6 +25,10 @@ API project for Data Filter Module + + org.openmrs.module + webservices.rest-omod-common + org.openmrs.api openmrs-api diff --git a/api/src/main/java/org/openmrs/module/datafilter/impl/api/DataFilterDefaultResponse.java b/api/src/main/java/org/openmrs/module/datafilter/impl/api/DataFilterDefaultResponse.java new file mode 100644 index 0000000..5dca03f --- /dev/null +++ b/api/src/main/java/org/openmrs/module/datafilter/impl/api/DataFilterDefaultResponse.java @@ -0,0 +1,66 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.datafilter.impl.api; + +import java.util.Date; +import java.util.Map; + +public class DataFilterDefaultResponse { + + private String uuid; + + private Date dateCreated; + + private Map entity; + + private Map basis; + + private Map creator; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Date getDateCreated() { + return dateCreated; + } + + public void setDateCreated(Date dateCreated) { + this.dateCreated = dateCreated; + } + + public Map getEntity() { + return entity; + } + + public void setEntity(Map entity) { + this.entity = entity; + } + + public Map getBasis() { + return basis; + } + + public void setBasis(Map basis) { + this.basis = basis; + } + + public Map getCreator() { + return creator; + } + + public void setCreator(Map creator) { + this.creator = creator; + } +} diff --git a/api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapResponseMapper.java b/api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapResponseMapper.java new file mode 100644 index 0000000..ca4c9c2 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapResponseMapper.java @@ -0,0 +1,99 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.datafilter.impl.api; + +import org.openmrs.Location; +import org.openmrs.Patient; +import org.openmrs.Person; +import org.openmrs.User; +import org.openmrs.api.LocationService; +import org.openmrs.api.PatientService; +import org.openmrs.api.UserService; +import org.openmrs.module.datafilter.impl.EntityBasisMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +public class EntityBasisMapResponseMapper { + + @Autowired + LocationService locationService; + + @Autowired + UserService userService; + + @Autowired + PatientService patientService; + + /** + * Handles only User, Patient, and Location objects TODO: Make this implementation generic to handle + * other OpenMRS objects + * + * @param a + * @param response + * @return + */ + private DataFilterDefaultResponse mapToDefaultResponse(EntityBasisMap a, DataFilterDefaultResponse response) { + response.setUuid(a.getUuid()); + response.setDateCreated(a.getDateCreated()); + response.setCreator(createUserMap(a.getCreator())); + if (a.getEntityType().equals("org.openmrs.User")) { + response.setEntity(createUserMap(userService.getUser(Integer.valueOf(a.getEntityIdentifier())))); + } else if (a.getEntityType().equals("org.openmrs.Patient")) { + response.setEntity(createPatientMap(patientService.getPatient(Integer.valueOf(a.getEntityIdentifier())))); + } + + if (a.getBasisType().equals("org.openmrs.Location")) { + response.setBasis(createLocationMap(locationService.getLocation(Integer.valueOf(a.getBasisIdentifier())))); + } + return response; + } + + public List constructResponse(List entityBasisMaps) { + return entityBasisMaps.stream().map(as -> this.mapToDefaultResponse(as, new DataFilterDefaultResponse())) + .collect(Collectors.toList()); + } + + private Map createLocationMap(Location l) { + Map locationMap = null; + if (l != null) { + locationMap = new HashMap(); + locationMap.put("name", l.getName()); + locationMap.put("uuid", l.getUuid()); + } + return locationMap; + } + + private Map createPatientMap(Patient p) { + Map map = new HashMap(); + map.put("name", p.getPersonName().getFullName()); + map.put("uuid", p.getUuid()); + map.put("identifier", p.getPatientIdentifier().getIdentifier()); + map.put("age", p.getAge()); + map.put("gender", p.getGender()); + map.putAll(p.getActiveIdentifiers().stream().filter(e -> e.getIdentifierType() != null) + .collect(Collectors.toMap(e -> e.getIdentifierType().toString().replaceAll("[- ]", ""), + e -> e.getIdentifier(), (e1, e2) -> e1 + "," + e2))); + return map; + } + + private Map createUserMap(User u) { + Person p = u.getPerson(); + Map map = new HashMap(); + map.put("name", p.getPersonName().getFullName()); + map.put("uuid", p.getUuid()); + return map; + } +} diff --git a/api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapSearchRequest.java b/api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapSearchRequest.java new file mode 100644 index 0000000..aab806f --- /dev/null +++ b/api/src/main/java/org/openmrs/module/datafilter/impl/api/EntityBasisMapSearchRequest.java @@ -0,0 +1,56 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.datafilter.impl.api; + +/** + * A model for search + */ +public class EntityBasisMapSearchRequest { + + private String entityIdentifier; + + private String entityType; + + private String basisIdentifier; + + private String basisType; + + public String getEntityIdentifier() { + return entityIdentifier; + } + + public void setEntityIdentifier(String entityIdentifier) { + this.entityIdentifier = entityIdentifier; + } + + public String getEntityType() { + return entityType; + } + + public void setEntityType(String entityType) { + this.entityType = entityType; + } + + public String getBasisIdentifier() { + return basisIdentifier; + } + + public void setBasisIdentifier(String basisIdentifier) { + this.basisIdentifier = basisIdentifier; + } + + public String getBasisType() { + return basisType; + } + + public void setBasisType(String basisType) { + this.basisType = basisType; + } +} diff --git a/api/src/main/java/org/openmrs/module/datafilter/impl/api/db/hibernate/HibernateDataFilterDAO.java b/api/src/main/java/org/openmrs/module/datafilter/impl/api/db/hibernate/HibernateDataFilterDAO.java index c9ce939..0baf372 100644 --- a/api/src/main/java/org/openmrs/module/datafilter/impl/api/db/hibernate/HibernateDataFilterDAO.java +++ b/api/src/main/java/org/openmrs/module/datafilter/impl/api/db/hibernate/HibernateDataFilterDAO.java @@ -41,7 +41,7 @@ public void setSessionFactory(SessionFactory sessionFactory) { */ @Override public EntityBasisMap getEntityBasisMap(String entityIdentifier, String entityType, String basisIdentifier, - String basisType) { + String basisType) { Criteria criteria = sessionFactory.getCurrentSession().createCriteria(EntityBasisMap.class); criteria.add(Restrictions.eq("entityIdentifier", entityIdentifier).ignoreCase()); @@ -83,8 +83,7 @@ public Collection getEntityBasisMaps(String entityIdentifier, St } @Override - public List getEntityBasisMapsByBasis(String entityType, String basisType, - String basisIdentifier) { + public List getEntityBasisMapsByBasis(String entityType, String basisType, String basisIdentifier) { Session session = sessionFactory.getCurrentSession(); @@ -92,13 +91,8 @@ public List getEntityBasisMapsByBasis(String entityType, String CriteriaQuery cq = cb.createQuery(EntityBasisMap.class); Root root = cq.from(EntityBasisMap.class); - cq.select(root).where( - cb.and( - cb.equal(root.get("entityType"), entityType), - cb.equal(root.get("basisType"), basisType), - cb.equal(root.get("basisIdentifier"), basisIdentifier) - ) - ); + cq.select(root).where(cb.and(cb.equal(root.get("entityType"), entityType), + cb.equal(root.get("basisType"), basisType), cb.equal(root.get("basisIdentifier"), basisIdentifier))); Query query = session.createQuery(cq); return query.getResultList(); diff --git a/api/src/main/java/org/openmrs/module/datafilter/impl/api/impl/DataFilterServiceImpl.java b/api/src/main/java/org/openmrs/module/datafilter/impl/api/impl/DataFilterServiceImpl.java index dac2df7..4e01b93 100644 --- a/api/src/main/java/org/openmrs/module/datafilter/impl/api/impl/DataFilterServiceImpl.java +++ b/api/src/main/java/org/openmrs/module/datafilter/impl/api/impl/DataFilterServiceImpl.java @@ -140,7 +140,7 @@ public Collection getEntityBasisMaps(OpenmrsObject entity, Strin @Override public Collection getEntityBasisMapsByBasis(Class entityClass, - OpenmrsObject basis) { + OpenmrsObject basis) { return getEntityBasisMapsByBasis(entityClass.getName(), basis); } diff --git a/omod/pom.xml b/omod/pom.xml index 7691f3c..15a0f15 100644 --- a/omod/pom.xml +++ b/omod/pom.xml @@ -26,6 +26,11 @@ OMOD project for Data Filter Module + + org.openmrs.module + webservices.rest-omod-common + provided + ${project.parent.groupId} ${project.parent.artifactId}-api diff --git a/omod/src/main/java/org/openmrs/module/datafilter/web/controller/DataFilterController.java b/omod/src/main/java/org/openmrs/module/datafilter/web/controller/DataFilterController.java new file mode 100644 index 0000000..f462301 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/datafilter/web/controller/DataFilterController.java @@ -0,0 +1,123 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ +package org.openmrs.module.datafilter.web.controller; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.openmrs.OpenmrsObject; +import org.openmrs.api.context.Context; +import org.openmrs.module.datafilter.impl.EntityBasisMap; +import org.openmrs.module.datafilter.impl.api.DataFilterDefaultResponse; +import org.openmrs.module.datafilter.impl.api.DataFilterService; +import org.openmrs.module.datafilter.impl.api.EntityBasisMapResponseMapper; +import org.openmrs.module.datafilter.impl.api.EntityBasisMapSearchRequest; +import org.openmrs.module.webservices.rest.web.RestConstants; +import org.openmrs.module.webservices.rest.web.v1_0.controller.BaseRestController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@Controller +@RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/datafilter") +public class DataFilterController extends BaseRestController { + + private Log log = LogFactory.getLog(this.getClass()); + + @Autowired + private DataFilterService dataFilterService; + + @Autowired + private EntityBasisMapResponseMapper dataFilterMapper; + + @RequestMapping(method = RequestMethod.POST, value = "entitybasismap") + @ResponseBody + public ResponseEntity grantAccess(@Valid @RequestBody EntityBasisMap entityBasisMapRequest) { + try { + OpenmrsObject entity = null; + OpenmrsObject basis = null; + String entityDomain = entityBasisMapRequest.getEntityType(); + String entityIdentifier = entityBasisMapRequest.getEntityIdentifier(); + String basisDomain = entityBasisMapRequest.getBasisType(); + String basisIdentifier = entityBasisMapRequest.getBasisIdentifier(); + + if (StringUtils.isNotBlank(entityDomain) && StringUtils.isNotBlank(entityIdentifier) + && entityDomain.equalsIgnoreCase("org.openmrs.User")) { + entity = Context.getUserService().getUserByUuid(entityIdentifier); + } else if (StringUtils.isNotBlank(entityDomain) && StringUtils.isNotBlank(entityIdentifier) + && entityDomain.equalsIgnoreCase("org.openmrs.Patient")) { + entity = Context.getPatientService().getPatientByUuid(entityIdentifier); + } + + if (StringUtils.isNotBlank(basisDomain) && StringUtils.isNotBlank(basisIdentifier) + && basisDomain.equalsIgnoreCase("org.openmrs.Location")) { + basis = Context.getLocationService().getLocationByUuid(basisIdentifier); + } + + if (entity != null && basis != null) { + dataFilterService.grantAccess(entity, basis); + return new ResponseEntity<>("Assignment done successfully", HttpStatus.OK); + } + return new ResponseEntity<>("There was an error saving the assignment", HttpStatus.INTERNAL_SERVER_ERROR); + } + catch (Exception e) { + log.error("Runtime error while trying to create new appointment", e); + return new ResponseEntity<>("Runtime error while trying to create new appointment", HttpStatus.BAD_REQUEST); + } + } + + @RequestMapping(method = RequestMethod.POST, value = "search") + @ResponseBody + public List searchEntityBasisMap(@Valid @RequestBody EntityBasisMapSearchRequest searchQuery) + throws IOException { + Collection entityBasisMaps = null; + + if (StringUtils.isNotBlank(searchQuery.getBasisType()) || StringUtils.isNotBlank(searchQuery.getEntityType())) { + + OpenmrsObject entity = null; + OpenmrsObject basis = null; + String entityDomain = searchQuery.getEntityType(); + String entityIdentifier = searchQuery.getEntityIdentifier(); + String basisDomain = searchQuery.getBasisType(); + String basisIdentifier = searchQuery.getBasisIdentifier(); + + if (StringUtils.isNotBlank(entityDomain) && StringUtils.isNotBlank(entityIdentifier) + && entityDomain.equalsIgnoreCase("org.openmrs.User")) { + entity = Context.getUserService().getUserByUuid(entityIdentifier); + } else if (StringUtils.isNotBlank(entityDomain) && StringUtils.isNotBlank(entityIdentifier) + && entityDomain.equalsIgnoreCase("org.openmrs.Patient")) { + entity = Context.getPatientService().getPatientByUuid(entityIdentifier); + } + + if (StringUtils.isNotBlank(basisDomain) && StringUtils.isNotBlank(basisIdentifier) + && basisDomain.equalsIgnoreCase("org.openmrs.Location")) { + basis = Context.getLocationService().getLocationByUuid(basisIdentifier); + } + + if (entity != null && basis == null) { + entityBasisMaps = dataFilterService.getEntityBasisMaps(entity, basisDomain); + } else if (basis != null && entity == null) { + entityBasisMaps = dataFilterService.getEntityBasisMapsByBasis(entityDomain, basis); + } + } + return dataFilterMapper.constructResponse(entityBasisMaps.stream().collect(Collectors.toList())); + } +} diff --git a/omod/src/main/resources/config.xml b/omod/src/main/resources/config.xml index df6d5af..17ba96d 100644 --- a/omod/src/main/resources/config.xml +++ b/omod/src/main/resources/config.xml @@ -27,6 +27,9 @@ ${project.parent.groupId}.${project.parent.artifactId}.DataFilterActivator + + org.openmrs.module.webservices.rest + ${project.parent.artifactId}DataFilterWebFilter diff --git a/pom.xml b/pom.xml index e53ccaf..e2bfdd7 100644 --- a/pom.xml +++ b/pom.xml @@ -49,10 +49,23 @@ 2.4.0 UTF-8 2.3.29 + 2.29.0 + + org.openmrs.module + webservices.rest-omod + ${webServices.version} + provided + + + org.openmrs.module + webservices.rest-omod-common + ${webServices.version} + provided + org.openmrs.api openmrs-api diff --git a/rest-endpoint-draft-readme.txt b/rest-endpoint-draft-readme.txt new file mode 100644 index 0000000..5634dd8 --- /dev/null +++ b/rest-endpoint-draft-readme.txt @@ -0,0 +1,93 @@ +-- create a mapping: + +Request type: POST +Request URL: {base_rest_url}/datafilter/entitybasismap +sample payload: +1. Map user to a location +{ +"entityIdentifier": "user-uuid", -- replace accordingly +"entityType":"org.openmrs.User", +"basisIdentifier":"location-uuid", -- replace accordingly +"basisType":"org.openmrs.Location" +} + +2. Map patient to a location +{ +"entityIdentifier": "patient-uuid", -- replace accordingly +"entityType":"org.openmrs.User", +"basisIdentifier":"location-uuid", -- replace accordingly +"basisType":"org.openmrs.Location" +} +-- ------------------------- + + +-- searching for locations for a user +Request type: POST +Request URL: {base_rest_url}/datafilter/search +Payload: +{ +"entityIdentifier": "46e679ea-74ee-45f1-9cad-4b7981852892", +"entityType":"org.openmrs.User", +"basisIdentifier":"", +"basisType":"org.openmrs.Location" +} + +sample response: +[ + { + "uuid": "e74e9407-21c0-11ef-a960-629a87b59084", + "dateCreated": 1717429786000, + "entity": { + "name": "Jelly Kwacha", + "uuid": "61686921-374c-4ce1-bab9-270ef9c0eeb9" + }, + "basis": { + "name": "Railways Dispensary (Kisumu)", + "uuid": "fc4aeac6-24e7-4da1-8d51-9fc1997a80d4" + }, + "creator": { + "name": "Super User", + "uuid": "54dc32bc-eaea-11e2-90be-0800271ad0ce" + } + } +] + + +-- Search patients mapped to a location + +Request type: POST +Request URL: {base_rest_url}/datafilter/search + +Payload: +{ +"entityIdentifier": "", +"entityType":"org.openmrs.Patient", +"basisIdentifier":"fc4aeac6-24e7-4da1-8d51-9fc1997a80d4", +"basisType":"org.openmrs.Location" +} + +Sample response: + +[ + { + "uuid": "d5242512-21c1-11ef-a960-629a87b59084", + "dateCreated": 1717430186000, + "entity": { + "OpenMRSID": "MXFXD", + "identifier": "MXFXD", + "gender": "F", + "PatientClinicNumber": "2467/24", + "name": "Aubry Waso Makena", + "uuid": "d97d2005-528c-4952-87e7-eeadf9d0628b", + "age": 10 + }, + "basis": { + "name": "Railways Dispensary (Kisumu)", + "uuid": "fc4aeac6-24e7-4da1-8d51-9fc1997a80d4" + }, + "creator": { + "name": "Super User", + "uuid": "54dc32bc-eaea-11e2-90be-0800271ad0ce" + } + } +]