mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 14:07:55 +01:00
Closes #67: Relations between document (client-side)
This commit is contained in:
parent
0525754337
commit
ff91521a67
@ -28,7 +28,7 @@ public class RelationDao {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<RelationDto> getByDocumentId(String documentId) {
|
public List<RelationDto> getByDocumentId(String documentId) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
StringBuilder sb = new StringBuilder("select d.DOC_ID_C, d.DOC_TITLE_C ");
|
StringBuilder sb = new StringBuilder("select d.DOC_ID_C, d.DOC_TITLE_C, r.REL_IDDOCFROM_C ");
|
||||||
sb.append(" from T_RELATION r ");
|
sb.append(" from T_RELATION r ");
|
||||||
sb.append(" join T_DOCUMENT d on d.DOC_ID_C = r.REL_IDDOCFROM_C and r.REL_IDDOCFROM_C != :documentId or d.DOC_ID_C = r.REL_IDDOCTO_C and r.REL_IDDOCTO_C != :documentId ");
|
sb.append(" join T_DOCUMENT d on d.DOC_ID_C = r.REL_IDDOCFROM_C and r.REL_IDDOCFROM_C != :documentId or d.DOC_ID_C = r.REL_IDDOCTO_C and r.REL_IDDOCTO_C != :documentId ");
|
||||||
sb.append(" where (r.REL_IDDOCFROM_C = :documentId or r.REL_IDDOCTO_C = :documentId) ");
|
sb.append(" where (r.REL_IDDOCFROM_C = :documentId or r.REL_IDDOCTO_C = :documentId) ");
|
||||||
@ -47,6 +47,8 @@ public class RelationDao {
|
|||||||
RelationDto relationDto = new RelationDto();
|
RelationDto relationDto = new RelationDto();
|
||||||
relationDto.setId((String) o[i++]);
|
relationDto.setId((String) o[i++]);
|
||||||
relationDto.setTitle((String) o[i++]);
|
relationDto.setTitle((String) o[i++]);
|
||||||
|
String fromDocId = (String) o[i++];
|
||||||
|
relationDto.setSource(documentId.equals(fromDocId));
|
||||||
relationDtoList.add(relationDto);
|
relationDtoList.add(relationDto);
|
||||||
}
|
}
|
||||||
return relationDtoList;
|
return relationDtoList;
|
||||||
|
@ -16,6 +16,11 @@ public class RelationDto {
|
|||||||
*/
|
*/
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the document is the source of the relation.
|
||||||
|
*/
|
||||||
|
private boolean source;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -31,4 +36,12 @@ public class RelationDto {
|
|||||||
public void setTitle(String title) {
|
public void setTitle(String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(boolean source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,8 @@ public class DocumentResource extends BaseResource {
|
|||||||
for (RelationDto relationDto : relationDtoList) {
|
for (RelationDto relationDto : relationDtoList) {
|
||||||
relationList.add(Json.createObjectBuilder()
|
relationList.add(Json.createObjectBuilder()
|
||||||
.add("id", relationDto.getId())
|
.add("id", relationDto.getId())
|
||||||
.add("title", relationDto.getTitle()));
|
.add("title", relationDto.getTitle())
|
||||||
|
.add("source", relationDto.isSource()));
|
||||||
}
|
}
|
||||||
document.add("relations", relationList);
|
document.add("relations", relationList);
|
||||||
|
|
||||||
@ -669,7 +670,8 @@ public class DocumentResource extends BaseResource {
|
|||||||
RelationDao relationDao = new RelationDao();
|
RelationDao relationDao = new RelationDao();
|
||||||
Set<String> documentIdSet = new HashSet<>();
|
Set<String> documentIdSet = new HashSet<>();
|
||||||
for (String targetDocId : relationList) {
|
for (String targetDocId : relationList) {
|
||||||
Document document = documentDao.getDocument(targetDocId, PermType.READ, principal.getId());
|
// ACL are not checked, because the editing user is not forced to view the target document
|
||||||
|
Document document = documentDao.getById(targetDocId);
|
||||||
if (document != null && !documentId.equals(targetDocId)) {
|
if (document != null && !documentId.equals(targetDocId)) {
|
||||||
documentIdSet.add(targetDocId);
|
documentIdSet.add(targetDocId);
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ angular.module('docs').controller('DocumentEdit', function($rootScope, $scope, $
|
|||||||
$scope.resetForm = function() {
|
$scope.resetForm = function() {
|
||||||
$scope.document = {
|
$scope.document = {
|
||||||
tags: [],
|
tags: [],
|
||||||
|
relations: [],
|
||||||
language: 'fra'
|
language: 'fra'
|
||||||
};
|
};
|
||||||
$scope.newFiles = [];
|
$scope.newFiles = [];
|
||||||
@ -72,6 +73,9 @@ angular.module('docs').controller('DocumentEdit', function($rootScope, $scope, $
|
|||||||
// Extract ids from tags
|
// Extract ids from tags
|
||||||
document.tags = _.pluck(document.tags, 'id');
|
document.tags = _.pluck(document.tags, 'id');
|
||||||
|
|
||||||
|
// Extract ids from relations (only when our document is the source)
|
||||||
|
document.relations = _.pluck(_.where(document.relations, { source: true }), 'id');
|
||||||
|
|
||||||
if ($scope.isEdit()) {
|
if ($scope.isEdit()) {
|
||||||
promise = Restangular.one('document', $stateParams.id).post('', document);
|
promise = Restangular.one('document', $stateParams.id).post('', document);
|
||||||
} else {
|
} else {
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relation selection directive.
|
||||||
|
*/
|
||||||
|
angular.module('docs').directive('selectRelation', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'partial/docs/directive.selectrelation.html',
|
||||||
|
replace: true,
|
||||||
|
scope: {
|
||||||
|
relations: '=',
|
||||||
|
ref: '@',
|
||||||
|
ngDisabled: '='
|
||||||
|
},
|
||||||
|
controller: function($scope, $q, Restangular) {
|
||||||
|
/**
|
||||||
|
* Add a relation.
|
||||||
|
*/
|
||||||
|
$scope.addRelation = function($item) {
|
||||||
|
// Does the new relation is already in the model
|
||||||
|
var duplicate = _.find($scope.relations, function(relation) {
|
||||||
|
if ($item.id == relation.id) {
|
||||||
|
return relation;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the new relation
|
||||||
|
if (!duplicate) {
|
||||||
|
$scope.relations.push({
|
||||||
|
id: $item.id,
|
||||||
|
title: $item.title,
|
||||||
|
source: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$scope.input = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a relation.
|
||||||
|
*/
|
||||||
|
$scope.deleteRelation = function(deleteRelation) {
|
||||||
|
$scope.relations = _.reject($scope.relations, function(relation) {
|
||||||
|
return relation.id == deleteRelation.id;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise for typeahead title.
|
||||||
|
*/
|
||||||
|
$scope.getDocumentTypeahead = function($viewValue) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
Restangular.one('document')
|
||||||
|
.getList('list', {
|
||||||
|
limit: 5,
|
||||||
|
sort_column: 1,
|
||||||
|
asc: true,
|
||||||
|
search: $viewValue
|
||||||
|
}).then(function(data) {
|
||||||
|
deferred.resolve(data.documents);
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
link: function(scope, element, attr, ctrl) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -70,6 +70,7 @@
|
|||||||
<script src="app/docs/filter/Filesize.js" type="text/javascript"></script>
|
<script src="app/docs/filter/Filesize.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/File.js" type="text/javascript"></script>
|
<script src="app/docs/directive/File.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/SelectTag.js" type="text/javascript"></script>
|
<script src="app/docs/directive/SelectTag.js" type="text/javascript"></script>
|
||||||
|
<script src="app/docs/directive/SelectRelation.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/AuditLog.js" type="text/javascript"></script>
|
<script src="app/docs/directive/AuditLog.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/InlineEdit.js" type="text/javascript"></script>
|
<script src="app/docs/directive/InlineEdit.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/directive/ImgError.js" type="text/javascript"></script>
|
<script src="app/docs/directive/ImgError.js" type="text/javascript"></script>
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
<div>
|
||||||
|
<ul class="list-inline">
|
||||||
|
<li ng-repeat="relation in relations | filter: { source: true }">
|
||||||
|
<span class="label label-info">{{ relation.title }}
|
||||||
|
<span class="glyphicon glyphicon-remove" ng-click="deleteRelation(relation)" ng-show="!ngDisabled"></span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<input class="form-control" type="text" id="{{ ref }}" placeholder="Type a document title" ng-model="input" ng-disabled="ngDisabled"
|
||||||
|
autocomplete="off"
|
||||||
|
typeahead="document.title for document in getDocumentTypeahead($viewValue) | filter: $viewValue"
|
||||||
|
typeahead-wait-ms="200" typeahead-on-select="addRelation($item)" />
|
||||||
|
</div>
|
@ -118,6 +118,12 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputRelations">Relations</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select-relation relations="document.relations" ref="inputRelations" ng-disabled="fileIsUploading"></select-relation>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -19,13 +19,23 @@
|
|||||||
<dt>Contributors</dt>
|
<dt>Contributors</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<span ng-repeat="contributor in document.contributors">
|
<span ng-repeat="contributor in document.contributors">
|
||||||
<span class="btn btn-default btn-xs">
|
<span class="btn btn-link btn-xs">
|
||||||
<a href="#/user/{{ contributor.username }}">
|
<a href="#/user/{{ contributor.username }}">
|
||||||
{{ contributor.username }}
|
{{ contributor.username }}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>Relations</dt>
|
||||||
|
<dd>
|
||||||
|
<span ng-repeat="relation in document.relations">
|
||||||
|
<span class="btn btn-link btn-xs">
|
||||||
|
<a href="#/document/view/{{ relation.id }}">
|
||||||
|
{{ relation.title }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<div ng-file-drop drag-over-class="bg-success" ng-multiple="true" allow-dir="false" ng-model="dropFiles"
|
<div ng-file-drop drag-over-class="bg-success" ng-multiple="true" allow-dir="false" ng-model="dropFiles"
|
||||||
|
@ -238,6 +238,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
JsonArray relations = json.getJsonArray("relations");
|
JsonArray relations = json.getJsonArray("relations");
|
||||||
Assert.assertEquals(1, relations.size());
|
Assert.assertEquals(1, relations.size());
|
||||||
Assert.assertEquals(document2Id, relations.getJsonObject(0).getString("id"));
|
Assert.assertEquals(document2Id, relations.getJsonObject(0).getString("id"));
|
||||||
|
Assert.assertFalse(relations.getJsonObject(0).getBoolean("source"));
|
||||||
Assert.assertEquals("My super title document 2", relations.getJsonObject(0).getString("title"));
|
Assert.assertEquals("My super title document 2", relations.getJsonObject(0).getString("title"));
|
||||||
|
|
||||||
// Get document 2
|
// Get document 2
|
||||||
@ -248,6 +249,7 @@ public class TestDocumentResource extends BaseJerseyTest {
|
|||||||
relations = json.getJsonArray("relations");
|
relations = json.getJsonArray("relations");
|
||||||
Assert.assertEquals(1, relations.size());
|
Assert.assertEquals(1, relations.size());
|
||||||
Assert.assertEquals(document1Id, relations.getJsonObject(0).getString("id"));
|
Assert.assertEquals(document1Id, relations.getJsonObject(0).getString("id"));
|
||||||
|
Assert.assertTrue(relations.getJsonObject(0).getBoolean("source"));
|
||||||
Assert.assertEquals("My super title document 1", relations.getJsonObject(0).getString("title"));
|
Assert.assertEquals("My super title document 1", relations.getJsonObject(0).getString("title"));
|
||||||
|
|
||||||
// Export a document in PDF format
|
// Export a document in PDF format
|
||||||
|
Loading…
Reference in New Issue
Block a user