Skip to content
Snippets Groups Projects
Commit 9af5380e authored by Martin Lowe's avatar Martin Lowe :flag_ca: Committed by Martin Lowe
Browse files

Update listings to use date strings instead of timestamps #32


Added support for RFC 3339 date string conversion. Updated dummy script
to use moment.js to create RFC date strings.

Change-Id: I98324ddf19b20e6746eab7a576c57c67c96e8ae1
Signed-off-by: Martin Lowe's avatarMartin Lowe <martin.lowe@eclipse-foundation.org>
parent d793e7be
No related branches found
No related tags found
No related merge requests found
...@@ -112,6 +112,19 @@ ...@@ -112,6 +112,19 @@
"path-exists": "^3.0.0" "path-exists": "^3.0.0"
} }
}, },
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"moment-timezone": {
"version": "0.5.27",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.27.tgz",
"integrity": "sha512-EIKQs7h5sAsjhPCqN6ggx6cEbs94GK050254TIJySD1bzoM5JTYDwAU1IoVOeTOL6Gm27kYJ51/uuvq1kIlrbw==",
"requires": {
"moment": ">= 2.9.0"
}
},
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"license": "EPL-2.0", "license": "EPL-2.0",
"dependencies": { "dependencies": {
"axios": "^0.19.0", "axios": "^0.19.0",
"moment-timezone": "^0.5.27",
"random-words": "^1.1.0", "random-words": "^1.1.0",
"uuid": "^3.3.3", "uuid": "^3.3.3",
"yargs": "^14.0.0" "yargs": "^14.0.0"
......
...@@ -48,11 +48,11 @@ public class Listing extends NodeBase { ...@@ -48,11 +48,11 @@ public class Listing extends NodeBase {
@SortableField(name = DatabaseFieldNames.CREATION_DATE) @SortableField(name = DatabaseFieldNames.CREATION_DATE)
@JsonbProperty(DatabaseFieldNames.CREATION_DATE) @JsonbProperty(DatabaseFieldNames.CREATION_DATE)
private long creationDate; private String creationDate;
@SortableField(name = DatabaseFieldNames.UPDATE_DATE) @SortableField(name = DatabaseFieldNames.UPDATE_DATE)
@JsonbProperty(DatabaseFieldNames.UPDATE_DATE) @JsonbProperty(DatabaseFieldNames.UPDATE_DATE)
private long updateDate; private String updateDate;
@JsonbProperty(DatabaseFieldNames.LICENSE_TYPE) @JsonbProperty(DatabaseFieldNames.LICENSE_TYPE)
private String license; private String license;
private List<String> marketIds; private List<String> marketIds;
...@@ -224,28 +224,28 @@ public class Listing extends NodeBase { ...@@ -224,28 +224,28 @@ public class Listing extends NodeBase {
/** /**
* @return the creationDate * @return the creationDate
*/ */
public long getCreationDate() { public String getCreationDate() {
return creationDate; return creationDate;
} }
/** /**
* @param creationDate the creationDate to set * @param creationDate the creationDate to set
*/ */
public void setCreationDate(long creationDate) { public void setCreationDate(String creationDate) {
this.creationDate = creationDate; this.creationDate = creationDate;
} }
/** /**
* @return the updateDate * @return the updateDate
*/ */
public long getUpdateDate() { public String getUpdateDate() {
return updateDate; return updateDate;
} }
/** /**
* @param updateDate the updateDate to set * @param updateDate the updateDate to set
*/ */
public void setUpdateDate(long updateDate) { public void setUpdateDate(String updateDate) {
this.updateDate = updateDate; this.updateDate = updateDate;
} }
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
*/ */
package org.eclipsefoundation.marketplace.dto.codecs; package org.eclipsefoundation.marketplace.dto.codecs;
import java.util.Date;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -25,6 +24,7 @@ import org.eclipsefoundation.marketplace.dto.converters.CategoryConverter; ...@@ -25,6 +24,7 @@ import org.eclipsefoundation.marketplace.dto.converters.CategoryConverter;
import org.eclipsefoundation.marketplace.dto.converters.OrganizationConverter; import org.eclipsefoundation.marketplace.dto.converters.OrganizationConverter;
import org.eclipsefoundation.marketplace.dto.converters.ListingVersionConverter; import org.eclipsefoundation.marketplace.dto.converters.ListingVersionConverter;
import org.eclipsefoundation.marketplace.dto.converters.TagConverter; import org.eclipsefoundation.marketplace.dto.converters.TagConverter;
import org.eclipsefoundation.marketplace.helper.DateTimeHelper;
import org.eclipsefoundation.marketplace.namespace.DatabaseFieldNames; import org.eclipsefoundation.marketplace.namespace.DatabaseFieldNames;
import com.mongodb.MongoClient; import com.mongodb.MongoClient;
...@@ -76,13 +76,13 @@ public class ListingCodec implements CollectibleCodec<Listing> { ...@@ -76,13 +76,13 @@ public class ListingCodec implements CollectibleCodec<Listing> {
doc.put(DatabaseFieldNames.TOTAL_NSTALLS, value.getInstallsTotal()); doc.put(DatabaseFieldNames.TOTAL_NSTALLS, value.getInstallsTotal());
doc.put(DatabaseFieldNames.LICENSE_TYPE, value.getLicense()); doc.put(DatabaseFieldNames.LICENSE_TYPE, value.getLicense());
doc.put(DatabaseFieldNames.LISTING_STATUS, value.getStatus()); doc.put(DatabaseFieldNames.LISTING_STATUS, value.getStatus());
doc.put(DatabaseFieldNames.UPDATE_DATE, new Date(value.getUpdateDate())); doc.put(DatabaseFieldNames.UPDATE_DATE, DateTimeHelper.toRFC3339(value.getUpdateDate()));
doc.put(DatabaseFieldNames.CREATION_DATE, new Date(value.getCreationDate())); doc.put(DatabaseFieldNames.CREATION_DATE, DateTimeHelper.toRFC3339(value.getCreationDate()));
doc.put(DatabaseFieldNames.FOUNDATION_MEMBER_FLAG, value.isFoundationMember()); doc.put(DatabaseFieldNames.FOUNDATION_MEMBER_FLAG, value.isFoundationMember());
doc.put(DatabaseFieldNames.CATEGORY_IDS, value.getCategoryIds()); doc.put(DatabaseFieldNames.CATEGORY_IDS, value.getCategoryIds());
doc.put(DatabaseFieldNames.SCREENSHOTS, value.getScreenshots()); doc.put(DatabaseFieldNames.SCREENSHOTS, value.getScreenshots());
doc.put(DatabaseFieldNames.MARKET_IDS, value.getMarketIds()); doc.put(DatabaseFieldNames.MARKET_IDS, value.getMarketIds());
// for nested document types, use the converters to safely transform into BSON // for nested document types, use the converters to safely transform into BSON
// documents // documents
doc.put(DatabaseFieldNames.LISTING_ORGANIZATIONS, organizationConverter.convert(value.getOrganization())); doc.put(DatabaseFieldNames.LISTING_ORGANIZATIONS, organizationConverter.convert(value.getOrganization()));
...@@ -102,7 +102,7 @@ public class ListingCodec implements CollectibleCodec<Listing> { ...@@ -102,7 +102,7 @@ public class ListingCodec implements CollectibleCodec<Listing> {
public Listing decode(BsonReader reader, DecoderContext decoderContext) { public Listing decode(BsonReader reader, DecoderContext decoderContext) {
Document document = documentCodec.decode(reader, decoderContext); Document document = documentCodec.decode(reader, decoderContext);
Listing out = new Listing(); Listing out = new Listing();
// for each field, get the value from the encoded object and set it in POJO // for each field, get the value from the encoded object and set it in POJO
out.setId(document.getString(DatabaseFieldNames.DOCID)); out.setId(document.getString(DatabaseFieldNames.DOCID));
out.setTitle(document.getString(DatabaseFieldNames.TITLE)); out.setTitle(document.getString(DatabaseFieldNames.TITLE));
...@@ -133,9 +133,9 @@ public class ListingCodec implements CollectibleCodec<Listing> { ...@@ -133,9 +133,9 @@ public class ListingCodec implements CollectibleCodec<Listing> {
out.setCategories(document.getList(DatabaseFieldNames.LISTING_CATEGORIES, Document.class).stream() out.setCategories(document.getList(DatabaseFieldNames.LISTING_CATEGORIES, Document.class).stream()
.map(categoryConverter::convert).collect(Collectors.toList())); .map(categoryConverter::convert).collect(Collectors.toList()));
// convert date to epoch milli // convert date to date string
out.setCreationDate(document.getDate(DatabaseFieldNames.CREATION_DATE).toInstant().toEpochMilli()); out.setCreationDate(DateTimeHelper.toRFC3339(document.getDate(DatabaseFieldNames.CREATION_DATE)));
out.setUpdateDate(document.getDate(DatabaseFieldNames.UPDATE_DATE).toInstant().toEpochMilli()); out.setUpdateDate(DateTimeHelper.toRFC3339(document.getDate(DatabaseFieldNames.UPDATE_DATE)));
return out; return out;
} }
......
/* Copyright (c) 2019 Eclipse Foundation and others.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License 2.0
* which is available at http://www.eclipse.org/legal/epl-v20.html,
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.marketplace.helper;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Central implementation for handling date time conversion in the service.
* Class uses Java8 DateTime formatters, creating an internal format that
* represents RFC 3339
*
* @author Martin Lowe
*/
public class DateTimeHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(DateTimeHelper.class);
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX");
/**
* Converts RFC 3339 compliant date string to date object. If non compliant
* string is passed, issue is logged and null is returned. If negative UTC
* timezone (-00:00) is passed, UTC time zone is assumed.
*
* @param dateString an RFC 3339 date string.
* @return a date object representing time in date string, or null if not in RFC
* 3339 format.
*/
public static Date toRFC3339(String dateString) {
try {
return Date.from(ZonedDateTime.parse(dateString, formatter).toInstant());
} catch (DateTimeParseException e) {
LOGGER.warn("Could not parse date from string '{}'", dateString, e);
return null;
}
}
/**
* Converts passed date to RFC 3339 compliant date string. Time is adjusted to
* be in UTC time.
*
* @param date the date object to convert to RFC 3339 format.
* @return the RFC 3339 format date string.
*/
public static String toRFC3339(Date date) {
return formatter.format(date.toInstant().atZone(ZoneId.of("UTC")));
}
// hide constructor
private DateTimeHelper() {
}
}
...@@ -26,6 +26,7 @@ const argv = require('yargs') ...@@ -26,6 +26,7 @@ const argv = require('yargs')
}).argv; }).argv;
let max = argv.c; let max = argv.c;
var moment = require('moment-timezone');
const lic_types = ["EPL-2.0","EPL-1.0","GPL"]; const lic_types = ["EPL-2.0","EPL-1.0","GPL"];
const platforms = ["windows","macos","linux"]; const platforms = ["windows","macos","linux"];
const eclipseVs = ["4.6","4.7","4.8","4.9","4.10","4.11","4.12"]; const eclipseVs = ["4.6","4.7","4.8","4.9","4.10","4.11","4.12"];
...@@ -143,6 +144,8 @@ function generateJSON(id) { ...@@ -143,6 +144,8 @@ function generateJSON(id) {
"status": "draft", "status": "draft",
"support_url": "https://jakarta.ee/about/faq", "support_url": "https://jakarta.ee/about/faq",
"license_type": lic_types[Math.floor(Math.random()*lic_types.length)], "license_type": lic_types[Math.floor(Math.random()*lic_types.length)],
"created": moment.tz((new Date()).toISOString(), "America/Toronto").format(),
"changed": moment.tz((new Date()).toISOString(), "America/Toronto").format(),
"authors": [ "authors": [
{ {
"full_name": "Martin Lowe", "full_name": "Martin Lowe",
......
/* Copyright (c) 2019 Eclipse Foundation and others.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License 2.0
* which is available at http://www.eclipse.org/legal/epl-v20.html,
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.marketplace.helper;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
/**
* Test class for {@linkplain DateTimeHelper}
*
* @author Martin Lowe
*/
@QuarkusTest
public class DateTimeHelperTest {
@Test
public void validRFC3339DateStringIn() {
// Test standard time
String dateString = "1996-12-19T16:39:57-08:00";
// Timezone needs to be set as otherwise it defaults to system local offset.
TimeZone tz = TimeZone.getTimeZone(ZoneId.of("GMT-08:00"));
Calendar c = Calendar.getInstance(tz);
Date d = DateTimeHelper.toRFC3339(dateString);
c.setTime(d);
Assertions.assertEquals(1996, c.get(Calendar.YEAR));
// 0 based month
Assertions.assertEquals(11, c.get(Calendar.MONTH));
Assertions.assertEquals(19, c.get(Calendar.DATE));
Assertions.assertEquals(16, c.get(Calendar.HOUR_OF_DAY));
Assertions.assertEquals(39, c.get(Calendar.MINUTE));
Assertions.assertEquals(57, c.get(Calendar.SECOND));
Assertions.assertEquals(-TimeUnit.MILLISECONDS.convert(8, TimeUnit.HOURS),
c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET));
// Test unknown offset time
String unknownOffsetDateString = "1996-12-19T16:39:57-00:00";
c = Calendar.getInstance(TimeZone.getTimeZone(ZoneId.of("UTC")));
// set calendar to actual value for easy reading
d = DateTimeHelper.toRFC3339(unknownOffsetDateString);
c.setTime(d);
System.out.println(c.toInstant().toString());
Assertions.assertEquals(1996, c.get(Calendar.YEAR));
// 0 based month
Assertions.assertEquals(11, c.get(Calendar.MONTH));
Assertions.assertEquals(19, c.get(Calendar.DATE));
Assertions.assertEquals(16, c.get(Calendar.HOUR_OF_DAY));
Assertions.assertEquals(39, c.get(Calendar.MINUTE));
Assertions.assertEquals(57, c.get(Calendar.SECOND));
Assertions.assertEquals(0, c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET));
}
@Test
public void validRFC3339DateStringOut() {
// Set a time equal to "1996-12-19T16:39:57-08:00"
// Timezone needs to be set as otherwise it defaults to system local offset.
TimeZone tz = TimeZone.getTimeZone(ZoneId.of("GMT-08:00"));
// create a calendar instance to represent the given date
Calendar c = Calendar.getInstance(tz);
c.set(1996, 11, 19, 16, 39, 57);
// expect UTC time in return
String expected = "1996-12-20T00:39:57Z";
String actual = DateTimeHelper.toRFC3339(c.getTime());
Assertions.assertEquals(expected, actual);
}
@Test
public void invalidRFC3339DateStringIn() {
// test various permutations of the date string to ensure format enforcement
Assertions.assertNull(DateTimeHelper.toRFC3339("19991220"),
"Expected no returned date object for string: 19991220");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996/12/20"),
"Expected no returned date object for string: 1996/12/20");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20"),
"Expected no returned date object for string: 1996-12-20");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20 16:39:57-08:00"),
"Expected no returned date object for string: 1996-12-20 16:39:57-08:00");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20T16:39:57"),
"Expected no returned date object for string: 1996-12-20T16:39:57");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20T16:39:57-0800"),
"Expected no returned date object for string: 1996-12-20T16:39:57-0800");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment