From cd97382f60fc2e916fdadb7f28f97f36cfcd4dc0 Mon Sep 17 00:00:00 2001 From: jendib Date: Mon, 29 Jul 2013 00:04:34 +0200 Subject: [PATCH] Sequential files upload, basic search system --- .../docs/core/dao/jpa/DocumentDao.java | 6 ++ .../dao/jpa/criteria/DocumentCriteria.java | 23 ++++++ .../resources/db/update/dbupdate-000-0.sql | 1 + docs-parent/pom.xml | 2 +- .../docs/rest/resource/DocumentResource.java | 7 +- .../src/main/webapp/js/controller/Document.js | 9 ++- .../main/webapp/js/controller/DocumentEdit.js | 77 +++++++++++-------- .../main/webapp/js/controller/DocumentView.js | 34 +++++++- .../main/webapp/partial/document.edit.html | 5 +- .../src/main/webapp/partial/document.html | 4 + .../main/webapp/partial/document.view.html | 2 +- .../docs/rest/TestDocumentResource.java | 23 ++++++ 12 files changed, 153 insertions(+), 40 deletions(-) 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 388ed09a..e71d9395 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 @@ -116,11 +116,17 @@ public class DocumentDao { // Adds search criteria List criteriaList = new ArrayList(); + if (criteria.getUserId() != null) { criteriaList.add("d.DOC_IDUSER_C = :userId"); parameterMap.put("userId", criteria.getUserId()); } + if (criteria.getSearch() != null) { + criteriaList.add("(d.DOC_TITLE_C LIKE :search OR d.DOC_DESCRIPTION_C LIKE :search)"); + parameterMap.put("search", "%" + criteria.getSearch() + "%"); + } + if (!criteriaList.isEmpty()) { sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList)); 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 f9e87891..195b8809 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 @@ -12,6 +12,11 @@ public class DocumentCriteria { */ private String userId; + /** + * Search query. + */ + private String search; + /** * Getter of userId. * @@ -29,4 +34,22 @@ public class DocumentCriteria { public void setUserId(String userId) { this.userId = userId; } + + /** + * Getter of search. + * + * @return the search + */ + public String getSearch() { + return search; + } + + /** + * Setter of search. + * + * @param search search + */ + public void setSearch(String search) { + this.search = search; + } } diff --git a/docs-core/src/main/resources/db/update/dbupdate-000-0.sql b/docs-core/src/main/resources/db/update/dbupdate-000-0.sql index f261311d..c865937d 100644 --- a/docs-core/src/main/resources/db/update/dbupdate-000-0.sql +++ b/docs-core/src/main/resources/db/update/dbupdate-000-0.sql @@ -1,3 +1,4 @@ +SET IGNORECASE TRUE; create memory table T_AUTHENTICATION_TOKEN ( AUT_ID_C varchar(36) not null, AUT_IDUSER_C varchar(36) not null, AUT_LONGLASTED_B bit not null, AUT_CREATIONDATE_D datetime not null, AUT_LASTCONNECTIONDATE_D datetime, primary key (AUT_ID_C) ); create memory table T_BASE_FUNCTION ( BAF_ID_C varchar(20) not null, primary key (BAF_ID_C) ); create cached table T_FILE ( FIL_ID_C varchar(36) not null, FIL_IDDOC_C varchar(36) not null, FIL_MIMETYPE_C varchar(100) not null, FIL_CREATEDATE_D datetime, FIL_DELETEDATE_D datetime, primary key (FIL_ID_C) ); diff --git a/docs-parent/pom.xml b/docs-parent/pom.xml index 92ac753f..5f0b2502 100644 --- a/docs-parent/pom.xml +++ b/docs-parent/pom.xml @@ -24,7 +24,7 @@ 1.6.4 1.6.6 4.7 - 2.2.9 + 2.3.0 1.17 0.3m 3.1.6 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 40fc896c..e645a6cc 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 @@ -20,6 +20,7 @@ import javax.ws.rs.core.Response; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; +import com.google.common.base.Strings; import com.sismics.docs.core.dao.jpa.DocumentDao; import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria; import com.sismics.docs.core.dao.jpa.dto.DocumentDto; @@ -86,7 +87,8 @@ public class DocumentResource extends BaseResource { @QueryParam("limit") Integer limit, @QueryParam("offset") Integer offset, @QueryParam("sort_column") Integer sortColumn, - @QueryParam("asc") Boolean asc) throws JSONException { + @QueryParam("asc") Boolean asc, + @QueryParam("search") String search) throws JSONException { if (!authenticate()) { throw new ForbiddenClientException(); } @@ -99,6 +101,9 @@ public class DocumentResource extends BaseResource { SortCriteria sortCriteria = new SortCriteria(sortColumn, asc); DocumentCriteria documentCriteria = new DocumentCriteria(); documentCriteria.setUserId(principal.getId()); + if (!Strings.isNullOrEmpty(search)) { + documentCriteria.setSearch(search); + } documentDao.findByCriteria(paginatedList, documentCriteria, sortCriteria); for (DocumentDto documentDto : paginatedList.getResultList()) { diff --git a/docs-web/src/main/webapp/js/controller/Document.js b/docs-web/src/main/webapp/js/controller/Document.js index 5e3cd3ac..4b98f5bd 100644 --- a/docs-web/src/main/webapp/js/controller/Document.js +++ b/docs-web/src/main/webapp/js/controller/Document.js @@ -22,7 +22,8 @@ App.controller('Document', function($scope, $state, Restangular) { offset: $scope.offset, limit: $scope.limit, sort_column: $scope.sortColumn, - asc: $scope.asc + asc: $scope.asc, + search: $scope.search }) .then(function(data) { $scope.documents = data; @@ -47,6 +48,12 @@ App.controller('Document', function($scope, $state, Restangular) { $scope.pageDocuments(); }); + $scope.$watch('search', function(prev, next) { + if (next) { + $scope.loadDocuments(); + } + }) + /** * Sort documents. */ diff --git a/docs-web/src/main/webapp/js/controller/DocumentEdit.js b/docs-web/src/main/webapp/js/controller/DocumentEdit.js index 67df4045..b2a0ebad 100644 --- a/docs-web/src/main/webapp/js/controller/DocumentEdit.js +++ b/docs-web/src/main/webapp/js/controller/DocumentEdit.js @@ -41,41 +41,58 @@ App.controller('DocumentEdit', function($scope, $q, $http, $state, $stateParams, var promises = []; $scope.fileProgress = 0; - _.each($scope.newFiles, function(file) { - // Build the payload - var formData = new FormData(); - formData.append('id', data.id); - formData.append('file', file); - - // Send the file - var promiseFile = $http.put('api/file', - formData, { - headers: { 'Content-Type': false }, - transformRequest: function(data) { return data; } - }); - - // TODO Handle progression when $q.notify will be released - - promiseFile.then(function() { - $scope.fileProgress += 100 / _.size($scope.newFiles); - }); - - // Store the promise for later - promises.push(promiseFile); - }); - // When all files upload are over, move on - var promiseAll = $q.all(promises); - if ($scope.isEdit()) { - promiseAll.then(function(data) { + var navigateNext = function() { + if ($scope.isEdit()) { $scope.loadDocuments(); $state.transitionTo('document.view', { id: $stateParams.id }); - }); - } else { - promiseAll.then(function(data) { + } else { $scope.document = {}; $scope.loadDocuments(); - }); + } + } + + if (_.size($scope.newFiles) == 0) { + navigateNext(); + } else { + $scope.fileIsUploading = true; + + // Send a file from the input file array and return a promise + var sendFile = function(key) { + // Build the payload + var file = $scope.newFiles[key]; + var formData = new FormData(); + formData.append('id', data.id); + formData.append('file', file); + + // Send the file + var promiseFile = $http.put('api/file', + formData, { + headers: { 'Content-Type': false }, + transformRequest: function(data) { return data; } + }); + + // TODO Handle progression when $q.notify will be released + + promiseFile.then(function() { + $scope.fileProgress += 100 / _.size($scope.newFiles); + }); + + return promiseFile; + }; + + // Upload files sequentially + var key = 0; + var then = function() { + key++; + if ($scope.newFiles[key]) { + sendFile(key).then(then); + } else { + $scope.fileIsUploading = false; + navigateNext(); + } + }; + sendFile(key).then(then); } }); }; diff --git a/docs-web/src/main/webapp/js/controller/DocumentView.js b/docs-web/src/main/webapp/js/controller/DocumentView.js index 1a6a77d3..fd7233eb 100644 --- a/docs-web/src/main/webapp/js/controller/DocumentView.js +++ b/docs-web/src/main/webapp/js/controller/DocumentView.js @@ -3,17 +3,43 @@ /** * Document view controller. */ -App.controller('DocumentView', function($rootScope, $scope, $state, $stateParams, Restangular) { +App.controller('DocumentView', function($rootScope, $scope, $state, $stateParams, $dialog, Restangular) { // Load data from server $scope.document = Restangular.one('document', $stateParams.id).get(); - Restangular.one('file').getList('list', { id: $stateParams.id }).then(function(data) { - $rootScope.files = data.files; - }); + + /** + * Load files from server. + */ + $scope.loadFiles = function() { + Restangular.one('file').getList('list', { id: $stateParams.id }).then(function(data) { + $rootScope.files = data.files; + }); + }; + $scope.loadFiles(); /** * Navigate to the selected file. */ $scope.openFile = function(file) { $state.transitionTo('document.view.file', { id: $stateParams.id, fileId: file.id }) + }; + + /** + * Delete a file. + */ + $scope.deleteFile = function(file) { + var title = 'Delete file'; + var msg = 'Do you really want to delete this file?'; + var btns = [{result:'cancel', label: 'Cancel'}, {result:'ok', label: 'OK', cssClass: 'btn-primary'}]; + + $dialog.messageBox(title, msg, btns) + .open() + .then(function(result) { + if (result == 'ok') { + Restangular.one('file', file.id).remove().then(function() { + $scope.loadFiles(); + }); + } + }); } }); \ No newline at end of file diff --git a/docs-web/src/main/webapp/partial/document.edit.html b/docs-web/src/main/webapp/partial/document.edit.html index 04684a35..3dbe5656 100644 --- a/docs-web/src/main/webapp/partial/document.edit.html +++ b/docs-web/src/main/webapp/partial/document.edit.html @@ -23,6 +23,7 @@ -
-
+
+

Uploading files...

+
\ No newline at end of file diff --git a/docs-web/src/main/webapp/partial/document.html b/docs-web/src/main/webapp/partial/document.html index 122a0f77..32fbbee8 100644 --- a/docs-web/src/main/webapp/partial/document.html +++ b/docs-web/src/main/webapp/partial/document.html @@ -4,6 +4,10 @@

+

+ + +

diff --git a/docs-web/src/main/webapp/partial/document.view.html b/docs-web/src/main/webapp/partial/document.view.html index 4e0ae103..911f194a 100644 --- a/docs-web/src/main/webapp/partial/document.view.html +++ b/docs-web/src/main/webapp/partial/document.view.html @@ -18,7 +18,7 @@

- +

diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java index 4dc9be4c..6bb34940 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java @@ -55,6 +55,29 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertTrue(documents.length() == 1); Assert.assertEquals(document1Id, documents.getJSONObject(0).getString("id")); + // Search documents + documentResource = resource().path("/document/list"); + documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); + getParams = new MultivaluedMapImpl(); + getParams.putSingle("search", "Sup"); + response = documentResource.queryParams(getParams).get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + documents = json.getJSONArray("documents"); + Assert.assertTrue(documents.length() == 1); + Assert.assertEquals(document1Id, documents.getJSONObject(0).getString("id")); + + // Search documents (nothing) + documentResource = resource().path("/document/list"); + documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); + getParams = new MultivaluedMapImpl(); + getParams.putSingle("search", "random"); + response = documentResource.queryParams(getParams).get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + documents = json.getJSONArray("documents"); + Assert.assertTrue(documents.length() == 0); + // Get a document documentResource = resource().path("/document/" + document1Id); documentResource.addFilter(new CookieAuthenticationFilter(document1Token));