mirror of
https://github.com/sismics/docs.git
synced 2024-11-22 14:07:55 +01:00
Closes #83: Edit ACLs for tags in UI + batch for old DB
This commit is contained in:
parent
b851fd0ecc
commit
a55c55bbdb
@ -176,8 +176,9 @@ public class TagDao {
|
|||||||
Map<String, Object> parameterMap = new HashMap<>();
|
Map<String, Object> parameterMap = new HashMap<>();
|
||||||
List<String> criteriaList = new ArrayList<>();
|
List<String> criteriaList = new ArrayList<>();
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("select distinct t.TAG_ID_C as c0, t.TAG_NAME_C as c1, t.TAG_COLOR_C as c2, t.TAG_IDPARENT_C as c3 ");
|
StringBuilder sb = new StringBuilder("select distinct t.TAG_ID_C as c0, t.TAG_NAME_C as c1, t.TAG_COLOR_C as c2, t.TAG_IDPARENT_C as c3, u.USE_USERNAME_C as c4 ");
|
||||||
sb.append(" from T_TAG t ");
|
sb.append(" from T_TAG t ");
|
||||||
|
sb.append(" join T_USER u on t.TAG_IDUSER_C = u.USE_ID_C ");
|
||||||
|
|
||||||
// Add search criterias
|
// Add search criterias
|
||||||
if (criteria.getId() != null) {
|
if (criteria.getId() != null) {
|
||||||
@ -223,7 +224,8 @@ public class TagDao {
|
|||||||
.setId((String) o[i++])
|
.setId((String) o[i++])
|
||||||
.setName((String) o[i++])
|
.setName((String) o[i++])
|
||||||
.setColor((String) o[i++])
|
.setColor((String) o[i++])
|
||||||
.setParentId((String) o[i]);
|
.setParentId((String) o[i++])
|
||||||
|
.setCreator((String) o[i]);
|
||||||
tagDtoList.add(tagDto);
|
tagDtoList.add(tagDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,11 @@ public class TagDto {
|
|||||||
*/
|
*/
|
||||||
private String parentId;
|
private String parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creator.
|
||||||
|
*/
|
||||||
|
private String creator;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -61,4 +66,13 @@ public class TagDto {
|
|||||||
this.parentId = parentId;
|
this.parentId = parentId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCreator() {
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagDto setCreator(String creator) {
|
||||||
|
this.creator = creator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,29 +21,20 @@ public class AclUtil {
|
|||||||
*
|
*
|
||||||
* @param json JSON
|
* @param json JSON
|
||||||
* @param sourceId Source ID
|
* @param sourceId Source ID
|
||||||
* @param principal Principal
|
* @param targetIdList List of target ID
|
||||||
*/
|
*/
|
||||||
public static void addAcls(JsonObjectBuilder json, String sourceId, IPrincipal principal) {
|
public static void addAcls(JsonObjectBuilder json, String sourceId, List<String> targetIdList) {
|
||||||
AclDao aclDao = new AclDao();
|
AclDao aclDao = new AclDao();
|
||||||
List<AclDto> aclDtoList = aclDao.getBySourceId(sourceId);
|
List<AclDto> aclDtoList = aclDao.getBySourceId(sourceId);
|
||||||
JsonArrayBuilder aclList = Json.createArrayBuilder();
|
JsonArrayBuilder aclList = Json.createArrayBuilder();
|
||||||
boolean writable = false;
|
|
||||||
for (AclDto aclDto : aclDtoList) {
|
for (AclDto aclDto : aclDtoList) {
|
||||||
aclList.add(Json.createObjectBuilder()
|
aclList.add(Json.createObjectBuilder()
|
||||||
.add("perm", aclDto.getPerm().name())
|
.add("perm", aclDto.getPerm().name())
|
||||||
.add("id", aclDto.getTargetId())
|
.add("id", aclDto.getTargetId())
|
||||||
.add("name", JsonUtil.nullable(aclDto.getTargetName()))
|
.add("name", JsonUtil.nullable(aclDto.getTargetName()))
|
||||||
.add("type", aclDto.getTargetType()));
|
.add("type", aclDto.getTargetType()));
|
||||||
|
|
||||||
if (!principal.isAnonymous()
|
|
||||||
&& (aclDto.getTargetId().equals(principal.getId())
|
|
||||||
|| principal.getGroupIdSet().contains(aclDto.getTargetId()))
|
|
||||||
&& aclDto.getPerm() == PermType.WRITE) {
|
|
||||||
// The source is writable for the current user
|
|
||||||
writable = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
json.add("acls", aclList)
|
json.add("acls", aclList)
|
||||||
.add("writable", writable);
|
.add("writable", aclDao.checkPermission(sourceId, PermType.WRITE, targetIdList));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,13 @@ import javax.ws.rs.Path;
|
|||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.TagDao;
|
||||||
|
import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
|
||||||
|
import com.sismics.docs.core.dao.jpa.dto.AclDto;
|
||||||
|
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
||||||
|
import com.sismics.docs.core.model.jpa.Acl;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.log4j.Appender;
|
import org.apache.log4j.Appender;
|
||||||
import org.apache.log4j.Level;
|
import org.apache.log4j.Level;
|
||||||
@ -284,12 +291,12 @@ public class AppResource extends BaseResource {
|
|||||||
Map<String, User> userMap = new HashMap<>();
|
Map<String, User> userMap = new HashMap<>();
|
||||||
for (File file : fileList) {
|
for (File file : fileList) {
|
||||||
java.nio.file.Path storedFile = DirectoryUtil.getStorageDirectory().resolve(file.getId());
|
java.nio.file.Path storedFile = DirectoryUtil.getStorageDirectory().resolve(file.getId());
|
||||||
User user = null;
|
User user;
|
||||||
if (userMap.containsKey(file.getUserId())) {
|
if (userMap.containsKey(file.getUserId())) {
|
||||||
user = userMap.get(file.getUserId());
|
user = userMap.get(file.getUserId());
|
||||||
} else {
|
} else {
|
||||||
user = userDao.getById(file.getUserId());
|
user = userDao.getById(file.getUserId());
|
||||||
user.setStorageCurrent(0l);
|
user.setStorageCurrent(0L);
|
||||||
userMap.put(user.getId(), user);
|
userMap.put(user.getId(), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,4 +319,49 @@ public class AppResource extends BaseResource {
|
|||||||
.add("status", "ok");
|
.add("status", "ok");
|
||||||
return Response.ok().entity(response.build()).build();
|
return Response.ok().entity(response.build()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add base ACLs to tags.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("batch/tag_acls")
|
||||||
|
public Response batchTagAcls() {
|
||||||
|
if (!authenticate()) {
|
||||||
|
throw new ForbiddenClientException();
|
||||||
|
}
|
||||||
|
checkBaseFunction(BaseFunction.ADMIN);
|
||||||
|
|
||||||
|
// Get all tags
|
||||||
|
TagDao tagDao = new TagDao();
|
||||||
|
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria(), null);
|
||||||
|
|
||||||
|
// Add READ and WRITE ACLs
|
||||||
|
for (TagDto tagDto : tagDtoList) {
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
List<AclDto> aclDtoList = aclDao.getBySourceId(tagDto.getId());
|
||||||
|
|
||||||
|
if (aclDtoList.size() == 0) {
|
||||||
|
// Create read ACL
|
||||||
|
Acl acl = new Acl();
|
||||||
|
acl.setPerm(PermType.READ);
|
||||||
|
acl.setSourceId(tagDto.getId());
|
||||||
|
acl.setTargetId(principal.getId());
|
||||||
|
aclDao.create(acl, principal.getId());
|
||||||
|
|
||||||
|
// Create write ACL
|
||||||
|
acl = new Acl();
|
||||||
|
acl.setPerm(PermType.WRITE);
|
||||||
|
acl.setSourceId(tagDto.getId());
|
||||||
|
acl.setTargetId(principal.getId());
|
||||||
|
aclDao.create(acl, principal.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always return OK
|
||||||
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
||||||
|
.add("status", "ok");
|
||||||
|
return Response.ok().entity(response.build()).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,6 @@ public class DocumentResource extends BaseResource {
|
|||||||
authenticate();
|
authenticate();
|
||||||
|
|
||||||
DocumentDao documentDao = new DocumentDao();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
AclDao aclDao = new AclDao();
|
|
||||||
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(shareId));
|
||||||
if (documentDto == null) {
|
if (documentDto == null) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
@ -90,7 +89,11 @@ public class DocumentResource extends BaseResource {
|
|||||||
} else {
|
} else {
|
||||||
// Add tags added by the current user on this document
|
// Add tags added by the current user on this document
|
||||||
TagDao tagDao = new TagDao();
|
TagDao tagDao = new TagDao();
|
||||||
List<TagDto> tagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)).setDocumentId(documentId), new SortCriteria(1, true));
|
List<TagDto> tagDtoList = tagDao.findByCriteria(
|
||||||
|
new TagCriteria()
|
||||||
|
.setTargetIdList(getTargetIdList(shareId))
|
||||||
|
.setDocumentId(documentId),
|
||||||
|
new SortCriteria(1, true));
|
||||||
JsonArrayBuilder tags = Json.createArrayBuilder();
|
JsonArrayBuilder tags = Json.createArrayBuilder();
|
||||||
for (TagDto tagDto : tagDtoList) {
|
for (TagDto tagDto : tagDtoList) {
|
||||||
tags.add(Json.createObjectBuilder()
|
tags.add(Json.createObjectBuilder()
|
||||||
@ -113,7 +116,7 @@ public class DocumentResource extends BaseResource {
|
|||||||
document.add("creator", documentDto.getCreator());
|
document.add("creator", documentDto.getCreator());
|
||||||
|
|
||||||
// Add ACL
|
// Add ACL
|
||||||
AclUtil.addAcls(document, documentId, principal);
|
AclUtil.addAcls(document, documentId, getTargetIdList(shareId));
|
||||||
|
|
||||||
// Add contributors
|
// Add contributors
|
||||||
ContributorDao contributorDao = new ContributorDao();
|
ContributorDao contributorDao = new ContributorDao();
|
||||||
|
@ -5,7 +5,6 @@ import com.sismics.docs.core.constant.PermType;
|
|||||||
import com.sismics.docs.core.dao.jpa.AclDao;
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
import com.sismics.docs.core.dao.jpa.TagDao;
|
import com.sismics.docs.core.dao.jpa.TagDao;
|
||||||
import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
|
import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.AclDto;
|
|
||||||
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
||||||
import com.sismics.docs.core.model.jpa.Acl;
|
import com.sismics.docs.core.model.jpa.Acl;
|
||||||
import com.sismics.docs.core.model.jpa.Tag;
|
import com.sismics.docs.core.model.jpa.Tag;
|
||||||
@ -13,14 +12,12 @@ import com.sismics.docs.core.util.jpa.SortCriteria;
|
|||||||
import com.sismics.rest.exception.ClientException;
|
import com.sismics.rest.exception.ClientException;
|
||||||
import com.sismics.rest.exception.ForbiddenClientException;
|
import com.sismics.rest.exception.ForbiddenClientException;
|
||||||
import com.sismics.rest.util.AclUtil;
|
import com.sismics.rest.util.AclUtil;
|
||||||
import com.sismics.rest.util.JsonUtil;
|
|
||||||
import com.sismics.rest.util.ValidationUtil;
|
import com.sismics.rest.util.ValidationUtil;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
import javax.json.Json;
|
import javax.json.Json;
|
||||||
import javax.json.JsonArrayBuilder;
|
import javax.json.JsonArrayBuilder;
|
||||||
import javax.json.JsonObjectBuilder;
|
import javax.json.JsonObjectBuilder;
|
||||||
import javax.json.JsonValue;
|
|
||||||
import javax.ws.rs.*;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
@ -64,8 +61,6 @@ public class TagResource extends BaseResource {
|
|||||||
.add("color", tagDto.getColor());
|
.add("color", tagDto.getColor());
|
||||||
if (tagIdSet.contains(tagDto.getParentId())) {
|
if (tagIdSet.contains(tagDto.getParentId())) {
|
||||||
item.add("parent", tagDto.getParentId());
|
item.add("parent", tagDto.getParentId());
|
||||||
} else {
|
|
||||||
item.add("parent", JsonValue.NULL);
|
|
||||||
}
|
}
|
||||||
items.add(item);
|
items.add(item);
|
||||||
}
|
}
|
||||||
@ -98,11 +93,12 @@ public class TagResource extends BaseResource {
|
|||||||
TagDto tagDto = tagDtoList.get(0);
|
TagDto tagDto = tagDtoList.get(0);
|
||||||
JsonObjectBuilder tag = Json.createObjectBuilder()
|
JsonObjectBuilder tag = Json.createObjectBuilder()
|
||||||
.add("id", tagDto.getId())
|
.add("id", tagDto.getId())
|
||||||
|
.add("creator", tagDto.getCreator())
|
||||||
.add("name", tagDto.getName())
|
.add("name", tagDto.getName())
|
||||||
.add("color", tagDto.getColor());
|
.add("color", tagDto.getColor());
|
||||||
|
|
||||||
// Add ACL
|
// Add ACL
|
||||||
AclUtil.addAcls(tag, id, principal);
|
AclUtil.addAcls(tag, id, getTargetIdList(null));
|
||||||
|
|
||||||
return Response.ok().entity(tag.build()).build();
|
return Response.ok().entity(tag.build()).build();
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ angular.module('docs',
|
|||||||
* Configuring modules.
|
* Configuring modules.
|
||||||
*/
|
*/
|
||||||
.config(function($stateProvider, $httpProvider, RestangularProvider) {
|
.config(function($stateProvider, $httpProvider, RestangularProvider) {
|
||||||
|
|
||||||
// Configuring UI Router
|
// Configuring UI Router
|
||||||
$stateProvider
|
$stateProvider
|
||||||
.state('main', {
|
.state('main', {
|
||||||
@ -26,6 +27,7 @@ angular.module('docs',
|
|||||||
})
|
})
|
||||||
.state('tag', {
|
.state('tag', {
|
||||||
url: '/tag',
|
url: '/tag',
|
||||||
|
abstract: true,
|
||||||
views: {
|
views: {
|
||||||
'page': {
|
'page': {
|
||||||
templateUrl: 'partial/docs/tag.html',
|
templateUrl: 'partial/docs/tag.html',
|
||||||
@ -33,6 +35,23 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('tag.default', {
|
||||||
|
url: '',
|
||||||
|
views: {
|
||||||
|
'tag': {
|
||||||
|
templateUrl: 'partial/docs/tag.default.html'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.state('tag.edit', {
|
||||||
|
url: '/:id',
|
||||||
|
views: {
|
||||||
|
'tag': {
|
||||||
|
templateUrl: 'partial/docs/tag.edit.html',
|
||||||
|
controller: 'TagEdit'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('settings', {
|
.state('settings', {
|
||||||
url: '/settings',
|
url: '/settings',
|
||||||
abstract: true,
|
abstract: true,
|
||||||
@ -264,6 +283,7 @@ angular.module('docs',
|
|||||||
})
|
})
|
||||||
.state('user', {
|
.state('user', {
|
||||||
url: '/user',
|
url: '/user',
|
||||||
|
abstract: true,
|
||||||
views: {
|
views: {
|
||||||
'page': {
|
'page': {
|
||||||
templateUrl: 'partial/docs/usergroup.html',
|
templateUrl: 'partial/docs/usergroup.html',
|
||||||
@ -271,6 +291,14 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('user.default', {
|
||||||
|
url: '',
|
||||||
|
views: {
|
||||||
|
'sub': {
|
||||||
|
templateUrl: 'partial/docs/usergroup.default.html'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('user.profile', {
|
.state('user.profile', {
|
||||||
url: '/:username',
|
url: '/:username',
|
||||||
views: {
|
views: {
|
||||||
@ -282,6 +310,7 @@ angular.module('docs',
|
|||||||
})
|
})
|
||||||
.state('group', {
|
.state('group', {
|
||||||
url: '/group',
|
url: '/group',
|
||||||
|
abstract: true,
|
||||||
views: {
|
views: {
|
||||||
'page': {
|
'page': {
|
||||||
templateUrl: 'partial/docs/usergroup.html',
|
templateUrl: 'partial/docs/usergroup.html',
|
||||||
@ -289,6 +318,14 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.state('group.default', {
|
||||||
|
url: '',
|
||||||
|
views: {
|
||||||
|
'sub': {
|
||||||
|
templateUrl: 'partial/docs/usergroup.default.html'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.state('group.profile', {
|
.state('group.profile', {
|
||||||
url: '/:name',
|
url: '/:name',
|
||||||
views: {
|
views: {
|
||||||
@ -298,7 +335,6 @@ angular.module('docs',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configuring Restangular
|
// Configuring Restangular
|
||||||
RestangularProvider.setBaseUrl('../api');
|
RestangularProvider.setBaseUrl('../api');
|
||||||
|
|
||||||
|
@ -3,95 +3,5 @@
|
|||||||
/**
|
/**
|
||||||
* Document view permissions controller.
|
* Document view permissions controller.
|
||||||
*/
|
*/
|
||||||
angular.module('docs').controller('DocumentViewPermissions', function ($scope, $stateParams, Restangular, $q) {
|
angular.module('docs').controller('DocumentViewPermissions', function() {
|
||||||
// Watch for ACLs change and group them for easy displaying
|
|
||||||
$scope.$watch('document.acls', function(acls) {
|
|
||||||
$scope.acls = _.groupBy(acls, function(acl) {
|
|
||||||
return acl.id;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize add ACL
|
|
||||||
$scope.acl = { perm: 'READ' };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete an ACL.
|
|
||||||
*/
|
|
||||||
$scope.deleteAcl = function(acl) {
|
|
||||||
Restangular.one('acl/' + $stateParams.id + '/' + acl.perm + '/' + acl.id, null).remove().then(function () {
|
|
||||||
$scope.document.acls = _.reject($scope.document.acls, function(s) {
|
|
||||||
return angular.equals(acl, s);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an ACL.
|
|
||||||
*/
|
|
||||||
$scope.addAcl = function() {
|
|
||||||
// Compute ACLs to add
|
|
||||||
$scope.acl.source = $stateParams.id;
|
|
||||||
var acls = [];
|
|
||||||
if ($scope.acl.perm == 'READWRITE') {
|
|
||||||
acls = [{
|
|
||||||
source: $stateParams.id,
|
|
||||||
target: $scope.acl.target.name,
|
|
||||||
perm: 'READ',
|
|
||||||
type: $scope.acl.target.type
|
|
||||||
}, {
|
|
||||||
source: $stateParams.id,
|
|
||||||
target: $scope.acl.target.name,
|
|
||||||
perm: 'WRITE',
|
|
||||||
type: $scope.acl.target.type
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
acls = [{
|
|
||||||
source: $stateParams.id,
|
|
||||||
target: $scope.acl.target.name,
|
|
||||||
perm: $scope.acl.perm,
|
|
||||||
type: $scope.acl.target.type
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add ACLs
|
|
||||||
_.each(acls, function(acl) {
|
|
||||||
Restangular.one('acl').put(acl).then(function(acl) {
|
|
||||||
if (_.isUndefined(acl.id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$scope.document.acls.push(acl);
|
|
||||||
$scope.document.acls = angular.copy($scope.document.acls);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset form
|
|
||||||
$scope.acl = { perm: 'READ' };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-complete on ACL target.
|
|
||||||
*/
|
|
||||||
$scope.getTargetAclTypeahead = function($viewValue) {
|
|
||||||
var deferred = $q.defer();
|
|
||||||
Restangular.one('acl/target/search')
|
|
||||||
.get({
|
|
||||||
search: $viewValue
|
|
||||||
}).then(function(data) {
|
|
||||||
var output = [];
|
|
||||||
|
|
||||||
// Add the type to use later
|
|
||||||
output.push.apply(output, _.map(data.users, function(user) {
|
|
||||||
user.type = 'USER';
|
|
||||||
return user;
|
|
||||||
}));
|
|
||||||
output.push.apply(output, _.map(data.groups, function(group) {
|
|
||||||
group.type = 'GROUP';
|
|
||||||
return group;
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Send the data to the typeahead directive
|
|
||||||
deferred.resolve(output, true);
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
};
|
|
||||||
});
|
});
|
@ -3,37 +3,14 @@
|
|||||||
/**
|
/**
|
||||||
* Tag controller.
|
* Tag controller.
|
||||||
*/
|
*/
|
||||||
angular.module('docs').controller('Tag', function($scope, $dialog, Tag, Restangular) {
|
angular.module('docs').controller('Tag', function($scope, $dialog, Restangular) {
|
||||||
$scope.tag = { name: '', color: '#3a87ad' };
|
$scope.tag = { name: '', color: '#3a87ad' };
|
||||||
|
|
||||||
// Retrieve tags
|
// Retrieve tags
|
||||||
Tag.tags().then(function(data) {
|
Restangular.one('tag/list').get().then(function(data) {
|
||||||
$scope.tags = data.tags;
|
$scope.tags = data.tags;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieve tag stats
|
|
||||||
Restangular.one('tag/stats').get().then(function(data) {
|
|
||||||
$scope.stats = data.stats;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns total number of document from tag stats.
|
|
||||||
*/
|
|
||||||
$scope.getStatCount = function() {
|
|
||||||
return _.reduce($scope.stats, function(memo, stat) {
|
|
||||||
return memo + stat.count
|
|
||||||
}, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate a tag name for duplicate.
|
|
||||||
*/
|
|
||||||
$scope.validateDuplicate = function(name) {
|
|
||||||
return !_.find($scope.tags, function(tag) {
|
|
||||||
return tag.name == name;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a tag.
|
* Add a tag.
|
||||||
*/
|
*/
|
||||||
@ -71,15 +48,6 @@ angular.module('docs').controller('Tag', function($scope, $dialog, Tag, Restangu
|
|||||||
*/
|
*/
|
||||||
$scope.updateTag = function(tag) {
|
$scope.updateTag = function(tag) {
|
||||||
// Update the server
|
// Update the server
|
||||||
return Restangular.one('tag', tag.id).post('', tag).then(function () {
|
return Restangular.one('tag', tag.id).post('', tag);
|
||||||
// Update the stat object
|
|
||||||
var stat = _.find($scope.stats, function (t) {
|
|
||||||
return tag.id == t.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (stat) {
|
|
||||||
_.extend(stat, tag);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
});
|
});
|
@ -0,0 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag edit controller.
|
||||||
|
*/
|
||||||
|
angular.module('docs').controller('TagEdit', function($scope, $stateParams, Restangular) {
|
||||||
|
Restangular.one('tag', $stateParams.id).get().then(function(data) {
|
||||||
|
$scope.tag = data;
|
||||||
|
})
|
||||||
|
});
|
112
docs-web/src/main/webapp/src/app/docs/directive/AclEdit.js
Normal file
112
docs-web/src/main/webapp/src/app/docs/directive/AclEdit.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL edit directive.
|
||||||
|
*/
|
||||||
|
angular.module('docs').directive('aclEdit', function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'partial/docs/directive.acledit.html',
|
||||||
|
replace: true,
|
||||||
|
scope: {
|
||||||
|
source: '=',
|
||||||
|
acls: '=',
|
||||||
|
writable: '=',
|
||||||
|
creator: '='
|
||||||
|
},
|
||||||
|
controller: function($scope, Restangular, $q) {
|
||||||
|
// Watch for ACLs change and group them for easy displaying
|
||||||
|
$scope.$watch('acls', function(acls) {
|
||||||
|
$scope.groupedAcls = _.groupBy(acls, function(acl) {
|
||||||
|
return acl.id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize add ACL
|
||||||
|
$scope.acl = { perm: 'READ' };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an ACL.
|
||||||
|
*/
|
||||||
|
$scope.deleteAcl = function(acl) {
|
||||||
|
Restangular.one('acl/' + $scope.source + '/' + acl.perm + '/' + acl.id, null).remove().then(function () {
|
||||||
|
$scope.acls = _.reject($scope.acls, function(s) {
|
||||||
|
return angular.equals(acl, s);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an ACL.
|
||||||
|
*/
|
||||||
|
$scope.addAcl = function() {
|
||||||
|
// Compute ACLs to add
|
||||||
|
$scope.acl.source = $scope.source;
|
||||||
|
var acls = [];
|
||||||
|
if ($scope.acl.perm == 'READWRITE') {
|
||||||
|
acls = [{
|
||||||
|
source: $scope.source,
|
||||||
|
target: $scope.acl.target.name,
|
||||||
|
perm: 'READ',
|
||||||
|
type: $scope.acl.target.type
|
||||||
|
}, {
|
||||||
|
source: $scope.source,
|
||||||
|
target: $scope.acl.target.name,
|
||||||
|
perm: 'WRITE',
|
||||||
|
type: $scope.acl.target.type
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
acls = [{
|
||||||
|
source: $scope.source,
|
||||||
|
target: $scope.acl.target.name,
|
||||||
|
perm: $scope.acl.perm,
|
||||||
|
type: $scope.acl.target.type
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add ACLs
|
||||||
|
_.each(acls, function(acl) {
|
||||||
|
Restangular.one('acl').put(acl).then(function(acl) {
|
||||||
|
if (_.isUndefined(acl.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$scope.acls.push(acl);
|
||||||
|
$scope.acls = angular.copy($scope.acls);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset form
|
||||||
|
$scope.acl = { perm: 'READ' };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-complete on ACL target.
|
||||||
|
*/
|
||||||
|
$scope.getTargetAclTypeahead = function($viewValue) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
Restangular.one('acl/target/search')
|
||||||
|
.get({
|
||||||
|
search: $viewValue
|
||||||
|
}).then(function(data) {
|
||||||
|
var output = [];
|
||||||
|
|
||||||
|
// Add the type to use later
|
||||||
|
output.push.apply(output, _.map(data.users, function(user) {
|
||||||
|
user.type = 'USER';
|
||||||
|
return user;
|
||||||
|
}));
|
||||||
|
output.push.apply(output, _.map(data.groups, function(group) {
|
||||||
|
group.type = 'GROUP';
|
||||||
|
return group;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Send the data to the typeahead directive
|
||||||
|
deferred.resolve(output, true);
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
link: function(scope, element, attr, ctrl) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -13,9 +13,9 @@ angular.module('docs').directive('selectTag', function() {
|
|||||||
ref: '@',
|
ref: '@',
|
||||||
ngDisabled: '='
|
ngDisabled: '='
|
||||||
},
|
},
|
||||||
controller: function($scope, Tag) {
|
controller: function($scope, Restangular) {
|
||||||
// Retrieve tags
|
// Retrieve tags
|
||||||
Tag.tags().then(function(data) {
|
Restangular.one('tag/list').get().then(function(data) {
|
||||||
$scope.allTags = data.tags;
|
$scope.allTags = data.tags;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ angular.module('docs').directive('selectTag', function() {
|
|||||||
if ($event) {
|
if ($event) {
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a tag.
|
* Remove a tag.
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag service.
|
|
||||||
*/
|
|
||||||
angular.module('docs').factory('Tag', function(Restangular) {
|
|
||||||
var tags = null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Returns tags.
|
|
||||||
* @param force If true, force reloading data
|
|
||||||
*/
|
|
||||||
tags: function(force) {
|
|
||||||
return Restangular.one('tag/list').get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -55,6 +55,7 @@
|
|||||||
<script src="app/docs/controller/document/FileModalView.js" type="text/javascript"></script>
|
<script src="app/docs/controller/document/FileModalView.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/Login.js" type="text/javascript"></script>
|
<script src="app/docs/controller/Login.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/tag/Tag.js" type="text/javascript"></script>
|
<script src="app/docs/controller/tag/Tag.js" type="text/javascript"></script>
|
||||||
|
<script src="app/docs/controller/tag/TagEdit.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/Navigation.js" type="text/javascript"></script>
|
<script src="app/docs/controller/Navigation.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/Settings.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/Settings.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/settings/SettingsDefault.js" type="text/javascript"></script>
|
<script src="app/docs/controller/settings/SettingsDefault.js" type="text/javascript"></script>
|
||||||
@ -73,7 +74,6 @@
|
|||||||
<script src="app/docs/controller/usergroup/UserProfile.js" type="text/javascript"></script>
|
<script src="app/docs/controller/usergroup/UserProfile.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/controller/usergroup/GroupProfile.js" type="text/javascript"></script>
|
<script src="app/docs/controller/usergroup/GroupProfile.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/service/User.js" type="text/javascript"></script>
|
<script src="app/docs/service/User.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/service/Tag.js" type="text/javascript"></script>
|
|
||||||
<script src="app/docs/filter/Newline.js" type="text/javascript"></script>
|
<script src="app/docs/filter/Newline.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/filter/Shorten.js" type="text/javascript"></script>
|
<script src="app/docs/filter/Shorten.js" type="text/javascript"></script>
|
||||||
<script src="app/docs/filter/Filesize.js" type="text/javascript"></script>
|
<script src="app/docs/filter/Filesize.js" type="text/javascript"></script>
|
||||||
@ -84,6 +84,7 @@
|
|||||||
<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>
|
||||||
<script src="app/docs/directive/Acl.js" type="text/javascript"></script>
|
<script src="app/docs/directive/Acl.js" type="text/javascript"></script>
|
||||||
|
<script src="app/docs/directive/AclEdit.js" type="text/javascript"></script>
|
||||||
<!-- endref -->
|
<!-- endref -->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
<div>
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th style="width: 40%">For</th>
|
||||||
|
<th style="width: 40%">Permission</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr ng-repeat="(id, acl) in groupedAcls">
|
||||||
|
<td><acl data="acl[0]"></acl></td>
|
||||||
|
<td>
|
||||||
|
<span class="label label-default" style="margin-right: 6px;" ng-repeat="a in acl | orderBy: 'perm'">
|
||||||
|
{{ a.perm }}
|
||||||
|
<span ng-show="(creator != a.name && a.type == 'USER' || a.type != 'USER') && writable"
|
||||||
|
class="glyphicon glyphicon-remove pointer"
|
||||||
|
ng-click="deleteAcl(a)"></span>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div ng-show="writable">
|
||||||
|
<h4>Add a permission</h4>
|
||||||
|
|
||||||
|
<form name="aclForm" class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="inputTarget">For</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<input required ng-maxlength="50" class="form-control" type="text" id="inputTarget"
|
||||||
|
placeholder="Search a user or group" name="target" ng-model="acl.target" autocomplete="off"
|
||||||
|
typeahead="target as target.name for target in getTargetAclTypeahead($viewValue) | filter: $viewValue"
|
||||||
|
typeahead-template-url="partial/docs/directive.typeahead.acl.html"
|
||||||
|
typeahead-wait-ms="200" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<span class="btn btn-primary" ng-if="acl.target.type" ng-click="acl.target = null">
|
||||||
|
<acl data="acl.target"></acl>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class=" col-sm-2 control-label" for="inputPermission">Permission</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<select class="form-control" ng-model="acl.perm" id="inputPermission">
|
||||||
|
<option value="READ">Can read</option>
|
||||||
|
<option value="READWRITE">Can edit</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-primary" ng-disabled="!acl.target.type" ng-click="addAcl()">
|
||||||
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,59 +1,4 @@
|
|||||||
<table class="table">
|
<acl-edit source="document.id"
|
||||||
<tr>
|
acls="document.acls"
|
||||||
<th style="width: 40%">For</th>
|
writable="document.writable"
|
||||||
<th style="width: 40%">Permission</th>
|
creator="document.creator"></acl-edit>
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr ng-repeat="(id, acl) in acls">
|
|
||||||
<td><acl data="acl[0]"></acl></td>
|
|
||||||
<td>
|
|
||||||
<span class="label label-default" style="margin-right: 6px;" ng-repeat="a in acl | orderBy: 'perm'">
|
|
||||||
{{ a.perm }}
|
|
||||||
<span ng-show="(document.creator != a.name && a.type == 'USER' || a.type != 'USER') && document.writable"
|
|
||||||
class="glyphicon glyphicon-remove pointer"
|
|
||||||
ng-click="deleteAcl(a)"></span>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div ng-show="document.writable">
|
|
||||||
<h4>Add a permission</h4>
|
|
||||||
|
|
||||||
<form name="aclForm" class="form-horizontal">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-2 control-label" for="inputTarget">For</label>
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<input required ng-maxlength="50" class="form-control" type="text" id="inputTarget"
|
|
||||||
placeholder="Search a user or group" name="target" ng-model="acl.target" autocomplete="off"
|
|
||||||
typeahead="target as target.name for target in getTargetAclTypeahead($viewValue) | filter: $viewValue"
|
|
||||||
typeahead-template-url="partial/docs/directive.typeahead.acl.html"
|
|
||||||
typeahead-wait-ms="200" />
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<span class="btn btn-primary" ng-if="acl.target.type" ng-click="acl.target = null">
|
|
||||||
<acl data="acl.target"></acl>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class=" col-sm-2 control-label" for="inputPermission">Permission</label>
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<select class="form-control" ng-model="acl.perm" id="inputPermission">
|
|
||||||
<option value="READ">Can read</option>
|
|
||||||
<option value="READWRITE">Can edit</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
|
||||||
<button type="submit" class="btn btn-primary" ng-disabled="!acl.target.type" ng-click="addAcl()">
|
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
@ -0,0 +1,6 @@
|
|||||||
|
<h1>Tags</h1>
|
||||||
|
<p><strong>Tags</strong> are labels associated to documents.</p>
|
||||||
|
<p>A document can be tagged by multiple tags, and a tag can be applied to multiple documents.</p>
|
||||||
|
<p>Using the <span class="glyphicon glyphicon-user"></span> button, you can edit permissions on a tag.</p>
|
||||||
|
<p>If a tag can be read by another user or group, associated documents can also be read by those people.</p>
|
||||||
|
<p>For example, tag your company documents with a tag <span class="label label-info">MyCompany</span> and add the permission <strong>Read</strong> to a group <span class="btn btn-default">employees</span></p>
|
4
docs-web/src/main/webapp/src/partial/docs/tag.edit.html
Normal file
4
docs-web/src/main/webapp/src/partial/docs/tag.edit.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<acl-edit source="tag.id"
|
||||||
|
acls="tag.acls"
|
||||||
|
writable="tag.writable"
|
||||||
|
creator="tag.creator"></acl-edit>
|
@ -5,10 +5,9 @@
|
|||||||
<p class="input-group" ng-class="{ 'has-error': !tagForm.name.$valid }">
|
<p class="input-group" ng-class="{ 'has-error': !tagForm.name.$valid }">
|
||||||
<span colorpicker class="input-group-addon btn btn-default" data-color="#3a87ad" ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span>
|
<span colorpicker class="input-group-addon btn btn-default" data-color="#3a87ad" ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span>
|
||||||
<input type="text" name="name" placeholder="New tag" class="form-control"
|
<input type="text" name="name" placeholder="New tag" class="form-control"
|
||||||
ng-maxlength="36" required ng-model="tag.name" ui-validate="{duplicate: 'validateDuplicate($value)', space: '!$value || $value.indexOf(\' \') == -1' }">
|
ng-maxlength="36" required ng-model="tag.name" ui-validate="{ space: '!$value || $value.indexOf(\' \') == -1' }">
|
||||||
<span class="input-group-addon btn btn-primary" ng-disabled="!tagForm.$valid" ng-click="addTag()">Add</span>
|
<span class="input-group-addon btn btn-primary" ng-disabled="!tagForm.$valid" ng-click="addTag()">Add</span>
|
||||||
</p>
|
</p>
|
||||||
<span class="help-block" ng-show="tagForm.name.$error.duplicate">This tag already exists</span>
|
|
||||||
<span class="help-block" ng-show="tagForm.name.$error.space">Space are not allowed</span>
|
<span class="help-block" ng-show="tagForm.name.$error.space">Space are not allowed</span>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@ -31,22 +30,15 @@
|
|||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td class="col-xs-1"><span colorpicker class="btn" on-hide="updateTag(tag)" data-color="" ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span></td>
|
<td class="col-xs-1"><span colorpicker class="btn" on-hide="updateTag(tag)" data-color="" ng-model="tag.color" ng-style="{ 'background': tag.color }"> </span></td>
|
||||||
<td class="col-xs-1"><button class="btn btn-danger pull-right" ng-click="deleteTag(tag)"><span class="glyphicon glyphicon-trash"></span></button></td>
|
<td class="col-xs-1"><a href="#/tag/{{ tag.id }}" class="btn btn-default pull-right" title="Edit permissions"><span class="glyphicon glyphicon-user"></span></a></td>
|
||||||
|
<td class="col-xs-1"><button class="btn btn-danger pull-right" ng-click="deleteTag(tag)" title="Delete this tag"><span class="glyphicon glyphicon-trash"></span></button></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-8" ng-if="stats.length >= 0">
|
<div class="col-md-8">
|
||||||
<h1>{{ tags.length }} <small>tag{{ tags.length > 1 ? 's' : '' }}</small></h1>
|
<div ui-view="tag"></div>
|
||||||
<dl class="dl-horizontal" ng-repeat="stat in stats | orderBy: '-count'">
|
|
||||||
<dt>{{ stat.name }} <span class="badge badge-info" ng-style="{ 'background': stat.color }">{{ stat.count }}</span></dt>
|
|
||||||
<dd><progressbar value="stat.count / getStatCount() * 100" class="progress-info"></progressbar></dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-8" ng-if="!stats">
|
|
||||||
<img src="img/loader.gif" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -0,0 +1,2 @@
|
|||||||
|
<h1>Users & Groups</h1>
|
||||||
|
<p>Here you can view informations about users and groups.</p>
|
@ -357,12 +357,13 @@ public class TestAclResource extends BaseJerseyTest {
|
|||||||
.param("language", "eng")));
|
.param("language", "eng")));
|
||||||
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
|
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
|
||||||
|
|
||||||
// acltag2 can see document1 with tag1
|
// acltag2 can see document1 with tag1 (non-writable)
|
||||||
json = target().path("/document/" + document1Id).request()
|
json = target().path("/document/" + document1Id).request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
.get(JsonObject.class);
|
.get(JsonObject.class);
|
||||||
tags = json.getJsonArray("tags");
|
tags = json.getJsonArray("tags");
|
||||||
Assert.assertEquals(1, tags.size());
|
Assert.assertEquals(1, tags.size());
|
||||||
|
Assert.assertFalse(json.getBoolean("writable"));
|
||||||
Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id"));
|
Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id"));
|
||||||
|
|
||||||
// acltag2 can see tag1
|
// acltag2 can see tag1
|
||||||
@ -392,6 +393,15 @@ public class TestAclResource extends BaseJerseyTest {
|
|||||||
.param("target", "acltag2")
|
.param("target", "acltag2")
|
||||||
.param("type", "USER")), JsonObject.class);
|
.param("type", "USER")), JsonObject.class);
|
||||||
|
|
||||||
|
// acltag2 can see document1 with tag1 (writable)
|
||||||
|
json = target().path("/document/" + document1Id).request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
.get(JsonObject.class);
|
||||||
|
tags = json.getJsonArray("tags");
|
||||||
|
Assert.assertEquals(1, tags.size());
|
||||||
|
Assert.assertTrue(json.getBoolean("writable"));
|
||||||
|
Assert.assertEquals(tag1Id, tags.getJsonObject(0).getString("id"));
|
||||||
|
|
||||||
// acltag2 can see and edit tag1
|
// acltag2 can see and edit tag1
|
||||||
json = target().path("/tag/" + tag1Id).request()
|
json = target().path("/tag/" + tag1Id).request()
|
||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, acltag2Token)
|
||||||
|
@ -2,11 +2,17 @@ package com.sismics.docs.rest;
|
|||||||
|
|
||||||
import javax.json.JsonArray;
|
import javax.json.JsonArray;
|
||||||
import javax.json.JsonObject;
|
import javax.json.JsonObject;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.EntityTransaction;
|
||||||
import javax.ws.rs.client.Entity;
|
import javax.ws.rs.client.Entity;
|
||||||
import javax.ws.rs.core.Form;
|
import javax.ws.rs.core.Form;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
import com.sismics.docs.core.dao.jpa.AclDao;
|
||||||
|
import com.sismics.util.context.ThreadLocalContext;
|
||||||
|
import com.sismics.util.jpa.EMF;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -57,6 +63,35 @@ public class TestAppResource extends BaseJerseyTest {
|
|||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
.post(Entity.form(new Form()));
|
.post(Entity.form(new Form()));
|
||||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
|
||||||
|
// Create a tag
|
||||||
|
json = target().path("/tag").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
|
.put(Entity.form(new Form()
|
||||||
|
.param("name", "Tag4")
|
||||||
|
.param("color", "#00ff00")), JsonObject.class);
|
||||||
|
String tagId = json.getString("id");
|
||||||
|
|
||||||
|
// Init transactional context
|
||||||
|
EntityManager em = EMF.get().createEntityManager();
|
||||||
|
ThreadLocalContext context = ThreadLocalContext.get();
|
||||||
|
context.setEntityManager(em);
|
||||||
|
EntityTransaction tx = em.getTransaction();
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
|
// Remove base ACLs
|
||||||
|
AclDao aclDao = new AclDao();
|
||||||
|
aclDao.delete(tagId, PermType.READ, "admin", "admin");
|
||||||
|
aclDao.delete(tagId, PermType.WRITE, "admin", "admin");
|
||||||
|
Assert.assertEquals(0, aclDao.getBySourceId(tagId).size());
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
// Add base ACLs to tags
|
||||||
|
response = target().path("/app/batch/tag_acls").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
|
.post(Entity.form(new Form()));
|
||||||
|
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||||
|
Assert.assertEquals(2, aclDao.getBySourceId(tagId).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,6 +52,7 @@ public class TestTagResource extends BaseJerseyTest {
|
|||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, tag1Token)
|
||||||
.get(JsonObject.class);
|
.get(JsonObject.class);
|
||||||
Assert.assertEquals("Tag4", json.getString("name"));
|
Assert.assertEquals("Tag4", json.getString("name"));
|
||||||
|
Assert.assertEquals("tag1", json.getString("creator"));
|
||||||
Assert.assertEquals("#00ff00", json.getString("color"));
|
Assert.assertEquals("#00ff00", json.getString("color"));
|
||||||
Assert.assertTrue(json.getBoolean("writable"));
|
Assert.assertTrue(json.getBoolean("writable"));
|
||||||
JsonArray acls = json.getJsonArray("acls");
|
JsonArray acls = json.getJsonArray("acls");
|
||||||
|
Loading…
Reference in New Issue
Block a user