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 a515fab40bd481eee110db24c4a9ac1a319d6406 Author: Yannick Martel <martel@©odelutin.com> Date: Tue Dec 9 16:12:44 2014 +0100 fixes #6019 participants on the question can add new documents in it --- .../coselmar/services/v1/QuestionsWebService.java | 56 +++++++++++++ coselmar-rest/src/main/resources/mapping | 2 +- .../src/main/webapp/js/coselmar-controllers.js | 94 ++++++++++++++++++++-- .../main/webapp/js/coselmar-questions-services.js | 23 +++++- coselmar-ui/src/main/webapp/js/coselmar.js | 2 +- .../main/webapp/views/questions/editquestion.html | 4 +- .../webapp/views/questions/newDocumentsPart.html | 38 +++++++++ .../src/main/webapp/views/questions/question.html | 29 +++++-- 8 files changed, 228 insertions(+), 20 deletions(-) diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java index 13939d0..61e1b2e 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/services/v1/QuestionsWebService.java @@ -9,6 +9,7 @@ import java.util.Set; import com.google.common.base.Function; import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; import fr.ifremer.coselmar.beans.DocumentBean; import fr.ifremer.coselmar.beans.QuestionBean; import fr.ifremer.coselmar.beans.UserBean; @@ -305,6 +306,61 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { return result; } + public void addDocuments(String questionId, DocumentBean[] documents) throws InvalidCredentialException, UnauthorizedException { + + // Check authentication + String authorization = getContext().getHeader("Authorization"); + UserWebToken userWebToken = checkAuthentication(authorization); + + // Only Supervisor can add question + String userRole = userWebToken.getRole(); + + if (!StringUtils.equalsIgnoreCase(CoselmarUserRole.SUPERVISOR.name(), userRole) + && StringUtils.equalsIgnoreCase(CoselmarUserRole.ADMIN.name(), userRole)) { + String message = String.format("User %s %s ('%s') is not allowed to delete question", + userWebToken.getFirstName(), userWebToken.getLastName(), userWebToken.getUserId()); + if (log.isWarnEnabled()) { + log.warn(message); + } + throw new UnauthorizedException(message); + + } + + String fullUserId = getFullIdFromShort(CoselmarUser.class, userWebToken.getUserId()); + + try { + getCoselmarUserDao().forTopiaIdEquals(fullUserId).findUnique(); + } catch (TopiaNoResultException tnre) { + // Should not happened, cause user are not really deleted + String message = String.format("Logged user ('%s') does not exist.", fullUserId); + if (log.isErrorEnabled()) { + log.error(message); + } + throw new InvalidCredentialException(message); + } + + // Retrieve Question + String fullQuestionId = getFullIdFromShort(Question.class, questionId); + Question question = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + + // Retrieve all documents + Collection<Document> questionDocuments = question.getRelatedDocuments(); + if (documents != null && documents.length > 0) { + List<Document> documentEntities = retrieveDocuments(Lists.newArrayList(documents)); + // Manage restriction list for document with Privacy.RESTRICTED + for (Document document : documentEntities) { + if (document.getPrivacy() == Privacy.RESTRICTED) { + document.addRestrictedList(question.getParticipants()); + } + if (!questionDocuments.contains(document)) { + question.addRelatedDocuments(document); + } + } + } + + commit(); + } + //////////////////////////////////////////////////////////////////////////// /////////////////////// Internal Parts ///////////////////////////// diff --git a/coselmar-rest/src/main/resources/mapping b/coselmar-rest/src/main/resources/mapping index fe16e65..49e9c52 100644 --- a/coselmar-rest/src/main/resources/mapping +++ b/coselmar-rest/src/main/resources/mapping @@ -48,7 +48,7 @@ DELETE /v1/users/{userId} UsersWebService.deleteUser GET /v1/questions QuestionsWebService.getQuestions GET /v1/questions/{questionId} QuestionsWebService.getQuestion #POST /v1/questions/{questionId} QuestionsWebService.saveQuestion -#POST /v1/questions/{questionId}/documents QuestionsWebService.addDocuments +POST /v1/questions/{questionId}/documents QuestionsWebService.addDocuments POST /v1/questions QuestionsWebService.addQuestion DELETE /v1/questions/{questionId} QuestionsWebService.deleteQuestion diff --git a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js index 13e9f77..0150ba5 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js +++ b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js @@ -423,10 +423,12 @@ coselmarControllers.controller("QuestionsCtrl", ['$scope', '$route', '$routePara }]); // Controller for All User View -coselmarControllers.controller("QuestionViewCtrl", ['$scope', '$route', '$routeParams', '$location', 'questionsService', - function($scope, $route, $routeParams, $location, questionsService){ +coselmarControllers.controller("QuestionCtrl", ['$scope', '$route', '$routeParams', '$location', '$modal', 'questionsService', + function($scope, $route, $routeParams, $location, $modal, questionsService){ $scope.editMode = $routeParams.edit ? $routeParams.edit : false; + $scope.isCurrentParticipant = false; + $scope.question = { 'newRelatedDocuments': []}; $scope.edit = function() { $location.search("edit"); @@ -437,17 +439,23 @@ coselmarControllers.controller("QuestionViewCtrl", ['$scope', '$route', '$routeP // success : just get the questions $scope.question = question; + // update scope about current user : if he is participant, more option enable in ui + for (var i = 0; i < $scope.question.participants.length; i++) { + if ($scope.question.participants[i].id == $scope.currentUser.userId) { + $scope.isCurrentParticipant = true; + // Should be able to put new documents in question + $scope.question.newRelatedDocuments = []; + break; + } + } + }, function(error) { // Fail function : TODO console.log("error during request"); console.log(error); }); - - $scope.saveQuestion = function(isValidForm){ - console.log($scope.question); - }; - + //Deletion $scope.deleteQuestion = function(){ questionsService.deleteQuestion($routeParams.questionId, function() { // success : goto questions list @@ -459,6 +467,76 @@ coselmarControllers.controller("QuestionViewCtrl", ['$scope', '$route', '$routeP }); }; + $scope.saveQuestion = function(isValidForm){ + //TODO + }; + + // New documents added + $scope.validateNewDocuments = function(){ + + if ($scope.question.newRelatedDocuments + && $scope.question.newRelatedDocuments.length > 0) { + + questionsService.addNewDocuments($routeParams.questionId, $scope.question.newRelatedDocuments, function() { + $route.reload(); + + }, function(error) { + // Fail function : TODO + console.log(error); + }); + } + }; + + // Modals part for documents + $scope.modalSearchDocuments = function (documentList) { + + var modalInstance = $modal.open({ + templateUrl: 'views/documents/modalDocumentSearch.html', + controller: 'ModalSearchDocumentsCtrl', + size: 'lg' + }); + + modalInstance.result.then(function (selectedDocument) { + var already = false; + for (var i = 0; i < documentList.length; i++) { + if (documentList[i].id == selectedDocument.id) { + already = true; + } + } + if (!already) { + documentList.push(selectedDocument); + } + }); + }; + + $scope.modalCreateDocument = function (documentList) { + + var modalInstance = $modal.open({ + templateUrl: 'views/documents/modalDocumentEdit.html', + controller: 'ModalCreateDocumentsCtrl', + size: 'lg' + }); + + modalInstance.result.then(function (selectedDocument) { + var already = false; + for (var i = 0; i < documentList.length; i++) { + if (documentList[i].id == selectedDocument.id) { + already = true + } + } + if (!already) { + documentList.push(selectedDocument); + } + }); + }; + + $scope.removeDocument = function(document, documentList) { + var position = documentList.indexOf(document); + if (document && position != -1) { + documentList.splice(position, 1); + } + } + }]); @@ -493,7 +571,7 @@ coselmarControllers.controller('ModalCreateDocumentsCtrl', function ($scope, $mo $scope.create = function (isValidForm) { - if (angular.isDate($scope.question.publicationDate)) { + if (angular.isDate($scope.document.publicationDate)) { $scope.document.publicationDate = $scope.document.publicationDate.getTime(); } diff --git a/coselmar-ui/src/main/webapp/js/coselmar-questions-services.js b/coselmar-ui/src/main/webapp/js/coselmar-questions-services.js index 60c219f..5aa3448 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar-questions-services.js +++ b/coselmar-ui/src/main/webapp/js/coselmar-questions-services.js @@ -15,7 +15,7 @@ function Question(resource, config){ var formData = new FormData(); formData.append("question", JSON.stringify(question)); - // Save the User + // Save the Question var serviceURl = baseURL; if (question.id) { serviceURl = baseURL + "/" + question.id @@ -34,7 +34,7 @@ function Question(resource, config){ this.findUsers = function(example, successFunction) { var userResource = resource(usersURL, {'like': example}); - userResource.query().$promise.then(successFunction); + userResource.query(successFunction); }; @@ -52,4 +52,23 @@ function Question(resource, config){ var questionResource = resource(baseURL + "/" + questionId); questionResource.get().$promise.then(successFunction, failFunction); } + + this.addNewDocuments = function(questionId, documents, successFunction, failFunction) { + + var formData = new FormData(); + formData.append("documents", JSON.stringify(documents)); + + var serviceURl = baseURL + "/" + questionId + "/documents"; + var questionResource = resource(serviceURl, null, { + 'save': { + method:'POST', + transformRequest: angular.identity, + isArray: true, + headers:{ + 'Content-Type': undefined + } + } + }); + questionResource.save(null, formData, successFunction, failFunction); + } }; \ No newline at end of file diff --git a/coselmar-ui/src/main/webapp/js/coselmar.js b/coselmar-ui/src/main/webapp/js/coselmar.js index 38b2605..cf7cd2f 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar.js +++ b/coselmar-ui/src/main/webapp/js/coselmar.js @@ -61,7 +61,7 @@ coselmarApp.config(['$routeProvider', function($routeProvider) { templateUrl : 'views/questions/newquestion.html' }).when('/questions/:questionId', { - controller : 'QuestionViewCtrl', + controller : 'QuestionCtrl', templateUrl : 'views/questions/question.html' diff --git a/coselmar-ui/src/main/webapp/views/questions/editquestion.html b/coselmar-ui/src/main/webapp/views/questions/editquestion.html index c43759d..c42e8e2 100644 --- a/coselmar-ui/src/main/webapp/views/questions/editquestion.html +++ b/coselmar-ui/src/main/webapp/views/questions/editquestion.html @@ -131,7 +131,7 @@ </ui-select-match> <ui-select-choices - repeat="expert in users.participants | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search}"> + repeat="expert in users.participants track by expert.id | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search}"> {{expert.firstName}} {{expert.name}} ({{expert.organization}}) </ui-select-choices> </ui-select> @@ -200,7 +200,7 @@ </ui-select-match> <ui-select-choices - repeat="expert in users.supervisors | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search}"> + repeat="expert in users.supervisors track by expert.id | propsFilter: {name: $select.search, firstName: $select.search, organization: $select.search}"> {{expert.firstName}} {{expert.name}} ({{expert.organization}}) </ui-select-choices> </ui-select> diff --git a/coselmar-ui/src/main/webapp/views/questions/newDocumentsPart.html b/coselmar-ui/src/main/webapp/views/questions/newDocumentsPart.html new file mode 100644 index 0000000..a742523 --- /dev/null +++ b/coselmar-ui/src/main/webapp/views/questions/newDocumentsPart.html @@ -0,0 +1,38 @@ +<div class=""> + + <div class="form-group col-md-12"> + + <dl> + + <dt>Contribute with new Documents</dt> + + <dd> + <table class="table table-bordered table-condensed"> + <tr> + <th>Name</th> + <th>Owner</th> + <th>Keywords</th> + <th>Deposit Date</th> + <th> + <a class="btn fa fa-search" title="Search document" + ng-click="modalSearchDocuments(question.newRelatedDocuments)"/> + <a class="btn fa fa-plus" title="Add new Document" + ng-click="modalCreateDocument(question.newRelatedDocuments)"/> + </th> + </tr> + <tr ng-repeat="document in question.newRelatedDocuments"> + <td>{{document.name}}</a></td> + <td>{{document.ownerName}}</td> + <td><span + ng-repeat="keyword in document.keywords">{{keyword}}, </span></td> + <td>{{document.depositDate | date:'mediumDate'}}</td> + <td><a class="btn fa fa-minus" title="Remove document" + ng-click="removeDocument(document, question.newRelatedDocuments)" /></td> + </tr> + </table> + </dd> + </dl> + + </div> + +</div> \ No newline at end of file diff --git a/coselmar-ui/src/main/webapp/views/questions/question.html b/coselmar-ui/src/main/webapp/views/questions/question.html index 33225d5..d5e53b8 100644 --- a/coselmar-ui/src/main/webapp/views/questions/question.html +++ b/coselmar-ui/src/main/webapp/views/questions/question.html @@ -1,19 +1,30 @@ <div style="padding: 0px 0px 0px 30px"> <div class="page-header" style="margin: 0"> - <h2>{{question.title}} - <a class="btn btn-action btn-edit pull-right" ng-click="edit()" ng-if="editMode != true"> - <span class="fa fa-edit" aria-hidden="true"></span>Edit - </a></h2> + <h2> + {{question.title}} + <!--<a class="btn btn-action btn-edit pull-right" ng-click="edit()" ng-if="editMode != true">--> + <!--<span class="fa fa-edit" aria-hidden="true"></span>Edit--> + <!--</a>--> + </h2> </div> - <div style="padding-bottom: 50px" ng-include="src='views/questions/viewquestion.html'" ng-if="editMode == false"> + <div style="padding-bottom: 50px" ng-if="editMode == false"> + <div ng-include="src='views/questions/viewquestion.html'"></div> + <div ng-include="src='views/questions/newDocumentsPart.html'" ng-if="isCurrentParticipant"></div> + </div> + + <div style="padding-bottom: 50px" ng-if="editMode == true"> + <div ng-include="src='views/questions/editquestion.html'"></div> + <div><a class="btn btn-action btn-success" ng-click="saveQuestion()"> + <span class="fa fa-check-square-o" aria-hidden="true"></span>Close + </a></div> </div> <div class="text-center" ng-if="question.closingDate"> Closed on {{question.closingDate}}. </div> - <div class="text-center" ng-if="!question.closingDate && currentUser.role == 'SUPERVISOR'"> + <div class="text-center" ng-if="!question.closingDate && currentUser.role == 'SUPERVISOR' && editMode == false"> <a class="btn btn-action btn-success" ng-click="closeQuestion()"> <span class="fa fa-check-square-o" aria-hidden="true"></span>Close </a> @@ -27,4 +38,10 @@ </a> </div> + <div class="text-center" ng-if="!question.closingDate && isCurrentParticipant && editMode == false && question.newRelatedDocuments.length > 0"> + <a class="btn btn-action btn-success" ng-click="validateNewDocuments()"> + <span class="fa fa-check-square-o" aria-hidden="true"></span>Validate new documents + </a> + </div> + </div> \ No newline at end of file -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.