mirror of
https://github.com/sismics/docs.git
synced 2024-11-25 15:17:57 +01:00
Sequential files upload, basic search system
This commit is contained in:
parent
51434752f5
commit
cd97382f60
@ -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));
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) );
|
||||||
|
@ -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>
|
||||||
|
@ -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()) {
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -41,41 +41,58 @@ App.controller('DocumentEdit', function($scope, $q, $http, $state, $stateParams,
|
|||||||
var promises = [];
|
var promises = [];
|
||||||
$scope.fileProgress = 0;
|
$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
|
// When all files upload are over, move on
|
||||||
var promiseAll = $q.all(promises);
|
var navigateNext = function() {
|
||||||
if ($scope.isEdit()) {
|
if ($scope.isEdit()) {
|
||||||
promiseAll.then(function(data) {
|
|
||||||
$scope.loadDocuments();
|
$scope.loadDocuments();
|
||||||
$state.transitionTo('document.view', { id: $stateParams.id });
|
$state.transitionTo('document.view', { id: $stateParams.id });
|
||||||
});
|
} else {
|
||||||
} else {
|
|
||||||
promiseAll.then(function(data) {
|
|
||||||
$scope.document = {};
|
$scope.document = {};
|
||||||
$scope.loadDocuments();
|
$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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
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.
|
* 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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -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>
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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));
|
||||||
|
Loading…
Reference in New Issue
Block a user