From 5426be9fa019a5c04a3f211c3c045e3a006a8456 Mon Sep 17 00:00:00 2001 From: Benjamin Gamard Date: Mon, 12 Mar 2018 14:15:00 +0100 Subject: [PATCH] Closes #193: last updated date (db + search + ui) --- .../docs/core/dao/jpa/DocumentDao.java | 18 +++++-- .../dao/jpa/criteria/DocumentCriteria.java | 26 ++++++++++ .../docs/core/dao/jpa/dto/DocumentDto.java | 13 +++++ .../sismics/docs/core/model/jpa/Document.java | 19 +++++-- .../src/main/resources/config.properties | 2 +- .../resources/db/update/dbupdate-018-0.sql | 4 ++ docs-web/src/dev/resources/config.properties | 2 +- .../docs/rest/resource/DocumentResource.java | 49 +++++++++++++++---- .../app/docs/controller/document/Document.js | 6 +++ docs-web/src/main/webapp/src/locale/en.json | 7 ++- .../webapp/src/partial/docs/document.html | 34 ++++++++++++- .../src/partial/docs/document.view.html | 2 +- docs-web/src/prod/resources/config.properties | 2 +- .../src/stress/resources/config.properties | 2 +- .../docs/rest/TestAuditLogResource.java | 41 +++++++++++++--- .../docs/rest/TestDocumentResource.java | 6 +++ 16 files changed, 202 insertions(+), 31 deletions(-) create mode 100644 docs-core/src/main/resources/db/update/dbupdate-018-0.sql diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java index c15c9624..f853d531 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java @@ -38,6 +38,7 @@ public class DocumentDao { public String create(Document document, String userId) { // Create the UUID document.setId(UUID.randomUUID().toString()); + document.setUpdateDate(new Date()); // Create the document EntityManager em = ThreadLocalContext.get().getEntityManager(); @@ -90,7 +91,7 @@ public class DocumentDao { } EntityManager em = ThreadLocalContext.get().getEntityManager(); - StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C, d.DOC_TITLE_C, d.DOC_DESCRIPTION_C, d.DOC_SUBJECT_C, d.DOC_IDENTIFIER_C, d.DOC_PUBLISHER_C, d.DOC_FORMAT_C, d.DOC_SOURCE_C, d.DOC_TYPE_C, d.DOC_COVERAGE_C, d.DOC_RIGHTS_C, d.DOC_CREATEDATE_D, d.DOC_LANGUAGE_C, "); + StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C, d.DOC_TITLE_C, d.DOC_DESCRIPTION_C, d.DOC_SUBJECT_C, d.DOC_IDENTIFIER_C, d.DOC_PUBLISHER_C, d.DOC_FORMAT_C, d.DOC_SOURCE_C, d.DOC_TYPE_C, d.DOC_COVERAGE_C, d.DOC_RIGHTS_C, d.DOC_CREATEDATE_D, d.DOC_UPDATEDATE_D, d.DOC_LANGUAGE_C, "); sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null), "); sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C), "); sb.append(" u.USE_USERNAME_C "); @@ -122,6 +123,7 @@ public class DocumentDao { documentDto.setCoverage((String) o[i++]); documentDto.setRights((String) o[i++]); documentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime()); + documentDto.setUpdateTimestamp(((Timestamp) o[i++]).getTime()); documentDto.setLanguage((String) o[i++]); documentDto.setShared(((Number) o[i++]).intValue() > 0); documentDto.setFileCount(((Number) o[i++]).intValue()); @@ -204,7 +206,7 @@ public class DocumentDao { StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C c0, d.DOC_TITLE_C c1, d.DOC_DESCRIPTION_C c2, d.DOC_CREATEDATE_D c3, d.DOC_LANGUAGE_C c4, "); sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) c5, "); sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C) c6, "); - sb.append(" rs2.RTP_ID_C c7, rs2.RTP_NAME_C "); + sb.append(" rs2.RTP_ID_C c7, rs2.RTP_NAME_C, d.DOC_UPDATEDATE_D c8 "); sb.append(" from T_DOCUMENT d "); sb.append(" left join (select rs.*, rs3.idDocument\n" + "from T_ROUTE_STEP rs \n" + @@ -238,6 +240,14 @@ public class DocumentDao { criteriaList.add("d.DOC_CREATEDATE_D <= :createDateMax"); parameterMap.put("createDateMax", criteria.getCreateDateMax()); } + if (criteria.getUpdateDateMin() != null) { + criteriaList.add("d.DOC_UPDATEDATE_D >= :updateDateMin"); + parameterMap.put("updateDateMin", criteria.getUpdateDateMin()); + } + if (criteria.getUpdateDateMax() != null) { + criteriaList.add("d.DOC_UPDATEDATE_D <= :updateDateMax"); + parameterMap.put("updateDateMax", criteria.getUpdateDateMax()); + } if (criteria.getTagIdList() != null && !criteria.getTagIdList().isEmpty()) { int index = 0; List tagCriteriaList = Lists.newArrayList(); @@ -288,7 +298,8 @@ public class DocumentDao { documentDto.setShared(((Number) o[i++]).intValue() > 0); documentDto.setFileCount(((Number) o[i++]).intValue()); documentDto.setActiveRoute(o[i++] != null); - documentDto.setCurrentStepName((String) o[i]); + documentDto.setCurrentStepName((String) o[i++]); + documentDto.setUpdateTimestamp(((Timestamp) o[i]).getTime()); documentDtoList.add(documentDto); } @@ -323,6 +334,7 @@ public class DocumentDao { documentDb.setRights(document.getRights()); documentDb.setCreateDate(document.getCreateDate()); documentDb.setLanguage(document.getLanguage()); + documentDb.setUpdateDate(new Date()); // Create audit log AuditLogUtil.create(documentDb, AuditLogType.UPDATE, userId); diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java index b39cf87f..73de591b 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java @@ -35,6 +35,16 @@ public class DocumentCriteria { */ private Date createDateMax; + /** + * Minimum update date. + */ + private Date updateDateMin; + + /** + * Maximum update date. + */ + private Date updateDateMax; + /** * Tag IDs. */ @@ -136,6 +146,22 @@ public class DocumentCriteria { return activeRoute; } + public Date getUpdateDateMin() { + return updateDateMin; + } + + public void setUpdateDateMin(Date updateDateMin) { + this.updateDateMin = updateDateMin; + } + + public Date getUpdateDateMax() { + return updateDateMax; + } + + public void setUpdateDateMax(Date updateDateMax) { + this.updateDateMax = updateDateMax; + } + public DocumentCriteria setActiveRoute(Boolean activeRoute) { this.activeRoute = activeRoute; return this; diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/DocumentDto.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/DocumentDto.java index ef7b4075..39e2dce4 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/DocumentDto.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/DocumentDto.java @@ -71,6 +71,11 @@ public class DocumentDto { */ private Long createTimestamp; + /** + * Update date. + */ + private Long updateTimestamp; + /** * Shared status. */ @@ -236,6 +241,14 @@ public class DocumentDto { return currentStepName; } + public Long getUpdateTimestamp() { + return updateTimestamp; + } + + public void setUpdateTimestamp(Long updateTimestamp) { + this.updateTimestamp = updateTimestamp; + } + public DocumentDto setCurrentStepName(String currentStepName) { this.currentStepName = currentStepName; return this; diff --git a/docs-core/src/main/java/com/sismics/docs/core/model/jpa/Document.java b/docs-core/src/main/java/com/sismics/docs/core/model/jpa/Document.java index 7b9da6f2..626e631c 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/model/jpa/Document.java +++ b/docs-core/src/main/java/com/sismics/docs/core/model/jpa/Document.java @@ -1,13 +1,12 @@ package com.sismics.docs.core.model.jpa; -import java.util.Date; +import com.google.common.base.MoreObjects; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; - -import com.google.common.base.MoreObjects; +import java.util.Date; /** * Document entity. @@ -102,6 +101,12 @@ public class Document implements Loggable { @Column(name = "DOC_CREATEDATE_D", nullable = false) private Date createDate; + /** + * Creation date. + */ + @Column(name = "DOC_UPDATEDATE_D", nullable = false) + private Date updateDate; + /** * Deletion date. */ @@ -229,6 +234,14 @@ public class Document implements Loggable { this.deleteDate = deleteDate; } + public Date getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(Date updateDate) { + this.updateDate = updateDate; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/docs-core/src/main/resources/config.properties b/docs-core/src/main/resources/config.properties index 3be02720..4e046a45 100644 --- a/docs-core/src/main/resources/config.properties +++ b/docs-core/src/main/resources/config.properties @@ -1 +1 @@ -db.version=17 \ No newline at end of file +db.version=18 \ No newline at end of file diff --git a/docs-core/src/main/resources/db/update/dbupdate-018-0.sql b/docs-core/src/main/resources/db/update/dbupdate-018-0.sql new file mode 100644 index 00000000..17b4dd7b --- /dev/null +++ b/docs-core/src/main/resources/db/update/dbupdate-018-0.sql @@ -0,0 +1,4 @@ +alter table T_DOCUMENT add column DOC_UPDATEDATE_D datetime; +update T_DOCUMENT set DOC_UPDATEDATE_D = DOC_CREATEDATE_D; +alter table T_DOCUMENT alter column DOC_UPDATEDATE_D datetime not null; +update T_CONFIG set CFG_VALUE_C = '18' where CFG_ID_C = 'DB_VERSION'; diff --git a/docs-web/src/dev/resources/config.properties b/docs-web/src/dev/resources/config.properties index 1c41d115..28a3b40a 100644 --- a/docs-web/src/dev/resources/config.properties +++ b/docs-web/src/dev/resources/config.properties @@ -1,3 +1,3 @@ api.current_version=${project.version} api.min_version=1.0 -db.version=17 \ No newline at end of file +db.version=18 \ No newline at end of file diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java index 74593c05..91785ef2 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java @@ -76,6 +76,7 @@ public class DocumentResource extends BaseResource { * @apiSuccess {String} title Title * @apiSuccess {String} description Description * @apiSuccess {Number} create_date Create date (timestamp) + * @apiSuccess {Number} update_date Update date (timestamp) * @apiSuccess {String} language Language * @apiSuccess {Boolean} shared True if the document is shared * @apiSuccess {Number} file_count Number of files in this document @@ -142,6 +143,7 @@ public class DocumentResource extends BaseResource { .add("title", documentDto.getTitle()) .add("description", JsonUtil.nullable(documentDto.getDescription())) .add("create_date", documentDto.getCreateTimestamp()) + .add("update_date", documentDto.getUpdateTimestamp()) .add("language", documentDto.getLanguage()) .add("shared", documentDto.getShared()) .add("file_count", documentDto.getFileCount()); @@ -328,6 +330,7 @@ public class DocumentResource extends BaseResource { * @apiSuccess {String} documents.title Title * @apiSuccess {String} documents.description Description * @apiSuccess {Number} documents.create_date Create date (timestamp) + * @apiSuccess {Number} documents.update_date Update date (timestamp) * @apiSuccess {String} documents.language Language * @apiSuccess {Boolean} documents.shared True if the document is shared * @apiSuccess {Boolean} documents.active_route True if a route is active on this document @@ -394,6 +397,7 @@ public class DocumentResource extends BaseResource { .add("title", documentDto.getTitle()) .add("description", JsonUtil.nullable(documentDto.getDescription())) .add("create_date", documentDto.getCreateTimestamp()) + .add("update_date", documentDto.getUpdateTimestamp()) .add("language", documentDto.getLanguage()) .add("shared", documentDto.getShared()) .add("active_route", documentDto.isActiveRoute()) @@ -464,32 +468,57 @@ public class DocumentResource extends BaseResource { break; case "after": case "before": + case "uafter": + case "ubefore": // New date span criteria try { + boolean isUpdated = params[0].startsWith("u"); DateTime date = formatter.parseDateTime(params[1]); - if (params[0].equals("before")) documentCriteria.setCreateDateMax(date.toDate()); - else documentCriteria.setCreateDateMin(date.toDate()); + if (params[0].endsWith("before")) { + if (isUpdated) documentCriteria.setUpdateDateMax(date.toDate()); + else documentCriteria.setCreateDateMax(date.toDate()); + } else { + if (isUpdated) documentCriteria.setUpdateDateMin(date.toDate()); + else documentCriteria.setCreateDateMin(date.toDate()); + } } catch (IllegalArgumentException e) { // Invalid date, returns no documents - if (params[0].equals("before")) documentCriteria.setCreateDateMax(new Date(0)); - else documentCriteria.setCreateDateMin(new Date(Long.MAX_VALUE / 2)); + documentCriteria.setCreateDateMin(new Date(0)); + documentCriteria.setCreateDateMax(new Date(0)); } break; + case "uat": case "at": // New specific date criteria try { + boolean isUpdated = params[0].startsWith("u"); if (params[1].length() == 10) { DateTime date = dayFormatter.parseDateTime(params[1]); - documentCriteria.setCreateDateMin(date.toDate()); - documentCriteria.setCreateDateMax(date.plusDays(1).minusSeconds(1).toDate()); + if (isUpdated) { + documentCriteria.setUpdateDateMin(date.toDate()); + documentCriteria.setUpdateDateMax(date.plusDays(1).minusSeconds(1).toDate()); + } else { + documentCriteria.setCreateDateMin(date.toDate()); + documentCriteria.setCreateDateMax(date.plusDays(1).minusSeconds(1).toDate()); + } } else if (params[1].length() == 7) { DateTime date = monthFormatter.parseDateTime(params[1]); - documentCriteria.setCreateDateMin(date.toDate()); - documentCriteria.setCreateDateMax(date.plusMonths(1).minusSeconds(1).toDate()); + if (isUpdated) { + documentCriteria.setUpdateDateMin(date.toDate()); + documentCriteria.setUpdateDateMax(date.plusMonths(1).minusSeconds(1).toDate()); + } else { + documentCriteria.setCreateDateMin(date.toDate()); + documentCriteria.setCreateDateMax(date.plusMonths(1).minusSeconds(1).toDate()); + } } else if (params[1].length() == 4) { DateTime date = yearFormatter.parseDateTime(params[1]); - documentCriteria.setCreateDateMin(date.toDate()); - documentCriteria.setCreateDateMax(date.plusYears(1).minusSeconds(1).toDate()); + if (isUpdated) { + documentCriteria.setUpdateDateMin(date.toDate()); + documentCriteria.setUpdateDateMax(date.plusYears(1).minusSeconds(1).toDate()); + } else { + documentCriteria.setCreateDateMin(date.toDate()); + documentCriteria.setCreateDateMax(date.plusYears(1).minusSeconds(1).toDate()); + } } } catch (IllegalArgumentException e) { // Invalid date, returns no documents diff --git a/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js b/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js index c81fb75e..e5e45180 100644 --- a/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js +++ b/docs-web/src/main/webapp/src/app/docs/controller/document/Document.js @@ -181,6 +181,12 @@ angular.module('docs').controller('Document', function ($scope, $rootScope, $tim if (!_.isUndefined($scope.advsearch.before_date)) { search += 'before:' + $filter('date')($scope.advsearch.before_date, 'yyyy-MM-dd') + ' '; } + if (!_.isUndefined($scope.advsearch.after_update_date)) { + search += 'uafter:' + $filter('date')($scope.advsearch.after_update_date, 'yyyy-MM-dd') + ' '; + } + if (!_.isUndefined($scope.advsearch.before_update_date)) { + search += 'ubefore:' + $filter('date')($scope.advsearch.before_update_date, 'yyyy-MM-dd') + ' '; + } if (!_.isEmpty($scope.advsearch.tags)) { search += _.reduce($scope.advsearch.tags, function(s, t) { return s + 'tag:' + t.name + ' '; diff --git a/docs-web/src/main/webapp/src/locale/en.json b/docs-web/src/main/webapp/src/locale/en.json index e6ba5ae4..54e16e84 100644 --- a/docs-web/src/main/webapp/src/locale/en.json +++ b/docs-web/src/main/webapp/src/locale/en.json @@ -45,8 +45,10 @@ "search_fulltext": "Fulltext search", "search_creator": "Creator", "search_language": "Language", - "search_before_date": "Before this date", - "search_after_date": "After this date", + "search_before_date": "Created before this date", + "search_after_date": "Created after this date", + "search_before_update_date": "Updated before this date", + "search_after_update_date": "Update after this date", "search_tags": "Tags", "search_shared": "Only shared documents", "search_workflow": "Workflow assigned to me", @@ -82,6 +84,7 @@ "upgrade_quota": "To upgrade your quota, ask your administrator", "quota": "{{ current | number: 0 }}MB ({{ percent | number: 1 }}%) used on {{ total | number: 0 }}MB", "count": "{{ count }} document{{ count > 1 ? 's' : '' }} found", + "last_updated": "Last updated {{ date | timeAgo: dateFormat }}", "view": { "delete_comment_title": "Delete comment", "delete_comment_message": "Do you really want to delete this comment?", diff --git a/docs-web/src/main/webapp/src/partial/docs/document.html b/docs-web/src/main/webapp/src/partial/docs/document.html index 1a04e204..2ad55053 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.html @@ -93,6 +93,36 @@ +
+ +
+ +
+
+ +
+ +
+ +
+
+
@@ -194,7 +224,9 @@ -
{{ document.create_date | timeAgo: dateFormat }}
+
+ {{ document.create_date | timeAgo: dateFormat }} +
diff --git a/docs-web/src/main/webapp/src/partial/docs/document.view.html b/docs-web/src/main/webapp/src/partial/docs/document.view.html index 9a27b326..d4d3905e 100644 --- a/docs-web/src/main/webapp/src/partial/docs/document.view.html +++ b/docs-web/src/main/webapp/src/partial/docs/document.view.html @@ -45,7 +45,7 @@