Skip to content

Commit

Permalink
Merge pull request #3323 from AtlasOfLivingAustralia/feature/issue3291
Browse files Browse the repository at this point in the history
project explorer start date and end date with client timezone
  • Loading branch information
chrisala authored Sep 12, 2024
2 parents a3662b0 + 5411a7b commit 20e86c6
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 8 deletions.
5 changes: 5 additions & 0 deletions grails-app/assets/javascripts/projectExplorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ var DatePickerModel = function(fromDate, toDate, isFilterByCompletedProjects, ur
var reloadWithDatesAndOption = function(newFromDate, newToDate, isFilterByCompletedProjects) {
var parsedNewFromDate = moment(newFromDate);
var parsedNewToDate = moment(newToDate);
var clientTimeZone = moment.tz.guess();
if (newFromDate && parsedNewFromDate.isValid()) {
urlWithoutDates += urlWithoutDates?'&':'?';
urlWithoutDates += 'fromDate='+moment(newFromDate).format(formatString);
Expand All @@ -66,6 +67,10 @@ var DatePickerModel = function(fromDate, toDate, isFilterByCompletedProjects, ur
urlWithoutDates += urlWithoutDates?'&':'?';
urlWithoutDates += 'isFilterByCompletedProjects='+isFilterByCompletedProjects;
}
if (clientTimeZone) {
urlWithoutDates += urlWithoutDates?'&':'?';
urlWithoutDates += 'clientTimeZone='+ encodeURIComponent(clientTimeZone);
}
$location.href = urlWithoutDates;
}

Expand Down
20 changes: 17 additions & 3 deletions grails-app/services/au/org/ala/merit/SearchService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import grails.core.GrailsApplication
import groovy.json.JsonSlurper
import groovy.util.logging.Slf4j
import org.apache.commons.lang.StringUtils
import org.joda.time.DateTime
import org.joda.time.DateTimeZone
import org.springframework.beans.factory.annotation.Autowired

import javax.annotation.PostConstruct
Expand All @@ -21,6 +23,7 @@ class SearchService {
def userService

private static final int FACET_LIMIT = 1500
static final String PLANNED_DATE_FORMAT = "yyyy-MM-dd"

@PostConstruct
private void init() {
Expand Down Expand Up @@ -157,15 +160,21 @@ class SearchService {
}

private void handleDateFilters(params) {
String fromDate = params.fromDate, toDate = params.toDate, clientTimeZone = params.clientTimeZone ?: grailsApplication.config.getProperty('clientTimeZone.defaultZone', 'Australia/Sydney')
DateTimeZone timeZone = DateTimeZone.forTimeZone(TimeZone.getTimeZone(clientTimeZone))
if ((params.isFilterByCompletedProjects ?: 'false').toBoolean()) {
if (params.fromDate || params.toDate) {
List fq = params.getList('fq')
if (!params.fromDate) {
fq += "_query:(plannedStartDate:[* TO ${params.toDate}) AND plannedEndDate:[* TO ${params.toDate}))"
String toDateUTC = getIsoDateFromClientDate(toDate, timeZone)
fq += "_query:(plannedStartDate:[* TO ${toDateUTC}) AND plannedEndDate:[* TO ${toDateUTC}))"
} else if (!params.toDate) {
fq += "_query:(plannedStartDate:[${params.fromDate} TO *] AND plannedEndDate:[${params.fromDate} TO *])"
String fromDateUTC = getIsoDateFromClientDate(fromDate, timeZone)
fq += "_query:(plannedStartDate:[${fromDateUTC} TO *] AND plannedEndDate:[${fromDateUTC} TO *])"
} else {
fq += "_query:(plannedStartDate:[${params.fromDate} TO ${params.toDate}] AND plannedEndDate:[${params.fromDate} TO ${params.toDate}])"
String fromDateUTC = getIsoDateFromClientDate(fromDate, timeZone)
String toDateUTC = getIsoDateFromClientDate(toDate, timeZone)
fq += "_query:(plannedStartDate:[${fromDateUTC} TO ${toDateUTC}] AND plannedEndDate:[${fromDateUTC} TO ${toDateUTC}])"
}
params.fq = fq
}
Expand All @@ -184,6 +193,11 @@ class SearchService {
}
}

String getIsoDateFromClientDate(String clientDate, DateTimeZone timeZone) {
DateTime clientDateDateTime = DateUtils.parseDisplayDate(clientDate, PLANNED_DATE_FORMAT , timeZone)
DateUtils.formatAsISOStringNoMillis(clientDateDateTime.toDate())
}

private handleActivityDateFilters(params) {
if (params.fromDate || params.toDate) {
List fq = params.getList('fq')
Expand Down
6 changes: 6 additions & 0 deletions grails-app/views/home/_downloadAllAsXlsx.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
<g:if test="${params.query}">
<input type="hidden" name="query" value="${params.query.encodeAsHTML()}">
</g:if>
<g:if test="${params.isFilterByCompletedProjects}">
<input type="hidden" name="isFilterByCompletedProjects" value="${params.isFilterByCompletedProjects.encodeAsHTML()}"/>
</g:if>
<g:if test="${params.clientTimeZone}">
<input type="hidden" name="clientTimeZone" value="${params.clientTimeZone.encodeAsHTML()}"/>
</g:if>
<br/></p><strong>Project Information</strong>
<ul class="unstyled">
<g:each in="${['Projects', 'Output Targets', 'Sites', 'Reports', 'Report Summary', 'Documents', 'Blog']}" var="name">
Expand Down
4 changes: 3 additions & 1 deletion grails-app/views/home/_projectFinder.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@
<tbody>
<tr>
<td width="50%"><g:render template="downloadAllAsXlsx"/></td>
<td width="50%"><a target="_blank" href=""${grailsApplication.config.getProperty('grails.serverURL')}"/search/downloadAllData<fc:formatParams params="${params}"/>view=json">JSON</a></td>
<td width="50%"><a target="_blank" href="${grailsApplication.config.getProperty('grails.serverURL')}/search/downloadAllData<fc:formatParams params="${params}"/>&view=json">JSON</a></td>
</tr>
</tbody>
</table>
Expand Down Expand Up @@ -482,6 +482,8 @@
params += '&isFilterByCompletedProjects=' + ${params.isFilterByCompletedProjects.encodeAsJavaScript()};
</g:if>

params += "&clientTimeZone=" + encodeURIComponent(moment.tz.guess() || '');

$.post(url, params).done(function(data1) {
//console.log("getJSON data", data);
var data
Expand Down
5 changes: 5 additions & 0 deletions grails-app/views/shared/_sites.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@
<g:if test="${params.query}">
url += "&query=${params.query.encodeAsURL()}"
</g:if>
<g:if test="${params.isFilterByCompletedProjects}">
url += "&isFilterByCompletedProjects=${params.isFilterByCompletedProjects.encodeAsURL()}"
</g:if>
url += "&clientTimeZone=" + encodeURIComponent(moment.tz.guess() || '');

$("#legend-table").hide();
$("#map-colorby-status").show();
$.getJSON(url, function(data) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/groovy/au/org/ala/merit/DateUtils.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ class DateUtils {
return DISPLAY_DATE_FORMATTER.parseDateTime(displayDateString)
}

static DateTime parseDisplayDate(String dateString, String format) {
DateTimeFormat.forPattern(format).withZone(DateTimeZone.default).parseDateTime(dateString)
static DateTime parseDisplayDate(String dateString, String format, DateTimeZone zone = DateTimeZone.default) {
DateTimeFormat.forPattern(format).withZone(zone).parseDateTime(dateString)
}

static DateTime now() {
Expand Down
25 changes: 24 additions & 1 deletion src/test/groovy/au/org/ala/merit/SearchServiceSpec.groovy
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package au.org.ala.merit

import au.org.ala.merit.hub.HubSettings
import grails.core.GrailsApplication
import grails.testing.spring.AutowiredTest
import org.apache.http.HttpStatus
import org.joda.time.DateTimeZone
import spock.lang.Specification

class SearchServiceSpec extends Specification implements AutowiredTest{
Expand Down Expand Up @@ -80,6 +80,29 @@ class SearchServiceSpec extends Specification implements AutowiredTest{
result == true
}

def "getIsoDateFromClientDate with various timezones"() {
expect: "The correct ISO date is returned for each date and time zone"
service.getIsoDateFromClientDate(clientDate, timeZone) == expectedIsoDate

where:
clientDate | timeZone | expectedIsoDate
"2024-09-10" | DateTimeZone.forID("Australia/Sydney") | "2024-09-09T14:00:00Z"
"2024-09-10" | DateTimeZone.forID("Australia/Perth") | "2024-09-09T16:00:00Z"
"2024-09-10" | DateTimeZone.forID("Australia/Darwin") | "2024-09-09T14:30:00Z"
}

def "getIsoDateFromClientDate throws exception for invalid input"() {
when: "Invalid input is passed to the method"
service.getIsoDateFromClientDate(clientDate, timeZone)

then: "An IllegalArgumentException is thrown"
thrown(IllegalArgumentException)

where: "Different invalid inputs are provided"
clientDate | timeZone
"invalid-date-format" | DateTimeZone.forID("Australia/Sydney")
}

private List stubGeoReponseFromCoordinateList(List coords) {
List results = new ArrayList(coords.size())
coords.each { List coord ->
Expand Down
4 changes: 3 additions & 1 deletion src/test/js/spec/DatePickerModelSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ describe("The documents contains view models for working with documents", functi
expect($location.href).toBeUndefined();

model.fromDate('2022-02-01');
expect($location.href).toEqual('?query=Test&fromDate=2022-02-01&toDate=2022-06-30&isFilterByCompletedProjects=true');
var location = $location.href;
location = location.replace(/&?clientTimeZone=[^&]*/, '');
expect(location).toEqual('?query=Test&fromDate=2022-02-01&toDate=2022-06-30&isFilterByCompletedProjects=true');
});
});

0 comments on commit 20e86c6

Please sign in to comment.