From e13f8627ec99611b30c14301ac8b4e46ed2a98ca Mon Sep 17 00:00:00 2001 From: marc Date: Fri, 18 Oct 2024 09:05:50 +0200 Subject: [PATCH] fix: Add program param in attribute image endpoint [DHIS2-17173][2.39] (#18862) * fix: Add program param in attribute image endpoint [DHIS2-17173][2.39] * fix: Add program param in attribute image endpoint [DHIS2-17173][2.39] * fix: Add program param in attribute image endpoint [DHIS2-17173][2.39] --- .../TrackedEntityAttributeService.java | 4 + .../DefaultTrackedEntityAttributeService.java | 15 ++ .../TrackedEntityInstanceController.java | 38 +--- .../TrackedEntityInstanceSupportService.java | 51 +++++ .../TrackedEntityInstanceControllerTest.java | 27 ++- ...ackedEntityInstanceSupportServiceTest.java | 204 ++++++++++++++++++ 6 files changed, 301 insertions(+), 38 deletions(-) create mode 100644 dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportServiceTest.java diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/trackedentity/TrackedEntityAttributeService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/trackedentity/TrackedEntityAttributeService.java index 6bd94db4a495..ad74e81c49d0 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/trackedentity/TrackedEntityAttributeService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/trackedentity/TrackedEntityAttributeService.java @@ -120,6 +120,10 @@ public interface TrackedEntityAttributeService { Set getAllUserReadableTrackedEntityAttributes(User user); + Set getProgramAttributes(Program program); + + Set getTrackedEntityTypeAttributes(TrackedEntityType trackedEntityType); + Set getAllUserReadableTrackedEntityAttributes( User user, List programs, List trackedEntityTypes); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/DefaultTrackedEntityAttributeService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/DefaultTrackedEntityAttributeService.java index 0c23d0d50b02..0271c605b97f 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/DefaultTrackedEntityAttributeService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/DefaultTrackedEntityAttributeService.java @@ -328,6 +328,21 @@ public Set getAllUserReadableTrackedEntityAttributes(Use return getAllUserReadableTrackedEntityAttributes(user, programs, trackedEntityTypes); } + @Transactional(readOnly = true) + @Override + public Set getProgramAttributes(Program program) { + return getAllUserReadableTrackedEntityAttributes( + currentUserService.getCurrentUser(), List.of(program), List.of()); + } + + @Transactional(readOnly = true) + @Override + public Set getTrackedEntityTypeAttributes( + TrackedEntityType trackedEntityType) { + return getAllUserReadableTrackedEntityAttributes( + currentUserService.getCurrentUser(), List.of(), List.of(trackedEntityType)); + } + @Override @Transactional(readOnly = true) public Set getAllUserReadableTrackedEntityAttributes( diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceController.java index 50eeef64c5bf..dac99a783935 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceController.java @@ -47,7 +47,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; -import java.util.stream.Collectors; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -86,13 +85,12 @@ import org.hisp.dhis.schema.descriptors.TrackedEntityInstanceSchemaDescriptor; import org.hisp.dhis.system.grid.GridUtils; import org.hisp.dhis.trackedentity.TrackedEntityInstanceQueryParams; -import org.hisp.dhis.trackedentity.TrackerAccessManager; import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue; import org.hisp.dhis.user.CurrentUserService; -import org.hisp.dhis.user.User; import org.hisp.dhis.webapi.controller.event.mapper.TrackedEntityCriteriaMapper; import org.hisp.dhis.webapi.controller.event.webrequest.TrackedEntityInstanceCriteria; import org.hisp.dhis.webapi.controller.exception.BadRequestException; +import org.hisp.dhis.webapi.controller.exception.NotFoundException; import org.hisp.dhis.webapi.mvc.annotation.ApiVersion; import org.hisp.dhis.webapi.service.ContextService; import org.hisp.dhis.webapi.service.TrackedEntityInstanceSupportService; @@ -141,8 +139,6 @@ public class TrackedEntityInstanceController { private final FileResourceService fileResourceService; - private final TrackerAccessManager trackerAccessManager; - private final TrackedEntityInstanceSupportService trackedEntityInstanceSupportService; private final TrackedEntityCriteriaMapper criteriaMapper; @@ -199,35 +195,23 @@ public class TrackedEntityInstanceController { public void getAttributeImage( @PathVariable("teiId") String teiId, @PathVariable("attributeId") String attributeId, + @RequestParam(required = false) String programId, @RequestParam(required = false) Integer width, @RequestParam(required = false) Integer height, @RequestParam(required = false) ImageFileDimension dimension, HttpServletResponse response) throws WebMessageException { - User user = currentUserService.getCurrentUser(); - - org.hisp.dhis.trackedentity.TrackedEntityInstance trackedEntityInstance = - instanceService.getTrackedEntityInstance(teiId); - - List trackerAccessErrors = trackerAccessManager.canRead(user, trackedEntityInstance); - - List attribute = - trackedEntityInstance.getTrackedEntityAttributeValues().stream() - .filter(val -> val.getAttribute().getUid().equals(attributeId)) - .collect(Collectors.toList()); - - if (!trackerAccessErrors.isEmpty()) { - throw new WebMessageException( - unauthorized( - "You're not authorized to access the TrackedEntityInstance with id: " + teiId)); - } - - if (attribute.size() == 0) { - throw new WebMessageException(notFound("Attribute not found for ID " + attributeId)); + TrackedEntityAttributeValue value; + try { + value = + trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + teiId, attributeId, programId); + } catch (NotFoundException e) { + throw new WebMessageException(notFound(e.getMessage())); + } catch (IllegalAccessException e) { + throw new WebMessageException(unauthorized(e.getMessage())); } - TrackedEntityAttributeValue value = attribute.get(0); - if (value == null) { throw new WebMessageException(notFound("Value not found for ID " + attributeId)); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportService.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportService.java index abf39a250f0e..cf3c68f1896b 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportService.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportService.java @@ -31,6 +31,7 @@ import com.google.common.base.Joiner; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -43,14 +44,17 @@ import org.hisp.dhis.program.Program; import org.hisp.dhis.program.ProgramService; import org.hisp.dhis.trackedentity.TrackedEntityAttribute; +import org.hisp.dhis.trackedentity.TrackedEntityAttributeService; import org.hisp.dhis.trackedentity.TrackedEntityType; import org.hisp.dhis.trackedentity.TrackedEntityTypeService; import org.hisp.dhis.trackedentity.TrackerAccessManager; import org.hisp.dhis.trackedentity.TrackerOwnershipManager; +import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue; import org.hisp.dhis.user.CurrentUserService; import org.hisp.dhis.user.User; import org.hisp.dhis.webapi.controller.exception.NotFoundException; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; /** This service should not be used in the new tracker. */ @Service @@ -69,6 +73,8 @@ public class TrackedEntityInstanceSupportService { private final TrackedEntityTypeService trackedEntityTypeService; + private final TrackedEntityAttributeService attributeService; + @SneakyThrows public TrackedEntityInstance getTrackedEntityInstance(String id, String pr, List fields) { User user = currentUserService.getCurrentUser(); @@ -167,4 +173,49 @@ public TrackedEntityInstanceParams getTrackedEntityInstanceParams(List f return params; } + + @Transactional(readOnly = true) + public TrackedEntityAttributeValue getTrackedEntityAttributeValue( + String teiUid, String attributeUid, String programUid) + throws NotFoundException, IllegalAccessException { + User currentUser = currentUserService.getCurrentUser(); + + org.hisp.dhis.trackedentity.TrackedEntityInstance trackedEntity = + instanceService.getTrackedEntityInstance(teiUid); + if (trackedEntity == null) { + throw new NotFoundException("Tracked entity not found for ID " + teiUid); + } + + Set trackedEntityAttributes; + if (programUid != null) { + Program program = programService.getProgram(programUid); + if (program == null) { + throw new NotFoundException("Program not found for ID " + programUid); + } + + if (!trackerAccessManager.canRead(currentUser, trackedEntity, program, false).isEmpty()) { + throw new IllegalAccessException( + "You're not authorized to access the TrackedEntity with id: " + teiUid); + } + + trackedEntityAttributes = attributeService.getProgramAttributes(program); + } else { + if (!trackerAccessManager.canRead(currentUser, trackedEntity).isEmpty()) { + throw new IllegalAccessException( + "You're not authorized to access the TrackedEntity with id: " + teiUid); + } + + trackedEntityAttributes = + attributeService.getTrackedEntityTypeAttributes(trackedEntity.getTrackedEntityType()); + } + + if (trackedEntityAttributes.stream().noneMatch(tea -> tea.getUid().equals(attributeUid))) { + throw new NotFoundException("Attribute not found for ID " + attributeUid); + } + + return trackedEntity.getTrackedEntityAttributeValues().stream() + .filter(val -> val.getAttribute().getUid().equals(attributeUid)) + .findFirst() + .orElseThrow(() -> new NotFoundException("Value not found for ID " + attributeUid)); + } } diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceControllerTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceControllerTest.java index 26de69c2943f..7f9c2cafeb6c 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceControllerTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/event/TrackedEntityInstanceControllerTest.java @@ -42,7 +42,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.Set; +import java.util.List; import org.hisp.dhis.common.CodeGenerator; import org.hisp.dhis.common.ValueType; import org.hisp.dhis.dxf2.events.trackedentity.TrackedEntityInstanceService; @@ -56,11 +56,13 @@ import org.hisp.dhis.schema.descriptors.TrackedEntityInstanceSchemaDescriptor; import org.hisp.dhis.trackedentity.TrackedEntityAttribute; import org.hisp.dhis.trackedentity.TrackedEntityInstance; -import org.hisp.dhis.trackedentity.TrackerAccessManager; +import org.hisp.dhis.trackedentity.TrackedEntityType; +import org.hisp.dhis.trackedentity.TrackedEntityTypeAttribute; import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue; import org.hisp.dhis.user.CurrentUserService; import org.hisp.dhis.user.User; import org.hisp.dhis.webapi.controller.exception.BadRequestException; +import org.hisp.dhis.webapi.service.TrackedEntityInstanceSupportService; import org.hisp.dhis.webapi.strategy.old.tracker.imports.impl.TrackedEntityInstanceAsyncStrategyImpl; import org.hisp.dhis.webapi.strategy.old.tracker.imports.impl.TrackedEntityInstanceStrategyImpl; import org.hisp.dhis.webapi.strategy.old.tracker.imports.impl.TrackedEntityInstanceSyncStrategyImpl; @@ -95,12 +97,12 @@ class TrackedEntityInstanceControllerTest { @Mock private org.hisp.dhis.trackedentity.TrackedEntityInstanceService instanceService; - @Mock private TrackerAccessManager trackerAccessManager; - @Mock private FileResourceService fileResourceService; @Mock private TrackedEntityInstance trackedEntityInstance; + @Mock private TrackedEntityInstanceSupportService trackedEntityInstanceSupportService; + private static final String ENDPOINT = TrackedEntityInstanceSchemaDescriptor.API_ENDPOINT; @BeforeEach @@ -114,15 +116,13 @@ public void setUp() throws BadRequestException, IOException { null, currentUserService, fileResourceService, - trackerAccessManager, - null, + trackedEntityInstanceSupportService, null, new TrackedEntityInstanceStrategyImpl( trackedEntityInstanceSyncStrategy, trackedEntityInstanceAsyncStrategy), config); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); - when(currentUserService.getCurrentUser()).thenReturn(user); } @Test @@ -132,6 +132,10 @@ void shouldRetrieveImageAsAnAttachment() throws Exception { TrackedEntityAttribute attribute = new TrackedEntityAttribute(); attribute.setUid(attributeUid); attribute.setValueType(ValueType.IMAGE); + TrackedEntityTypeAttribute teta = new TrackedEntityTypeAttribute(); + teta.setUid(attributeUid); + TrackedEntityType trackedEntityType = new TrackedEntityType(); + trackedEntityType.setTrackedEntityTypeAttributes(List.of(teta)); TrackedEntityAttributeValue attributeValue = new TrackedEntityAttributeValue(); attributeValue.setAttribute(attribute); attributeValue.setValue("fileName"); @@ -143,13 +147,13 @@ void shouldRetrieveImageAsAnAttachment() throws Exception { File file = new ClassPathResource("images/dhis2.png").getFile(); - when(instanceService.getTrackedEntityInstance(teUid)).thenReturn(trackedEntityInstance); - when(trackedEntityInstance.getTrackedEntityAttributeValues()) - .thenReturn(Set.of(attributeValue)); when(fileResourceService.getFileResource("fileName")).thenReturn(fileResource); when(fileResourceService.getFileResourceContent(fileResource)) .thenReturn(new FileInputStream(file)); when(config.getProperty(ConfigurationKey.CSP_HEADER_VALUE)).thenReturn("script-src 'none';"); + when(trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + teUid, attributeUid, null)) + .thenReturn(attributeValue); mockMvc .perform( @@ -166,7 +170,7 @@ void shouldRetrieveImageAsAnAttachment() throws Exception { @Test void shouldCallSyncStrategy() throws Exception { - + when(currentUserService.getCurrentUser()).thenReturn(user); when(trackedEntityInstanceSyncStrategy.mergeOrDeleteTrackedEntityInstances(any())) .thenReturn(new ImportSummaries()); @@ -181,6 +185,7 @@ void shouldCallSyncStrategy() throws Exception { @Test void shouldCallAsyncStrategy() throws Exception { + when(currentUserService.getCurrentUser()).thenReturn(user); mockMvc .perform( post(ENDPOINT) diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportServiceTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportServiceTest.java new file mode 100644 index 000000000000..d9e2e1de1a6c --- /dev/null +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/service/TrackedEntityInstanceSupportServiceTest.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2004-2024, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.webapi.service; + +import static java.util.Collections.emptyList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Set; +import org.hisp.dhis.common.ValueType; +import org.hisp.dhis.program.Program; +import org.hisp.dhis.program.ProgramService; +import org.hisp.dhis.trackedentity.TrackedEntityAttribute; +import org.hisp.dhis.trackedentity.TrackedEntityAttributeService; +import org.hisp.dhis.trackedentity.TrackedEntityInstance; +import org.hisp.dhis.trackedentity.TrackedEntityType; +import org.hisp.dhis.trackedentity.TrackedEntityTypeAttribute; +import org.hisp.dhis.trackedentity.TrackerAccessManager; +import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue; +import org.hisp.dhis.user.CurrentUserService; +import org.hisp.dhis.user.User; +import org.hisp.dhis.webapi.controller.exception.NotFoundException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class TrackedEntityInstanceSupportServiceTest { + + @Mock private ProgramService programService; + + @Mock private TrackerAccessManager trackerAccessManager; + + @Mock private org.hisp.dhis.trackedentity.TrackedEntityInstanceService instanceService; + + @Mock private TrackedEntityAttributeService attributeService; + + @Mock private CurrentUserService currentUserService; + + @InjectMocks private TrackedEntityInstanceSupportService trackedEntityInstanceSupportService; + + private TrackedEntityInstance trackedEntity; + + private Program program; + + private User user; + + private TrackedEntityAttributeValue trackedEntityAttributeValue; + + private TrackedEntityAttribute tea; + + @BeforeEach + public void setUpTest() { + TrackedEntityType trackedEntityType = new TrackedEntityType("TET", "desc"); + trackedEntityType.setAutoFields(); + trackedEntity = new TrackedEntityInstance(); + trackedEntity.setAutoFields(); + trackedEntity.setTrackedEntityType(trackedEntityType); + program = new Program("A"); + program.setUid("A"); + program.setTrackedEntityType(trackedEntityType); + user = new User(); + + trackedEntity = new TrackedEntityInstance(); + trackedEntity.setUid("TeUid12345"); + trackedEntity.setTrackedEntityType(trackedEntityType); + tea = new TrackedEntityAttribute(); + tea.setUid("TeaUid12345"); + tea.setUnique(true); + tea.setValueType(ValueType.TEXT); + tea.setOrgunitScope(false); + + trackedEntityAttributeValue = + new TrackedEntityAttributeValue(tea, trackedEntity, "attribute value"); + trackedEntity.setTrackedEntityAttributeValues(Set.of(trackedEntityAttributeValue)); + + TrackedEntityTypeAttribute trackedEntityTypeAttribute = new TrackedEntityTypeAttribute(); + trackedEntityTypeAttribute.setTrackedEntityAttribute(tea); + trackedEntityType.setTrackedEntityTypeAttributes(List.of(trackedEntityTypeAttribute)); + trackedEntity.setTrackedEntityType(trackedEntityType); + + when(currentUserService.getCurrentUser()).thenReturn(user); + } + + @Test + void shouldWorkWhenGettingAttributeValueIfIsProgramAttribute() + throws NotFoundException, IllegalAccessException { + when(instanceService.getTrackedEntityInstance(trackedEntity.getUid())) + .thenReturn(trackedEntity); + when(programService.getProgram(program.getUid())).thenReturn(program); + when(trackerAccessManager.canRead(user, trackedEntity, program, false)).thenReturn(emptyList()); + when(attributeService.getProgramAttributes(program)).thenReturn(Set.of(tea)); + + assertEquals( + trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + trackedEntity.getUid(), tea.getUid(), program.getUid()), + trackedEntityAttributeValue); + } + + @Test + void shouldFailWhenGettingAttributeValueIfProgramDoesNotExist() { + when(instanceService.getTrackedEntityInstance(trackedEntity.getUid())) + .thenReturn(trackedEntity); + + Exception exception = + assertThrows( + NotFoundException.class, + () -> + trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + trackedEntity.getUid(), tea.getUid(), program.getUid())); + assertEquals("Program not found for ID " + program.getUid(), exception.getMessage()); + } + + @Test + void shouldFailWhenGettingAttributeValueIfTeProgramNotAccessible() { + when(instanceService.getTrackedEntityInstance(trackedEntity.getUid())) + .thenReturn(trackedEntity); + when(programService.getProgram(program.getUid())).thenReturn(program); + when(trackerAccessManager.canRead(user, trackedEntity, program, false)) + .thenReturn(List.of("error")); + + Exception exception = + assertThrows( + IllegalAccessException.class, + () -> + trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + trackedEntity.getUid(), tea.getUid(), program.getUid())); + assertEquals( + "You're not authorized to access the TrackedEntity with id: " + trackedEntity.getUid(), + exception.getMessage()); + } + + @Test + void shouldWorkWhenGettingAttributeValueIfIsTrackedEntityTypeAttribute() + throws NotFoundException, IllegalAccessException { + when(instanceService.getTrackedEntityInstance(trackedEntity.getUid())) + .thenReturn(trackedEntity); + when(trackerAccessManager.canRead(user, trackedEntity)).thenReturn(emptyList()); + when(attributeService.getTrackedEntityTypeAttributes(trackedEntity.getTrackedEntityType())) + .thenReturn(Set.of(tea)); + + assertEquals( + trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + trackedEntity.getUid(), tea.getUid(), null), + trackedEntityAttributeValue); + } + + @Test + void shouldFailWhenGettingAttributeValueIfTrackedEntityDoesNotExist() { + Exception exception = + assertThrows( + NotFoundException.class, + () -> + trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + trackedEntity.getUid(), tea.getUid(), null)); + assertEquals( + "Tracked entity not found for ID " + trackedEntity.getUid(), exception.getMessage()); + } + + @Test + void shouldFailWhenGettingAttributeIfAttributeNotFound() { + when(instanceService.getTrackedEntityInstance(trackedEntity.getUid())) + .thenReturn(trackedEntity); + when(trackerAccessManager.canRead(user, trackedEntity)).thenReturn(emptyList()); + + Exception exception = + assertThrows( + NotFoundException.class, + () -> + trackedEntityInstanceSupportService.getTrackedEntityAttributeValue( + trackedEntity.getUid(), tea.getUid(), null)); + assertEquals("Attribute not found for ID " + tea.getUid(), exception.getMessage()); + } +}