Sequential files upload, basic search system

This commit is contained in:
jendib 2013-07-29 00:04:34 +02:00
parent 51434752f5
commit cd97382f60
12 changed files with 153 additions and 40 deletions

View File

@ -116,11 +116,17 @@ public class DocumentDao {
// Adds search criteria // Adds search criteria
List<String> criteriaList = new ArrayList<String>(); List<String> criteriaList = new ArrayList<String>();
if (criteria.getUserId() != null) { if (criteria.getUserId() != null) {
criteriaList.add("d.DOC_IDUSER_C = :userId"); criteriaList.add("d.DOC_IDUSER_C = :userId");
parameterMap.put("userId", criteria.getUserId()); 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()) { if (!criteriaList.isEmpty()) {
sb.append(" where "); sb.append(" where ");
sb.append(Joiner.on(" and ").join(criteriaList)); sb.append(Joiner.on(" and ").join(criteriaList));

View File

@ -12,6 +12,11 @@ public class DocumentCriteria {
*/ */
private String userId; private String userId;
/**
* Search query.
*/
private String search;
/** /**
* Getter of userId. * Getter of userId.
* *
@ -29,4 +34,22 @@ public class DocumentCriteria {
public void setUserId(String userId) { public void setUserId(String userId) {
this.userId = 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;
}
} }

View File

@ -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_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 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) ); 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) );

View File

@ -24,7 +24,7 @@
<org.slf4j.version>1.6.4</org.slf4j.version> <org.slf4j.version>1.6.4</org.slf4j.version>
<org.slf4j.jcl-over-slf4j.version>1.6.6</org.slf4j.jcl-over-slf4j.version> <org.slf4j.jcl-over-slf4j.version>1.6.6</org.slf4j.jcl-over-slf4j.version>
<junit.junit.version>4.7</junit.junit.version> <junit.junit.version>4.7</junit.junit.version>
<org.hsqldb.hsqldb.version>2.2.9</org.hsqldb.hsqldb.version> <org.hsqldb.hsqldb.version>2.3.0</org.hsqldb.hsqldb.version>
<com.sun.jersey.version>1.17</com.sun.jersey.version> <com.sun.jersey.version>1.17</com.sun.jersey.version>
<org.mindrot.jbcrypt>0.3m</org.mindrot.jbcrypt> <org.mindrot.jbcrypt>0.3m</org.mindrot.jbcrypt>
<org.subethamail.subethasmtp.version>3.1.6</org.subethamail.subethasmtp.version> <org.subethamail.subethasmtp.version>3.1.6</org.subethamail.subethasmtp.version>

View File

@ -20,6 +20,7 @@ import javax.ws.rs.core.Response;
import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject; 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.DocumentDao;
import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria; import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria;
import com.sismics.docs.core.dao.jpa.dto.DocumentDto; import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
@ -86,7 +87,8 @@ public class DocumentResource extends BaseResource {
@QueryParam("limit") Integer limit, @QueryParam("limit") Integer limit,
@QueryParam("offset") Integer offset, @QueryParam("offset") Integer offset,
@QueryParam("sort_column") Integer sortColumn, @QueryParam("sort_column") Integer sortColumn,
@QueryParam("asc") Boolean asc) throws JSONException { @QueryParam("asc") Boolean asc,
@QueryParam("search") String search) throws JSONException {
if (!authenticate()) { if (!authenticate()) {
throw new ForbiddenClientException(); throw new ForbiddenClientException();
} }
@ -99,6 +101,9 @@ public class DocumentResource extends BaseResource {
SortCriteria sortCriteria = new SortCriteria(sortColumn, asc); SortCriteria sortCriteria = new SortCriteria(sortColumn, asc);
DocumentCriteria documentCriteria = new DocumentCriteria(); DocumentCriteria documentCriteria = new DocumentCriteria();
documentCriteria.setUserId(principal.getId()); documentCriteria.setUserId(principal.getId());
if (!Strings.isNullOrEmpty(search)) {
documentCriteria.setSearch(search);
}
documentDao.findByCriteria(paginatedList, documentCriteria, sortCriteria); documentDao.findByCriteria(paginatedList, documentCriteria, sortCriteria);
for (DocumentDto documentDto : paginatedList.getResultList()) { for (DocumentDto documentDto : paginatedList.getResultList()) {

View File

@ -22,7 +22,8 @@ App.controller('Document', function($scope, $state, Restangular) {
offset: $scope.offset, offset: $scope.offset,
limit: $scope.limit, limit: $scope.limit,
sort_column: $scope.sortColumn, sort_column: $scope.sortColumn,
asc: $scope.asc asc: $scope.asc,
search: $scope.search
}) })
.then(function(data) { .then(function(data) {
$scope.documents = data; $scope.documents = data;
@ -47,6 +48,12 @@ App.controller('Document', function($scope, $state, Restangular) {
$scope.pageDocuments(); $scope.pageDocuments();
}); });
$scope.$watch('search', function(prev, next) {
if (next) {
$scope.loadDocuments();
}
})
/** /**
* Sort documents. * Sort documents.
*/ */

View File

@ -41,8 +41,26 @@ App.controller('DocumentEdit', function($scope, $q, $http, $state, $stateParams,
var promises = []; var promises = [];
$scope.fileProgress = 0; $scope.fileProgress = 0;
_.each($scope.newFiles, function(file) { // When all files upload are over, move on
var navigateNext = function() {
if ($scope.isEdit()) {
$scope.loadDocuments();
$state.transitionTo('document.view', { id: $stateParams.id });
} 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 // Build the payload
var file = $scope.newFiles[key];
var formData = new FormData(); var formData = new FormData();
formData.append('id', data.id); formData.append('id', data.id);
formData.append('file', file); formData.append('file', file);
@ -60,22 +78,21 @@ App.controller('DocumentEdit', function($scope, $q, $http, $state, $stateParams,
$scope.fileProgress += 100 / _.size($scope.newFiles); $scope.fileProgress += 100 / _.size($scope.newFiles);
}); });
// Store the promise for later return promiseFile;
promises.push(promiseFile); };
});
// When all files upload are over, move on // Upload files sequentially
var promiseAll = $q.all(promises); var key = 0;
if ($scope.isEdit()) { var then = function() {
promiseAll.then(function(data) { key++;
$scope.loadDocuments(); if ($scope.newFiles[key]) {
$state.transitionTo('document.view', { id: $stateParams.id }); sendFile(key).then(then);
});
} else { } else {
promiseAll.then(function(data) { $scope.fileIsUploading = false;
$scope.document = {}; navigateNext();
$scope.loadDocuments(); }
}); };
sendFile(key).then(then);
} }
}); });
}; };

View File

@ -3,17 +3,43 @@
/** /**
* Document view controller. * 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 // Load data from server
$scope.document = Restangular.one('document', $stateParams.id).get(); $scope.document = Restangular.one('document', $stateParams.id).get();
/**
* Load files from server.
*/
$scope.loadFiles = function() {
Restangular.one('file').getList('list', { id: $stateParams.id }).then(function(data) { Restangular.one('file').getList('list', { id: $stateParams.id }).then(function(data) {
$rootScope.files = data.files; $rootScope.files = data.files;
}); });
};
$scope.loadFiles();
/** /**
* Navigate to the selected file. * Navigate to the selected file.
*/ */
$scope.openFile = function(file) { $scope.openFile = function(file) {
$state.transitionTo('document.view.file', { id: $stateParams.id, fileId: file.id }) $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();
});
}
});
} }
}); });

View File

@ -23,6 +23,7 @@
</div> </div>
</form> </form>
<div class="row-fluid"> <div class="row-fluid" ng-show="fileIsUploading">
<div class="span12"><progress percent="fileProgress" class="progress-info active"></progress></div> <h4>Uploading files...</h4>
<div class="span6"><progress percent="fileProgress" class="progress-info active"></progress></div>
</div> </div>

View File

@ -4,6 +4,10 @@
<p class="text-center"> <p class="text-center">
<button class="btn btn-primary" type="button" ng-click="addDocument()">Add a document</button> <button class="btn btn-primary" type="button" ng-click="addDocument()">Add a document</button>
</p> </p>
<p class="input-prepend text-center input-block-level">
<span class="add-on"><span class="icon-search"></span></span>
<input class="span10" type="text" placeholder="Search" ng-model="search" >
</p>
<table class="table table-striped table-hover table-documents"> <table class="table table-striped table-hover table-documents">
<thead> <thead>
<tr> <tr>

View File

@ -18,7 +18,7 @@
</a> </a>
<div class="caption"> <div class="caption">
<p class="text-right"> <p class="text-right">
<button class="btn btn-danger" ng-click="deleteFile(file.id)"><span class="icon-trash icon-white"></span></button> <button class="btn btn-danger" ng-click="deleteFile(file)"><span class="icon-trash icon-white"></span></button>
</p> </p>
</div> </div>
</div> </div>

View File

@ -55,6 +55,29 @@ public class TestDocumentResource extends BaseJerseyTest {
Assert.assertTrue(documents.length() == 1); Assert.assertTrue(documents.length() == 1);
Assert.assertEquals(document1Id, documents.getJSONObject(0).getString("id")); 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 // Get a document
documentResource = resource().path("/document/" + document1Id); documentResource = resource().path("/document/" + document1Id);
documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); documentResource.addFilter(new CookieAuthenticationFilter(document1Token));