Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Remove entities service dependency from relationship service [DHIS2-18883] #19832

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.LongSupplier;
Expand All @@ -47,6 +48,7 @@
import org.hisp.dhis.common.IdentifiableObject;
import org.hisp.dhis.common.SoftDeletableObject;
import org.hisp.dhis.common.SortDirection;
import org.hisp.dhis.common.UID;
import org.hisp.dhis.common.hibernate.SoftDeleteHibernateObjectStore;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.Event;
Expand Down Expand Up @@ -88,6 +90,49 @@ public HibernateRelationshipStore(
super(entityManager, jdbcTemplate, publisher, Relationship.class, aclService, true);
}

@Override
public Optional<TrackedEntity> findTrackedEntity(UID trackedEntity) {
@Language("hql")
String hql =
"""
from TrackedEntity te
where te.uid = :trackedEntity
""";
List<TrackedEntity> trackedEntities =
getQuery(hql, TrackedEntity.class)
.setParameter(TRACKED_ENTITY, trackedEntity.getValue())
.getResultList();
return trackedEntities.stream().findFirst();
}

@Override
public Optional<Enrollment> findEnrollment(UID enrollment) {
@Language("hql")
String hql =
"""
from Enrollment e
where e.uid = :enrollment
""";
List<Enrollment> enrollments =
getQuery(hql, Enrollment.class)
.setParameter(ENROLLMENT, enrollment.getValue())
.getResultList();
return enrollments.stream().findFirst();
}

@Override
public Optional<Event> findEvent(UID event) {
@Language("hql")
String hql =
"""
from Event e
where e.uid = :event
""";
List<Event> events =
getQuery(hql, Event.class).setParameter(EVENT, event.getValue()).getResultList();
return events.stream().findFirst();
}

@Override
public List<Relationship> getByTrackedEntity(
TrackedEntity trackedEntity, RelationshipQueryParams queryParams) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@
import javax.annotation.Nonnull;
import lombok.RequiredArgsConstructor;
import org.hisp.dhis.common.IdentifiableObject;
import org.hisp.dhis.feedback.BadRequestException;
import org.hisp.dhis.common.UID;
import org.hisp.dhis.feedback.ForbiddenException;
import org.hisp.dhis.feedback.NotFoundException;
import org.hisp.dhis.tracker.export.enrollment.EnrollmentService;
import org.hisp.dhis.tracker.export.event.EventService;
import org.hisp.dhis.tracker.export.trackedentity.TrackedEntityService;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.Event;
import org.hisp.dhis.trackedentity.TrackedEntity;
import org.hisp.dhis.tracker.acl.TrackerAccessManager;
import org.hisp.dhis.user.CurrentUserUtil;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -47,19 +49,18 @@
@RequiredArgsConstructor
class RelationshipOperationParamsMapper {

private final TrackedEntityService trackedEntityService;
private final EnrollmentService enrollmentService;
private final EventService eventService;
private final RelationshipStore relationshipStore;
private final TrackerAccessManager trackerAccessManager;

@Transactional(readOnly = true)
public RelationshipQueryParams map(@Nonnull RelationshipOperationParams params)
throws NotFoundException, ForbiddenException, BadRequestException {
throws NotFoundException, ForbiddenException {

IdentifiableObject entity =
switch (params.getType()) {
case TRACKED_ENTITY -> trackedEntityService.getTrackedEntity(params.getIdentifier());
case ENROLLMENT -> enrollmentService.getEnrollment(params.getIdentifier());
case EVENT -> eventService.getEvent(params.getIdentifier());
case TRACKED_ENTITY -> getTrackedEntity(params.getIdentifier());
case ENROLLMENT -> getEnrollment(params.getIdentifier());
case EVENT -> getEvent(params.getIdentifier());
case RELATIONSHIP -> throw new IllegalArgumentException("Unsupported type");
};

Expand All @@ -69,4 +70,44 @@ public RelationshipQueryParams map(@Nonnull RelationshipOperationParams params)
.includeDeleted(params.isIncludeDeleted())
.build();
}

private TrackedEntity getTrackedEntity(UID trackedEntityUid)
throws NotFoundException, ForbiddenException {
TrackedEntity trackedEntity =
relationshipStore
.findTrackedEntity(trackedEntityUid)
.orElseThrow(() -> new NotFoundException(TrackedEntity.class, trackedEntityUid));
if (!trackerAccessManager
.canRead(CurrentUserUtil.getCurrentUserDetails(), trackedEntity)
.isEmpty()) {
throw new ForbiddenException(TrackedEntity.class, trackedEntityUid);
}
return trackedEntity;
}

private Enrollment getEnrollment(UID enrollmentUid) throws NotFoundException, ForbiddenException {
Enrollment enrollment =
relationshipStore
.findEnrollment(enrollmentUid)
.orElseThrow(() -> new NotFoundException(Enrollment.class, enrollmentUid));
if (!trackerAccessManager
.canRead(CurrentUserUtil.getCurrentUserDetails(), enrollment, false)
.isEmpty()) {
throw new ForbiddenException(Enrollment.class, enrollmentUid);
}
return enrollment;
}

private Event getEvent(UID eventUid) throws NotFoundException, ForbiddenException {
Event event =
relationshipStore
.findEvent(eventUid)
.orElseThrow(() -> new NotFoundException(Event.class, eventUid));
if (!trackerAccessManager
.canRead(CurrentUserUtil.getCurrentUserDetails(), event, false)
.isEmpty()) {
throw new ForbiddenException(Event.class, eventUid);
}
return event;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
package org.hisp.dhis.tracker.export.relationship;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.hisp.dhis.common.IdentifiableObjectStore;
import org.hisp.dhis.common.UID;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.Event;
import org.hisp.dhis.relationship.Relationship;
Expand All @@ -40,6 +42,12 @@
public interface RelationshipStore extends IdentifiableObjectStore<Relationship> {
String ID = RelationshipStore.class.getName();

Optional<TrackedEntity> findTrackedEntity(UID trackedEntity);

Optional<Enrollment> findEnrollment(UID enrollment);

Optional<Event> findEvent(UID event);

List<Relationship> getByTrackedEntity(
TrackedEntity trackedEntity, RelationshipQueryParams queryParams);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@
import static org.hisp.dhis.tracker.TrackerType.TRACKED_ENTITY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;

import java.util.List;
import java.util.Optional;
import org.hisp.dhis.common.SortDirection;
import org.hisp.dhis.common.UID;
import org.hisp.dhis.feedback.BadRequestException;
import org.hisp.dhis.feedback.ForbiddenException;
import org.hisp.dhis.feedback.NotFoundException;
import org.hisp.dhis.organisationunit.OrganisationUnit;
Expand All @@ -50,9 +51,8 @@
import org.hisp.dhis.trackedentity.TrackedEntity;
import org.hisp.dhis.tracker.acl.TrackerAccessManager;
import org.hisp.dhis.tracker.export.Order;
import org.hisp.dhis.tracker.export.enrollment.EnrollmentService;
import org.hisp.dhis.tracker.export.event.EventService;
import org.hisp.dhis.tracker.export.trackedentity.TrackedEntityService;
import org.hisp.dhis.user.SystemUser;
import org.hisp.dhis.user.UserDetails;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand All @@ -69,13 +69,9 @@ class RelationshipOperationParamsMapperTest extends TestBase {

private static final UID EV_UID = UID.of("TvjwTPToKHO");

@Mock private TrackedEntityService trackedEntityService;
@Mock private RelationshipStore relationshipStore;

@Mock private EnrollmentService enrollmentService;

@Mock private EventService eventService;

@Mock private TrackerAccessManager accessManager;
@Mock private TrackerAccessManager trackerAccessManager;

@InjectMocks private RelationshipOperationParamsMapper mapper;

Expand All @@ -85,6 +81,8 @@ class RelationshipOperationParamsMapperTest extends TestBase {

private Event event;

private UserDetails user;

@BeforeEach
public void setUp() {
OrganisationUnit organisationUnit = createOrganisationUnit('A');
Expand All @@ -97,12 +95,14 @@ public void setUp() {
enrollment.setUid(EN_UID.getValue());
event = createEvent(programStage, enrollment, organisationUnit);
event.setUid(EV_UID.getValue());
user = new SystemUser();
injectSecurityContextNoSettings(user);
}

@Test
void shouldMapTrackedEntityWhenATrackedEntityIsPassed()
throws NotFoundException, ForbiddenException, BadRequestException {
when(trackedEntityService.getTrackedEntity(TE_UID)).thenReturn(trackedEntity);
throws NotFoundException, ForbiddenException {
when(relationshipStore.findTrackedEntity(TE_UID)).thenReturn(Optional.of(trackedEntity));
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(TRACKED_ENTITY).identifier(TE_UID).build();

Expand All @@ -113,9 +113,27 @@ void shouldMapTrackedEntityWhenATrackedEntityIsPassed()
}

@Test
void shouldMapEnrollmentWhenAEnrollmentIsPassed()
throws NotFoundException, ForbiddenException, BadRequestException {
when(enrollmentService.getEnrollment(EN_UID)).thenReturn(enrollment);
void shouldThrowNotFoundExceptionWhenATrackedEntityIsNotPresent() {
when(relationshipStore.findTrackedEntity(TE_UID)).thenReturn(Optional.empty());
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(TRACKED_ENTITY).identifier(TE_UID).build();

assertThrows(NotFoundException.class, () -> mapper.map(params));
}

@Test
void shouldThrowForbiddenExceptionWhenATrackedEntityIsNotAccessible() {
when(relationshipStore.findTrackedEntity(TE_UID)).thenReturn(Optional.of(trackedEntity));
when(trackerAccessManager.canRead(user, trackedEntity)).thenReturn(List.of("error"));
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(TRACKED_ENTITY).identifier(TE_UID).build();

assertThrows(ForbiddenException.class, () -> mapper.map(params));
}

@Test
void shouldMapEnrollmentWhenAEnrollmentIsPassed() throws NotFoundException, ForbiddenException {
when(relationshipStore.findEnrollment(EN_UID)).thenReturn(Optional.of(enrollment));
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(ENROLLMENT).identifier(EN_UID).build();

Expand All @@ -126,9 +144,27 @@ void shouldMapEnrollmentWhenAEnrollmentIsPassed()
}

@Test
void shouldMapEventWhenAEventIsPassed()
throws NotFoundException, ForbiddenException, BadRequestException {
when(eventService.getEvent(EV_UID)).thenReturn(event);
void shouldThrowNotFoundExceptionWhenAnEnrollmentIsNotPresent() {
when(relationshipStore.findEnrollment(EN_UID)).thenReturn(Optional.empty());
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(ENROLLMENT).identifier(EN_UID).build();

assertThrows(NotFoundException.class, () -> mapper.map(params));
}

@Test
void shouldThrowForbiddenExceptionWhenAnEnrollmentIsNotAccessible() {
when(relationshipStore.findEnrollment(EN_UID)).thenReturn(Optional.of(enrollment));
when(trackerAccessManager.canRead(user, enrollment, false)).thenReturn(List.of("error"));
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(ENROLLMENT).identifier(EN_UID).build();

assertThrows(ForbiddenException.class, () -> mapper.map(params));
}

@Test
void shouldMapEventWhenAEventIsPassed() throws NotFoundException, ForbiddenException {
when(relationshipStore.findEvent(EV_UID)).thenReturn(Optional.of(event));
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(EVENT).identifier(EV_UID).build();

Expand All @@ -139,9 +175,27 @@ void shouldMapEventWhenAEventIsPassed()
}

@Test
void shouldMapOrderInGivenOrder()
throws ForbiddenException, NotFoundException, BadRequestException {
when(trackedEntityService.getTrackedEntity(TE_UID)).thenReturn(trackedEntity);
void shouldThrowNotFoundExceptionWhenAnEventIsNotPresent() {
when(relationshipStore.findEvent(EV_UID)).thenReturn(Optional.empty());
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(EVENT).identifier(EV_UID).build();

assertThrows(NotFoundException.class, () -> mapper.map(params));
}

@Test
void shouldThrowForbiddenExceptionWhenAnEventIsNotAccessible() {
when(relationshipStore.findEvent(EV_UID)).thenReturn(Optional.of(event));
when(trackerAccessManager.canRead(user, event, false)).thenReturn(List.of("error"));
RelationshipOperationParams params =
RelationshipOperationParams.builder().type(EVENT).identifier(EV_UID).build();

assertThrows(ForbiddenException.class, () -> mapper.map(params));
}

@Test
void shouldMapOrderInGivenOrder() throws ForbiddenException, NotFoundException {
when(relationshipStore.findTrackedEntity(TE_UID)).thenReturn(Optional.of(trackedEntity));

RelationshipOperationParams operationParams =
RelationshipOperationParams.builder()
Expand All @@ -157,8 +211,8 @@ void shouldMapOrderInGivenOrder()

@Test
void shouldMapNullOrderingParamsWhenNoOrderingParamsAreSpecified()
throws ForbiddenException, NotFoundException, BadRequestException {
when(trackedEntityService.getTrackedEntity(TE_UID)).thenReturn(trackedEntity);
throws ForbiddenException, NotFoundException {
when(relationshipStore.findTrackedEntity(TE_UID)).thenReturn(Optional.of(trackedEntity));

RelationshipOperationParams operationParams =
RelationshipOperationParams.builder().type(TRACKED_ENTITY).identifier(TE_UID).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import org.hisp.dhis.common.UidObject;
import org.hisp.dhis.jsontree.JsonArray;
import org.hisp.dhis.jsontree.JsonList;
import org.hisp.dhis.jsontree.JsonObject;
Expand Down Expand Up @@ -124,16 +125,16 @@ public static void assertTrackedEntityWithinRelationshipItem(
jsonTe.getTrackedEntityType(),
"trackedEntityType UID");
assertEquals(expected.getOrganisationUnit().getUid(), jsonTe.getOrgUnit(), "orgUnit UID");
assertTrue(jsonTe.getAttributes().isEmpty(), "attributes should be empty");
assertFalse(jsonTe.getAttributes().isEmpty(), "attributes should be empty");
assertFalse(
jsonTe.has("relationships"), "relationships is not returned within relationship items");
}

public static void assertHasOnlyUid(String expectedUid, String member, JsonObject json) {
public static void assertHasOnlyUid(UidObject expected, String member, JsonObject json) {
JsonObject j = json.getObject(member);
assertFalse(j.isEmpty(), member + " should not be empty");
assertHasOnlyMembers(j, member);
assertEquals(expectedUid, j.getString(member).string(), member + " UID");
assertEquals(expected.getUid(), j.getString(member).string(), member + " UID");
}

public static void assertEnrollmentWithinRelationship(
Expand All @@ -149,7 +150,7 @@ public static void assertEnrollmentWithinRelationship(
assertEquals(expected.getFollowup(), jsonEnrollment.getFollowUp(), "followUp");
assertEquals(
expected.getOrganisationUnit().getUid(), jsonEnrollment.getOrgUnit(), "orgUnit UID");
assertTrue(jsonEnrollment.getArray("events").isEmpty(), "events should be empty");
assertFalse(jsonEnrollment.getArray("events").isEmpty(), "events should be empty");
assertFalse(
jsonEnrollment.has("relationships"),
"relationships is not returned within relationship items");
Expand Down
Loading
Loading