This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository coselmar. See http://git.codelutin.com/coselmar.git commit 5e3299722403c4f027fde642d99e9204dceedc5e Author: Yannick Martel <martel@©odelutin.com> Date: Thu Nov 27 11:11:18 2014 +0100 #6142 Filter documents list according to privacy and userRole --- .../fr/ifremer/coselmar/persistence/DaoUtils.java | 112 +++++++++++++++++++++ .../persistence/entity/DocumentTopiaDao.java | 32 ++++++ .../coselmar/services/v1/DocumentsWebService.java | 36 ++++++- coselmar-ui/src/main/webapp/index.html | 9 +- .../src/main/webapp/views/documents/documents.html | 2 +- 5 files changed, 180 insertions(+), 11 deletions(-) diff --git a/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/DaoUtils.java b/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/DaoUtils.java new file mode 100644 index 0000000..c8c1cc6 --- /dev/null +++ b/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/DaoUtils.java @@ -0,0 +1,112 @@ +package fr.ifremer.coselmar.persistence; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +/** + * Class containing utilities methods for DAO request. + * + * @author Eric Chatellier + * @author Arnaud Thimel (Code Lutin) + * @author ymartel (codelutin) + */ +public class DaoUtils { + + protected static final String LIKE = + "TRANSLATE(LOWER( %s )," + + "'áàâãäåāăąèééêëēĕėęěìíîïìĩīĭḩóôõöōŏőùúûüũūŭůäàáâãåæçćĉčöòóôõøüùúûßéèêëýñîìíïş'," + + "'aaaaaaaaaeeeeeeeeeeiiiiiiiihooooooouuuuuuuuaaaaaaeccccoooooouuuuseeeeyniiiis')" + + "like LOWER( %s )"; + + /** + * Generate sql like operator case and accent insensitive. + * + * @param field1 entity field to search into + * @param field2 value field (must be accent escaped) + * @return sql string + */ + public static String getFieldLikeInsensitive(String field1, String field2) { + String query = String.format(LIKE, field1, field2); + return query; + } + + public static String addQueryAttribute(Map<String, Object> args, String entityAttributeName, Object value) { + String baseAttributeName = entityAttributeName.replaceAll("[.]", "_"); + + int index = 0; + String queryAttributeName; + do { + queryAttributeName = baseAttributeName + index; + index++; + } while (args.containsKey(queryAttributeName)); + + args.put(queryAttributeName, value); + + return queryAttributeName; + } + + protected static String getQueryForAttributeLike(String entityAlias, String entityAttributeName, Map<String, Object> args, String likeValue, String operator) { + // TODO AThimel 12/07/13 Refactor : peut-être qu'il n'est pas nécessaire d'utiliser la méthode "getFieldLikeInsensitive" + String alias = StringUtils.isBlank(entityAlias) ? "" : entityAlias + "."; + String queryAttributeName = addQueryAttribute(args, entityAttributeName, StringUtils.stripAccents(likeValue)); + String result = " " + operator + " " + DaoUtils.getFieldLikeInsensitive(alias + entityAttributeName, ":" + queryAttributeName); + + return result; + } + + public static String getQueryForAttributeEquals(String entityAlias, String entityAttributeName, Map<String, Object> args, Object value, String operator) { + String result = ""; + + if (value != null) { + String alias = StringUtils.isBlank(entityAlias) ? "" : entityAlias + "."; + String queryAttributeName = addQueryAttribute(args, entityAttributeName, value); + result += String.format(" %s %s = :%s", operator, alias + entityAttributeName, queryAttributeName); + } + + return result; + } + + public static String andAttributeEquals(String entityAlias, String entityAttributeName, Map<String, Object> args, Object value) { + String result = getQueryForAttributeEquals(entityAlias, entityAttributeName, args, value, "AND"); + return result; + } + + public static String orAttributeEquals(String entityAlias, String entityAttributeName, Map<String, Object> args, Object value) { + String result = getQueryForAttributeEquals(entityAlias, entityAttributeName, args, value, "OR"); + return result; + } + + public static String andAttributeLike(String entityAlias, String entityAttributeName, Map<String, Object> args, String value) { + String result = ""; + if (StringUtils.isNotBlank(value)) { + result = getQueryForAttributeLike(entityAlias, entityAttributeName, args, "%" + value + "%", "AND"); + } + return result; + } + + public static String orAttributeLike(String entityAlias, String entityAttributeName, Map<String, Object> args, String value) { + String result = ""; + if (StringUtils.isNotBlank(value)) { + result = getQueryForAttributeLike(entityAlias, entityAttributeName, args, "%" + value + "%", "OR"); + } + + return result; + } + + protected static String getQueryForAttributeContains(String entityAlias, String entityAttributeName, Map<String, Object> args, Object value, String operator) { + String result = ""; + + String alias = StringUtils.isBlank(entityAlias) ? "" : entityAlias + "."; + String queryAttributeName = addQueryAttribute(args, entityAttributeName, value); + result += String.format(" %s %s in element( :%s )", operator, queryAttributeName, alias + entityAttributeName); + + return result; + } + + public static String andAttributeContains(String entityAlias, String entityAttributeName, Map<String, Object> args, Object value) { + String result = getQueryForAttributeContains(entityAlias, entityAttributeName, args, value, "AND"); + return result; + } + +} diff --git a/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/entity/DocumentTopiaDao.java b/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/entity/DocumentTopiaDao.java index efee2f6..4648ff4 100644 --- a/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/entity/DocumentTopiaDao.java +++ b/coselmar-persistence/src/main/java/fr/ifremer/coselmar/persistence/entity/DocumentTopiaDao.java @@ -24,7 +24,11 @@ package fr.ifremer.coselmar.persistence.entity; * #L% */ +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import fr.ifremer.coselmar.persistence.DaoUtils; public class DocumentTopiaDao extends AbstractDocumentTopiaDao<Document> { @@ -34,8 +38,36 @@ public class DocumentTopiaDao extends AbstractDocumentTopiaDao<Document> { for (String keyword : keywords) { queryBuilder.addContains(Document.PROPERTY_KEYWORDS, keyword); } + List<Document> documents = queryBuilder.findAll(); return documents; } + public List<Document> findAllFilterByUser(CoselmarUser currentUser, List<String> keywords) { + + StringBuilder hqlBuilder = new StringBuilder("FROM " + Document.class.getName() + " D"); + + Map<String, Object> args = new HashMap<>(); + + // can list all public document + String privacyPublicCondition = DaoUtils.getQueryForAttributeEquals("D", Document.PROPERTY_PRIVACY, args, DocumentPrivacy.PUBLIC, ""); + hqlBuilder.append(" WHERE " + privacyPublicCondition); + + // Can list his own private document + String privacyPrivateCondition = DaoUtils.getQueryForAttributeEquals("D", Document.PROPERTY_PRIVACY, args, DocumentPrivacy.PRIVATE, ""); + String ownerCondition = DaoUtils.andAttributeEquals("D", Document.PROPERTY_OWNER, args, currentUser); + + hqlBuilder.append(" OR ( " + privacyPrivateCondition + " " + ownerCondition + " )"); + + if (keywords != null) { + for (String keyword : keywords) { + DaoUtils.andAttributeContains("D", Document.PROPERTY_KEYWORDS, args, keyword); + } + } + + List<Document> documents = forHql(hqlBuilder.toString(), args).findAll(); + + return documents; + } + } //DocumentTopiaDao diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java index bde35f3..99717c1 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/DocumentsWebService.java @@ -101,14 +101,29 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { return documentBean; } - public List<DocumentBean> getDocuments(List<String> searchKeywords) { + public List<DocumentBean> getDocuments(List<String> searchKeywords) throws InvalidCredentialException { + + // Check authentication + String authorization = getContext().getHeader("Authorization"); + UserWebToken userWebToken = checkAuthentication(authorization); + + // Retrieve current user + String fullCurrentUserId = getFullUserIdFromShort(userWebToken.getUserId()); + CoselmarUser currentUser = getCoselmarUserDao().forTopiaIdEquals(fullCurrentUserId).findAnyOrNull(); + + String currentUserRole = userWebToken.getRole().toUpperCase(); List<Document> documentList; - if (searchKeywords != null && !searchKeywords.isEmpty()) { - documentList = getDocumentDao().findAllContainingAllKeywords(searchKeywords); + + // Admin and Supervisor can see all documents (public, private and restricted) + if (Lists.newArrayList(CoselmarUserRole.ADMIN.name(), CoselmarUserRole.ADMIN.name()).contains(currentUserRole)) { + documentList = findAllDocuments(searchKeywords); + } else { - documentList = getDocumentDao().findAll(); + //Other can only see public, his own private and restricted for which he is allowed + documentList = getDocumentDao().findAllFilterByUser(currentUser, searchKeywords);; } + List<DocumentBean> result = new ArrayList<>(documentList.size()); for (Document document : documentList) { @@ -362,7 +377,7 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { } else if (document.getPrivacy() == DocumentPrivacy.PRIVATE) { CoselmarUser documentOwner = document.getOwner(); boolean isOwner = StringUtils.equals(documentOwner.getTopiaId(), getFullUserIdFromShort(userWebToken.getUserId())); - isAuthorized = isOwner || Lists.newArrayList(CoselmarUserRole.ADMIN, CoselmarUserRole.SUPERVISOR).contains(viewerRole); + isAuthorized = isOwner || Lists.newArrayList(CoselmarUserRole.ADMIN.name(), CoselmarUserRole.SUPERVISOR.name()).contains(viewerRole); } else { // Restricted : Not yet implemented @@ -374,4 +389,15 @@ public class DocumentsWebService extends CoselmarWebServiceSupport { protected String getDocumentFullId(String documentId) { return Document.class.getCanonicalName() + getPersistenceContext().getTopiaIdFactory().getSeparator() + documentId; } + + protected List<Document> findAllDocuments(List<String> searchKeywords) { + List<Document> documentList; + if (searchKeywords != null && !searchKeywords.isEmpty()) { + documentList = getDocumentDao().findAllContainingAllKeywords(searchKeywords); + } else { + documentList = getDocumentDao().findAll(); + } + return documentList; + } + } diff --git a/coselmar-ui/src/main/webapp/index.html b/coselmar-ui/src/main/webapp/index.html index f8ac539..d277fe7 100644 --- a/coselmar-ui/src/main/webapp/index.html +++ b/coselmar-ui/src/main/webapp/index.html @@ -34,7 +34,6 @@ <script src="nuiton-js/angular-messages.js"></script> <script src="nuiton-js/angular-ui-bootstrap.js"></script> <script src="nuiton-js/bootstrap.js"></script> - <script src="nuiton-js/bootstrap-tpls.js"></script> <script src="js/angular-jwt.js"></script> <script src="js/coselmar.js"></script> <script src="js/coselmar-constants.js"></script> @@ -64,17 +63,17 @@ <nav class="hidden-xs"> <ul class="nav navbar-nav"> <a href="#" role="button" class="navbar-brand">Coselmar Traceability</a> - <li class="dropdown" ng-if="currentUser.role == 'ADMIN'"> + <li ng-if="currentUser.role == 'ADMIN'"> <a href="#/users" class="dropdown-toggle">User</a> </li> - <li class="dropdown" ng-if="currentUser"> + <li ng-if="currentUser"> <a href="#/documents" role="button" class="dropdown-toggle">Documents</a> </li> <li class="dropdown"> <a role="button" class="dropdown-toggle">Questions<span class="caret"></span></a> <ul class="dropdown-menu" role="menu"> - <li><a href="#/questions">List</a></li> - <li><a href="#/questions">List</a></li> + <!--<li><a href="#/questions">List</a></li>--> + <!--<li><a href="#/questions">List</a></li>--> </ul> </li> </ul> diff --git a/coselmar-ui/src/main/webapp/views/documents/documents.html b/coselmar-ui/src/main/webapp/views/documents/documents.html index 4c089ef..e35b46c 100644 --- a/coselmar-ui/src/main/webapp/views/documents/documents.html +++ b/coselmar-ui/src/main/webapp/views/documents/documents.html @@ -31,7 +31,7 @@ <div> <div> - <div class="form-group"> + <div class="form-group" ng-if="currentUser.role == 'EXPERT'> <a href="#/documents/new" class="form-inline navbar-left btn btn-primary">Add a document</a> </div> <form class="form-inline pull-right" role="documentOptions" ng-submit="searchDocuments()"> -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.