diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java index a0c4e2cea34d..23afed9101d4 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java @@ -33,7 +33,9 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.Calendar; @@ -109,6 +111,9 @@ public class DateUtils { ObjectArrays.concat( SUPPORTED_DATE_ONLY_PARSERS, SUPPORTED_DATE_TIME_FORMAT_PARSERS, DateTimeParser.class); + private static final DateTimeFormatter ONLY_DATE_FORMATTER = + new DateTimeFormatterBuilder().append(null, SUPPORTED_DATE_ONLY_PARSERS).toFormatter(); + private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder().append(null, SUPPORTED_DATE_FORMAT_PARSERS).toFormatter(); @@ -662,8 +667,8 @@ public static String getPrettyInterval(Date start, Date end) { } /** - * Parses the given string into a Date using the supported date formats. Returns null if the - * string cannot be parsed. + * Parses the given string into a Date using the supported date formats. Add time at the beginning + * of the day if no time was provided. Returns null if the string cannot be parsed. * * @param dateString the date string. * @return a date. @@ -672,6 +677,29 @@ public static Date parseDate(String dateString) { return safeParseDateTime(dateString, DATE_FORMATTER); } + /** + * Parses the given string into a Date using the supported date formats. Add time at the end of + * the day if no time was provided. Returns null if the string cannot be parsed. + * + * @param dateString the date string. + * @return a date. + */ + public static Date parseDateEndOfTheDay(String dateString) { + if (StringUtils.isEmpty(dateString)) { + return null; + } + + try { + Date date = safeParseDateTime(dateString, ONLY_DATE_FORMATTER); + LocalDateTime localDateTime = + LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).with(LocalTime.MAX); + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } catch (IllegalArgumentException e) { + // dateString has time defined + } + return safeParseDateTime(dateString, DATE_FORMATTER); + } + /** * Parses the given string into a Date using the supported date formats. Returns null if the * string cannot be parsed. diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java index 67a71fec172b..2384c8056d90 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java @@ -192,6 +192,22 @@ public static T throwIfNull(T object, Supplier the function return type. + * @param the object type. + * @param function the function to be applied to non-null object. + */ + public static U applyIfNotNull(T object, Function function) { + if (object == null) { + return null; + } + + return function.apply(object); + } + /** * Util method that always returns a new Set, either instantiated from a non-null Set passed as an * argument, or if a null arg is passed then returning an empty Set. This helps reduce possible diff --git a/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/NotificationRuleActionImplementer.java b/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/NotificationRuleActionImplementer.java index 89804a28efb2..7ad52a99790c 100644 --- a/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/NotificationRuleActionImplementer.java +++ b/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/NotificationRuleActionImplementer.java @@ -37,9 +37,7 @@ import org.hisp.dhis.notification.logging.NotificationLoggingService; import org.hisp.dhis.notification.logging.NotificationValidationResult; import org.hisp.dhis.program.Enrollment; -import org.hisp.dhis.program.EnrollmentService; import org.hisp.dhis.program.Event; -import org.hisp.dhis.program.EventService; import org.hisp.dhis.program.notification.ProgramNotificationTemplate; import org.hisp.dhis.program.notification.ProgramNotificationTemplateService; import org.hisp.dhis.rules.models.RuleAction; @@ -62,10 +60,6 @@ abstract class NotificationRuleActionImplementer implements RuleActionImplemente protected final NotificationLoggingService notificationLoggingService; - protected final EnrollmentService enrollmentService; - - protected final EventService eventService; - protected ExternalNotificationLogEntry createLogEntry(String key, String templateUid) { ExternalNotificationLogEntry entry = new ExternalNotificationLogEntry(); entry.setLastSentAt(new Date()); diff --git a/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionScheduleMessageImplementer.java b/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionScheduleMessageImplementer.java index e89f953bdb3c..d57f58d6c209 100644 --- a/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionScheduleMessageImplementer.java +++ b/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionScheduleMessageImplementer.java @@ -36,9 +36,7 @@ import org.hisp.dhis.notification.logging.NotificationTriggerEvent; import org.hisp.dhis.notification.logging.NotificationValidationResult; import org.hisp.dhis.program.Enrollment; -import org.hisp.dhis.program.EnrollmentService; import org.hisp.dhis.program.Event; -import org.hisp.dhis.program.EventService; import org.hisp.dhis.program.notification.ProgramNotificationInstance; import org.hisp.dhis.program.notification.ProgramNotificationInstanceService; import org.hisp.dhis.program.notification.ProgramNotificationTemplate; @@ -70,15 +68,9 @@ public class RuleActionScheduleMessageImplementer extends NotificationRuleAction public RuleActionScheduleMessageImplementer( ProgramNotificationTemplateService programNotificationTemplateService, NotificationLoggingService notificationLoggingService, - EnrollmentService enrollmentService, - EventService eventService, ProgramNotificationInstanceService programNotificationInstanceService, NotificationTemplateService notificationTemplateService) { - super( - programNotificationTemplateService, - notificationLoggingService, - enrollmentService, - eventService); + super(programNotificationTemplateService, notificationLoggingService); this.programNotificationInstanceService = programNotificationInstanceService; this.notificationTemplateService = notificationTemplateService; } diff --git a/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionSendMessageImplementer.java b/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionSendMessageImplementer.java index e5eb61ccd5b2..e135557d08e6 100644 --- a/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionSendMessageImplementer.java +++ b/dhis-2/dhis-services/dhis-service-program-rule/src/main/java/org/hisp/dhis/programrule/engine/RuleActionSendMessageImplementer.java @@ -34,9 +34,7 @@ import org.hisp.dhis.notification.logging.NotificationTriggerEvent; import org.hisp.dhis.notification.logging.NotificationValidationResult; import org.hisp.dhis.program.Enrollment; -import org.hisp.dhis.program.EnrollmentService; import org.hisp.dhis.program.Event; -import org.hisp.dhis.program.EventService; import org.hisp.dhis.program.notification.ProgramNotificationTemplate; import org.hisp.dhis.program.notification.ProgramNotificationTemplateService; import org.hisp.dhis.program.notification.event.ProgramRuleEnrollmentEvent; @@ -72,14 +70,8 @@ public class RuleActionSendMessageImplementer extends NotificationRuleActionImpl public RuleActionSendMessageImplementer( ProgramNotificationTemplateService programNotificationTemplateService, NotificationLoggingService notificationLoggingService, - EnrollmentService enrollmentService, - EventService eventService, ApplicationEventPublisher publisher) { - super( - programNotificationTemplateService, - notificationLoggingService, - enrollmentService, - eventService); + super(programNotificationTemplateService, notificationLoggingService); this.publisher = publisher; } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParams.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParams.java index e07485afefdb..287fa994769c 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParams.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParams.java @@ -46,14 +46,16 @@ import org.hisp.dhis.fieldfiltering.FieldPath; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.program.Enrollment; +import org.hisp.dhis.program.Event; import org.hisp.dhis.program.Program; import org.hisp.dhis.program.ProgramStage; import org.hisp.dhis.program.ProgramStatus; import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria; import org.hisp.dhis.webapi.controller.tracker.export.PageRequestParams; -import org.hisp.dhis.webapi.controller.tracker.view.Event; import org.hisp.dhis.webapi.controller.tracker.view.TrackedEntity; import org.hisp.dhis.webapi.controller.tracker.view.User; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; /** * Represents query parameters sent to {@link EventsExportController}. @@ -139,9 +141,9 @@ public class EventRequestParams implements PageRequestParams { private Date scheduledBefore; - private Date updatedAfter; + private StartDateTime updatedAfter; - private Date updatedBefore; + private EndDateTime updatedBefore; private String updatedWithin; diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParamsMapper.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParamsMapper.java index 3458d316915d..1adc5d8cf1ef 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParamsMapper.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventRequestParamsMapper.java @@ -28,6 +28,7 @@ package org.hisp.dhis.webapi.controller.tracker.export.event; import static java.util.Collections.emptySet; +import static org.hisp.dhis.util.ObjectUtils.applyIfNotNull; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamsValidator.parseFilters; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamsValidator.validateDeprecatedParameter; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamsValidator.validateDeprecatedUidsParameter; @@ -48,6 +49,8 @@ import org.hisp.dhis.tracker.export.event.EventOperationParams.EventOperationParamsBuilder; import org.hisp.dhis.util.DateUtils; import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; import org.springframework.stereotype.Component; /** @@ -114,22 +117,10 @@ public EventOperationParams map(EventRequestParams eventRequestParams) EventOperationParamsBuilder builder = EventOperationParams.builder() - .programUid( - eventRequestParams.getProgram() != null - ? eventRequestParams.getProgram().getValue() - : null) - .programStageUid( - eventRequestParams.getProgramStage() != null - ? eventRequestParams.getProgramStage().getValue() - : null) - .orgUnitUid( - eventRequestParams.getOrgUnit() != null - ? eventRequestParams.getOrgUnit().getValue() - : null) - .trackedEntityUid( - eventRequestParams.getTrackedEntity() != null - ? eventRequestParams.getTrackedEntity().getValue() - : null) + .programUid(applyIfNotNull(eventRequestParams.getProgram(), UID::getValue)) + .programStageUid(applyIfNotNull(eventRequestParams.getProgramStage(), UID::getValue)) + .orgUnitUid(applyIfNotNull(eventRequestParams.getOrgUnit(), UID::getValue)) + .trackedEntityUid(applyIfNotNull(eventRequestParams.getTrackedEntity(), UID::getValue)) .programStatus(eventRequestParams.getProgramStatus()) .followUp(eventRequestParams.getFollowUp()) .orgUnitMode(orgUnitMode) @@ -139,16 +130,17 @@ public EventOperationParams map(EventRequestParams eventRequestParams) .occurredBefore(eventRequestParams.getOccurredBefore()) .scheduledAfter(eventRequestParams.getScheduledAfter()) .scheduledBefore(eventRequestParams.getScheduledBefore()) - .updatedAfter(eventRequestParams.getUpdatedAfter()) - .updatedBefore(eventRequestParams.getUpdatedBefore()) + .updatedAfter( + applyIfNotNull(eventRequestParams.getUpdatedAfter(), StartDateTime::toDate)) + .updatedBefore( + applyIfNotNull(eventRequestParams.getUpdatedBefore(), EndDateTime::toDate)) .updatedWithin(eventRequestParams.getUpdatedWithin()) .enrollmentEnrolledBefore(eventRequestParams.getEnrollmentEnrolledBefore()) .enrollmentEnrolledAfter(eventRequestParams.getEnrollmentEnrolledAfter()) .enrollmentOccurredBefore(eventRequestParams.getEnrollmentOccurredBefore()) .enrollmentOccurredAfter(eventRequestParams.getEnrollmentOccurredAfter()) .eventStatus(eventRequestParams.getStatus()) - .attributeCategoryCombo( - attributeCategoryCombo != null ? attributeCategoryCombo.getValue() : null) + .attributeCategoryCombo(applyIfNotNull(attributeCategoryCombo, UID::getValue)) .attributeCategoryOptions(UID.toValueSet(attributeCategoryOptions)) .idSchemes(eventRequestParams.getIdSchemes()) .includeAttributes(false) diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/EndDateTime.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/EndDateTime.java new file mode 100644 index 000000000000..8a9a0c605830 --- /dev/null +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/EndDateTime.java @@ -0,0 +1,58 @@ +/* + * 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.webdomain; + +import java.util.Date; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.hisp.dhis.util.DateUtils; + +/** + * EndDateTime represents an upper limit date and time used to filter results in search APIs. + * + *

EndDateTime accepts any date and time in ISO8601 format. If no time is defined, then the time + * at the end of the day is used by default. + * + *

This behavior, combined with {@link StartDateTime}, allows to correctly implement an interval + * search including start and end dates. + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class EndDateTime { + private final Date date; + + public static EndDateTime of(String date) { + return new EndDateTime(DateUtils.parseDateEndOfTheDay(date)); + } + + public Date toDate() { + if (date == null) { + return null; + } + return new Date(date.getTime()); + } +} diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/StartDateTime.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/StartDateTime.java new file mode 100644 index 000000000000..4b52f917ba0a --- /dev/null +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/StartDateTime.java @@ -0,0 +1,58 @@ +/* + * 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.webdomain; + +import java.util.Date; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.hisp.dhis.util.DateUtils; + +/** + * StartDateTime represents a lower limit date and time used to filter results in search APIs. + * + *

StartDateTime accepts any date and time in ISO8601 format. If no time is defined, then the + * time at the beginning of the day is used by default. + * + *

This behavior, combined with {@link EndDateTime}, allows to correctly implement an interval + * search including start and end dates. + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class StartDateTime { + private final Date date; + + public static StartDateTime of(String date) { + return new StartDateTime(DateUtils.parseDate(date)); + } + + public Date toDate() { + if (date == null) { + return null; + } + return new Date(date.getTime()); + } +} diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/common/UIDBindingTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/common/UIDBindingTest.java index c640defa4aff..e26ec4e674d5 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/common/UIDBindingTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/common/UIDBindingTest.java @@ -75,10 +75,7 @@ class UIDBindingTest { @BeforeEach public void setUp() { - mockMvc = - MockMvcBuilders.standaloneSetup(new UIDController()) - .setControllerAdvice(new CrudControllerAdvice()) - .build(); + mockMvc = MockMvcBuilders.standaloneSetup(new UIDController()).build(); } @Test diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/DatesBindingTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/DatesBindingTest.java new file mode 100644 index 000000000000..00f19e11f48a --- /dev/null +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/DatesBindingTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004-2022, 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.controller; + +import static org.hisp.dhis.dxf2.webmessage.WebMessageUtils.ok; +import static org.hisp.dhis.util.ObjectUtils.applyIfNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Date; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hisp.dhis.dxf2.webmessage.WebMessage; +import org.hisp.dhis.util.DateUtils; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.stereotype.Controller; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +class DatesBindingTest { + private static final String ENDPOINT = "/binding"; + + private MockMvc mockMvc; + private Date actualStartDateTime; + private Date actualEndDateTime; + + @BeforeEach + public void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(new BindingController()).build(); + } + + @Test + void shouldReturnADateAtTheEndOfTheDayWhenAnEndDateIsPassedWithoutTime() throws Exception { + mockMvc.perform(get(ENDPOINT).param("end", "2001-06-17")).andExpect(status().isOk()); + + assertNull(actualStartDateTime); + assertEquals("2001-06-17T23:59:59", DateUtils.toLongDate(actualEndDateTime)); + } + + @Test + void shouldReturnADateWithTimeWhenAnEndDateIsPassedWithTime() throws Exception { + mockMvc.perform(get(ENDPOINT).param("end", "2001-06-17T16:45:34")).andExpect(status().isOk()); + + assertNull(actualStartDateTime); + assertEquals("2001-06-17T16:45:34", DateUtils.toLongDate(actualEndDateTime)); + } + + @Test + void shouldReturnADateAtTheStartOfTheDayWhenAnStartDateIsPassedWithoutTime() throws Exception { + mockMvc.perform(get(ENDPOINT).param("start", "2001-06-17")).andExpect(status().isOk()); + + assertEquals("2001-06-17T00:00:00", DateUtils.toLongDate(actualStartDateTime)); + assertNull(actualEndDateTime); + } + + @Test + void shouldReturnADateWithTimeWhenAnStartDateIsPassedWithTime() throws Exception { + mockMvc.perform(get(ENDPOINT).param("start", "2001-06-17T16:45:34")).andExpect(status().isOk()); + + assertEquals("2001-06-17T16:45:34", DateUtils.toLongDate(actualStartDateTime)); + assertNull(actualEndDateTime); + } + + @Controller + private class BindingController { + @GetMapping(value = ENDPOINT) + public @ResponseBody WebMessage getDefault(Params params) { + actualStartDateTime = applyIfNotNull(params.getStart(), StartDateTime::toDate); + actualEndDateTime = applyIfNotNull(params.getEnd(), EndDateTime::toDate); + return ok(); + } + } + + @NoArgsConstructor + @Data + private class Params { + private StartDateTime start; + + private EndDateTime end; + } +} diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java index ff3d43a1ec16..a96e0dca9eac 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java @@ -61,10 +61,7 @@ class OrderBindingTest { @BeforeEach public void setUp() { - mockMvc = - MockMvcBuilders.standaloneSetup(new OrderingController()) - .setControllerAdvice(new CrudControllerAdvice()) - .build(); + mockMvc = MockMvcBuilders.standaloneSetup(new OrderingController()).build(); } @Test diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java index 60745765044d..6dc26cc79c73 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java @@ -52,10 +52,7 @@ class SpringBindingTest { @BeforeEach public void setUp() { - mockMvc = - MockMvcBuilders.standaloneSetup(new BindingController()) - .setControllerAdvice(new CrudControllerAdvice()) - .build(); + mockMvc = MockMvcBuilders.standaloneSetup(new BindingController()).build(); } @Test diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventImportRequestParamsMapperTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventImportRequestParamsMapperTest.java index 356d15fe2d55..9a9264b4a132 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventImportRequestParamsMapperTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/event/EventImportRequestParamsMapperTest.java @@ -77,6 +77,8 @@ import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserService; import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -262,15 +264,15 @@ void testMappingScheduledAfterBefore() throws BadRequestException { void shouldMapAfterAndBeforeDatesWhenSupplied() throws BadRequestException { EventRequestParams eventRequestParams = new EventRequestParams(); - Date updatedAfter = parseDate("2022-01-01"); + StartDateTime updatedAfter = StartDateTime.of("2022-01-01"); eventRequestParams.setUpdatedAfter(updatedAfter); - Date updatedBefore = parseDate("2022-09-12"); + EndDateTime updatedBefore = EndDateTime.of("2022-09-12"); eventRequestParams.setUpdatedBefore(updatedBefore); EventOperationParams params = mapper.map(eventRequestParams); - assertEquals(updatedAfter, params.getUpdatedAfter()); - assertEquals(updatedBefore, params.getUpdatedBefore()); + assertEquals(updatedAfter.toDate(), params.getUpdatedAfter()); + assertEquals(updatedBefore.toDate(), params.getUpdatedBefore()); } @Test @@ -288,9 +290,9 @@ void shouldMapUpdatedWithinDateWhenSupplied() throws BadRequestException { void shouldFailWithBadRequestExceptionWhenTryingToMapAllUpdateDatesTogether() { EventRequestParams eventRequestParams = new EventRequestParams(); - Date updatedAfter = parseDate("2022-01-01"); + StartDateTime updatedAfter = StartDateTime.of("2022-01-01"); eventRequestParams.setUpdatedAfter(updatedAfter); - Date updatedBefore = parseDate("2022-09-12"); + EndDateTime updatedBefore = EndDateTime.of("2022-09-12"); eventRequestParams.setUpdatedBefore(updatedBefore); String updatedWithin = "P6M"; eventRequestParams.setUpdatedWithin(updatedWithin);