Skip to content

Commit 45fff09

Browse files
committed
Allow non UTC lastUpdateTimestamp
1 parent 6b188a4 commit 45fff09

2 files changed

Lines changed: 92 additions & 12 deletions

File tree

src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@
6161

6262
import java.io.InputStream;
6363
import java.net.URI;
64-
import java.time.Instant;
64+
import java.time.LocalDateTime;
65+
import java.time.ZoneId;
66+
import java.time.format.DateTimeFormatter;
67+
import java.time.format.DateTimeParseException;
68+
import java.time.temporal.ChronoUnit;
6569
import java.util.*;
6670
import java.util.concurrent.Callable;
6771
import java.util.logging.Level;
@@ -488,21 +492,32 @@ public Command<DatasetVersion> handleLatestPublished() {
488492
}
489493

490494
protected void validateInternalTimestampIsNotOutdated(DvObject dvObject, String sourceLastUpdateTime) throws WrappedResponse {
491-
Date date = sourceLastUpdateTime != null ? DateUtil.parseDate(sourceLastUpdateTime, "yyyy-MM-dd'T'HH:mm:ss'Z'") : null;
492-
if (date == null) {
495+
LocalDateTime dtIN = null;
496+
try {
497+
dtIN = sourceLastUpdateTime != null ? LocalDateTime.parse(sourceLastUpdateTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME) : null;
498+
} catch (DateTimeParseException e) {
499+
}
500+
if (dtIN == null) {
493501
throw new WrappedResponse(
494-
badRequest(BundleUtil.getStringFromBundle("jsonparser.error.parsing.date", Collections.singletonList(sourceLastUpdateTime)))
502+
badRequest(BundleUtil.getStringFromBundle("jsonparser.error.parsing.date", List.of(sourceLastUpdateTime)))
495503
);
496504
}
497-
Instant instant = date.toInstant();
498-
Instant updateTimestamp =
499-
(dvObject instanceof DataFile) ? ((DataFile) dvObject).getFileMetadata().getDatasetVersion().getLastUpdateTime().toInstant() :
500-
(dvObject instanceof Dataset) ? ((Dataset) dvObject).getLatestVersion().getLastUpdateTime().toInstant() :
501-
instant;
502-
// granularity is to the second since the json output only returns dates in this format to the second
503-
if (updateTimestamp.getEpochSecond() != instant.getEpochSecond()) {
505+
506+
Date lastUpdateTimestamp =
507+
(dvObject instanceof DataFile) ? ((DataFile) dvObject).getFileMetadata().getDatasetVersion().getLastUpdateTime() :
508+
(dvObject instanceof Dataset) ? ((Dataset) dvObject).getLatestVersion().getLastUpdateTime() :
509+
null;
510+
511+
if (lastUpdateTimestamp != null) {
512+
LocalDateTime localDateTime = lastUpdateTimestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS);
513+
if (!localDateTime.equals(dtIN)) {
514+
throw new WrappedResponse(
515+
badRequest(BundleUtil.getStringFromBundle("abstractApiBean.error.internalVersionTimestampIsOutdated", List.of(sourceLastUpdateTime)))
516+
);
517+
}
518+
} else {
504519
throw new WrappedResponse(
505-
badRequest(BundleUtil.getStringFromBundle("abstractApiBean.error.internalVersionTimestampIsOutdated", Collections.singletonList(sourceLastUpdateTime)))
520+
badRequest(BundleUtil.getStringFromBundle("jsonparser.error.parsing.date", List.of(sourceLastUpdateTime)))
506521
);
507522
}
508523
}

src/test/java/edu/harvard/iq/dataverse/api/DatasetsTest.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
package edu.harvard.iq.dataverse.api;
22

3+
import edu.harvard.iq.dataverse.Dataset;
4+
import edu.harvard.iq.dataverse.DatasetVersion;
5+
import edu.harvard.iq.dataverse.util.DateUtil;
36
import org.junit.jupiter.api.Test;
7+
8+
import java.time.*;
9+
import java.time.format.DateTimeFormatter;
10+
import java.util.Date;
411
import java.util.HashSet;
12+
import java.util.List;
513
import java.util.Set;
614
import java.util.function.Predicate;
715
import java.util.stream.Collectors;
816

17+
import static org.assertj.core.api.Fail.fail;
918
import static org.junit.jupiter.api.Assertions.assertEquals;
1019
import static org.junit.jupiter.api.Assertions.assertTrue;
1120

@@ -55,4 +64,60 @@ public void testCleanup() {
5564
assertTrue(deleted.contains("1837fda17ce-d7b9987fc6e9_suffix"));
5665
assertTrue(deleted.contains("1837fda17ce-d7b9987fc6e9.aux"));
5766
}
67+
68+
@Test
69+
public void testValidateInternalTimestampIsNotOutdated() {
70+
Datasets dsBean = new Datasets();
71+
Dataset ds = new Dataset();
72+
DatasetVersion dsv = new DatasetVersion();
73+
dsv.setDataset(ds);
74+
ds.setVersions(List.of(dsv));
75+
76+
// setLastUpdateTime LOCAL TIME ZONE
77+
String str1 = "2023-10-01T10:00:00+05:00";
78+
LocalDateTime dt1 = LocalDateTime.parse(str1, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
79+
dsv.setLastUpdateTime(Date.from(dt1.atZone(ZoneId.systemDefault()).toInstant()));
80+
81+
// Test not Equal
82+
String str2 = "2023-10-01T11:00:00-08:00";
83+
try {
84+
dsBean.validateInternalTimestampIsNotOutdated(ds,str2);
85+
fail();
86+
} catch (AbstractApiBean.WrappedResponse e) {
87+
}
88+
89+
// Test Equal
90+
try {
91+
dsBean.validateInternalTimestampIsNotOutdated(ds,str1);
92+
} catch (AbstractApiBean.WrappedResponse e) {
93+
fail();
94+
}
95+
96+
// setLastUpdateTime UTC
97+
String str11 = "2023-10-01T10:00:00Z";
98+
Date dt11 = DateUtil.parseDate(str11, "yyyy-MM-dd'T'HH:mm:ss'Z'");
99+
dsv.setLastUpdateTime(dt11);
100+
101+
// Test Not Equal
102+
String str12 = "2023-10-01T11:00:00Z";
103+
try {
104+
dsBean.validateInternalTimestampIsNotOutdated(ds,str12);
105+
fail();
106+
} catch (AbstractApiBean.WrappedResponse e) {
107+
}
108+
109+
// Test Equal
110+
try {
111+
dsBean.validateInternalTimestampIsNotOutdated(ds,str11);
112+
} catch (AbstractApiBean.WrappedResponse e) {
113+
fail();
114+
}
115+
116+
// Test BAD Date/Time
117+
try {
118+
dsBean.validateInternalTimestampIsNotOutdated(ds,"invalid");
119+
fail();
120+
} catch (AbstractApiBean.WrappedResponse e) {
121+
}
122+
}
58123
}

0 commit comments

Comments
 (0)