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 349b65cf339f83d0436baa217614de7e90ef448d Author: Yannick Martel <martel@©odelutin.com> Date: Wed Dec 10 12:12:08 2014 +0100 prepare full edit of question --- .../src/main/xmi/coselmar-model.zargo | Bin 9735 -> 9741 bytes .../coselmar/converter/BeanEntityConverter.java | 3 +- .../coselmar/services/v1/QuestionsWebService.java | 186 ++++++++++++++++++++- coselmar-rest/src/main/resources/mapping | 2 +- .../src/main/webapp/js/coselmar-controllers.js | 24 ++- .../main/webapp/views/questions/editquestion.html | 7 - .../main/webapp/views/questions/newquestion.html | 8 +- .../src/main/webapp/views/questions/question.html | 6 +- 8 files changed, 203 insertions(+), 33 deletions(-) diff --git a/coselmar-persistence/src/main/xmi/coselmar-model.zargo b/coselmar-persistence/src/main/xmi/coselmar-model.zargo index 830802b..9e32b2a 100644 Binary files a/coselmar-persistence/src/main/xmi/coselmar-model.zargo and b/coselmar-persistence/src/main/xmi/coselmar-model.zargo differ diff --git a/coselmar-rest/src/main/java/fr/ifremer/coselmar/converter/BeanEntityConverter.java b/coselmar-rest/src/main/java/fr/ifremer/coselmar/converter/BeanEntityConverter.java index 76449ea..5f20852 100644 --- a/coselmar-rest/src/main/java/fr/ifremer/coselmar/converter/BeanEntityConverter.java +++ b/coselmar-rest/src/main/java/fr/ifremer/coselmar/converter/BeanEntityConverter.java @@ -113,6 +113,7 @@ public class BeanEntityConverter { result.setSummary(question.getSummary()); result.setType(question.getType()); result.setPrivacy(question.getPrivacy().name()); + result.setStatus(question.getStatus().name()); Collection<String> theme = question.getTheme(); if (theme != null && !theme.isEmpty()) { @@ -166,7 +167,7 @@ public class BeanEntityConverter { for (CoselmarUser contributor : contributors) { String lightId = idFactory.getRandomPart(contributor.getTopiaId()); UserBean contributorBean = toBean(lightId, contributor); - result.addClient(contributorBean); + result.addContributor(contributorBean); } } 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 e00230c..661775c 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 @@ -151,7 +151,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Hierarchy of questions Set<QuestionBean> parents = question.getParents(); if (parents != null && !parents.isEmpty()) { - List<Question> questions = retrieveQuestions(parents); + Set<Question> questions = retrieveQuestions(parents); questionEntity.addAllParents(questions); } @@ -159,7 +159,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { // Documents on init Set<DocumentBean> relatedDocuments = question.getRelatedDocuments(); if (relatedDocuments != null && !relatedDocuments.isEmpty()) { - List<Document> documents = retrieveDocuments(relatedDocuments); + Set<Document> documents = retrieveDocuments(relatedDocuments); // Manage restriction list for document with Privacy.RESTRICTED for (Document document : documents) { if (document.getPrivacy() == Privacy.RESTRICTED) { @@ -351,7 +351,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { question.setStatus(Status.IN_PROGRESS); } - List<Document> documentEntities = retrieveDocuments(Lists.newArrayList(documents)); + Set<Document> documentEntities = retrieveDocuments(Lists.newArrayList(documents)); // Manage restriction list for document with Privacy.RESTRICTED for (Document document : documentEntities) { if (document.getPrivacy() == Privacy.RESTRICTED) { @@ -366,6 +366,178 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { commit(); } + public void saveQuestion(QuestionBean question) 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)) { + String message = String.format("User %s %s ('%s') is not allowed to save question", + userWebToken.getFirstName(), userWebToken.getLastName(), userWebToken.getUserId()); + if (log.isWarnEnabled()) { + log.warn(message); + } + throw new UnauthorizedException(message); + + } + + // retrieve user who will be assigned as question supervisor + String fullUserId = getFullUserIdFromShort(userWebToken.getUserId()); + + CoselmarUser supervisor; + try { + supervisor = 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); + } + + // let's go + Question questionEntity; + // An update + String questionId = question.getId(); + boolean inEdition = StringUtils.isNotBlank(questionId); + if (inEdition) { + String fullQuestionId = getFullIdFromShort(Question.class, questionId); + questionEntity = getQuestionDao().forTopiaIdEquals(fullQuestionId).findUnique(); + + } else { + // or a create + questionEntity = getQuestionDao().create(); + } + + // Question basics + + questionEntity.setTitle(question.getTitle()); + + questionEntity.setSummary(question.getSummary()); + + questionEntity.setType(question.getType()); + + Set<String> themes = question.getThemes(); + if (themes != null) { + questionEntity.setTheme(new HashSet(themes)); + } + + // By default, privacy is private + String privacy = question.getPrivacy(); + Privacy realPrivacy = privacy != null ? Privacy.valueOf(privacy.toUpperCase()) : Privacy.PRIVATE; + questionEntity.setPrivacy(realPrivacy); + + // On creation, Status is Open + if (inEdition) { + questionEntity.setStatus(question.getStatus() != null ? Status.valueOf(question.getStatus().toUpperCase()) : Status.OPEN); + } else { + questionEntity.setStatus(Status.OPEN); + } + + // Manage Dates : submission & deadline + Date submissionDate = question.getSubmissionDate(); + if (submissionDate != null) { + questionEntity.setSubmissionDate(new Date(submissionDate.getTime())); + } else { + questionEntity.setSubmissionDate(new Date()); + } + + Date deadline = question.getDeadline(); + if (deadline != null) { + questionEntity.setDeadline(new Date(deadline.getTime())); + } + + + // Users around the question + + // First Supervisor is the one creating this question + questionEntity.addSupervisors(supervisor); + + questionEntity.addAllExternalExperts(question.getExternalExperts()); + + // Retrieve the clients + Set<UserBean> clients = question.getClients(); + if (clients != null && !clients.isEmpty()) { + Set<CoselmarUser> clientEntities = retrieveUsers(clients); + questionEntity.addAllClients(clientEntities); + } + + // For participants, should create a dedicated group, + // that could be used to restrict documents access + Set<UserBean> participants = question.getParticipants(); + CoselmarUserGroup participantGroup; + + //On update, get the existing group, make a diff : removed participants become contributor + if (inEdition) { + participantGroup = questionEntity.getParticipants(); + + if (participants != null && !participants.isEmpty()) { + Set<CoselmarUser> expertEntities = retrieveUsers(participants); + + // For each already assigned participants, if not in new list, assign them as contributors + for (CoselmarUser participantBefore : participantGroup.getMembers()) { + if (!expertEntities.contains(participantBefore)) { + questionEntity.addContributors(participantBefore); + } + } + + participantGroup.clearMembers(); + participantGroup.addAllMembers(expertEntities); + } + + } else { + // If not update, create new group + participantGroup = getCoselmarUserGroupDao().create(); + participantGroup.setName(question.getTitle()); + + if (participants != null && !participants.isEmpty()) { + Set<CoselmarUser> expertEntities = retrieveUsers(participants); + participantGroup.addAllMembers(expertEntities); + } + } + questionEntity.setParticipants(participantGroup); + + // Retrieve the supervisor + Set<UserBean> supervisors = question.getSupervisors(); + if (supervisors != null && !supervisors.isEmpty()) { + Set<CoselmarUser> supervisorEntities = retrieveUsers(supervisors); + questionEntity.addAllSupervisors(supervisorEntities); + } + + // Note : no contributors now, contributors are old participants, + // excluded from process + + + // Hierarchy of questions + Set<QuestionBean> parents = question.getParents(); + if (parents != null && !parents.isEmpty()) { + Set<Question> questions = retrieveQuestions(parents); + questionEntity.addAllParents(questions); + } + + + // Documents on init + Set<DocumentBean> relatedDocuments = question.getRelatedDocuments(); + if (relatedDocuments != null && !relatedDocuments.isEmpty()) { + Set<Document> documents = retrieveDocuments(relatedDocuments); + // Manage restriction list for document with Privacy.RESTRICTED + for (Document document : documents) { + if (document.getPrivacy() == Privacy.RESTRICTED) { + document.addRestrictedList(participantGroup); + } + } + + questionEntity.addAllRelatedDocuments(documents); + } + + commit(); + } + //////////////////////////////////////////////////////////////////////////// /////////////////////// Internal Parts ///////////////////////////// @@ -386,7 +558,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { } - protected List<Question> retrieveQuestions(Collection<QuestionBean> questionBeans) { + protected Set<Question> retrieveQuestions(Collection<QuestionBean> questionBeans) { Function<QuestionBean, String> getIds = new Function<QuestionBean, String>() { @Override public String apply(QuestionBean questionBean) { @@ -396,11 +568,11 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Collection<String> questionIds = Collections2.transform(questionBeans, getIds); List<Question> questions = getQuestionDao().forTopiaIdIn(questionIds).findAll(); - return questions; + return new HashSet<>(questions); } - protected List<Document> retrieveDocuments(Collection<DocumentBean> documentBeans) { + protected Set<Document> retrieveDocuments(Collection<DocumentBean> documentBeans) { Function<DocumentBean, String> getIds = new Function<DocumentBean, String>() { @Override public String apply(DocumentBean documentBean) { @@ -410,7 +582,7 @@ public class QuestionsWebService extends CoselmarWebServiceSupport { Collection<String> documentIds = Collections2.transform(documentBeans, getIds); List<Document> documents = getDocumentDao().forTopiaIdIn(documentIds).findAll(); - return documents; + return new HashSet<>(documents); } diff --git a/coselmar-rest/src/main/resources/mapping b/coselmar-rest/src/main/resources/mapping index 49e9c52..0268034 100644 --- a/coselmar-rest/src/main/resources/mapping +++ b/coselmar-rest/src/main/resources/mapping @@ -47,7 +47,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} QuestionsWebService.saveQuestion 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 793cd38..993e497 100644 --- a/coselmar-ui/src/main/webapp/js/coselmar-controllers.js +++ b/coselmar-ui/src/main/webapp/js/coselmar-controllers.js @@ -281,13 +281,13 @@ coselmarControllers.controller("NewQuestionCtrl", ['$scope', '$route', '$locatio 'clients' : [], 'relatedDocuments': [] }; $scope.users = { 'participants' : [], 'clients': [], 'supervisors' : []}; - questionsService.findUsers({'role': 'EXPERT', 'active': 'true'}, function(users) { + questionsService.findUsers({'role': 'EXPERT', 'active': 'true'}, '', function(users) { $scope.users.participants = users; }); - questionsService.findUsers({'role': 'CLIENT', 'active': 'true'}, function(users) { + questionsService.findUsers({'role': 'CLIENT', 'active': 'true'}, '', function(users) { $scope.users.clients = users; }); - questionsService.findUsers({'role': 'SUPERVISOR', 'active': 'true'}, function(users) { + questionsService.findUsers({'role': 'SUPERVISOR', 'active': 'true'}, '', function(users) { $scope.users.supervisors = users; }); @@ -545,21 +545,19 @@ coselmarControllers.controller("QuestionCtrl", ['$scope', '$route', '$routeParam }); }; - $scope.saveQuestion = function(isValidForm){ + $scope.saveQuestion = function(){ if (angular.isDate($scope.question.deadline)) { $scope.question.deadline = $scope.question.deadline.getTime(); } // Call service to create a new user - if(isValidForm) { -// questionsService.saveQuestion($scope.question, function() { - $location.search(""); -// },function(error) { -// //TODO ymartel 20141118 : deal with error.status or statusText -// console.log("error occurs"); -// console.log(error.s); -// }); - } + questionsService.saveQuestion($scope.question, function() { + $location.search(""); + },function(error) { + //TODO ymartel 20141118 : deal with error.status or statusText + console.log("error occurs"); + console.log(error.s); + }); }; $scope.closeQuestion = function(){ diff --git a/coselmar-ui/src/main/webapp/views/questions/editquestion.html b/coselmar-ui/src/main/webapp/views/questions/editquestion.html index b8e5f70..f58aedb 100644 --- a/coselmar-ui/src/main/webapp/views/questions/editquestion.html +++ b/coselmar-ui/src/main/webapp/views/questions/editquestion.html @@ -1,8 +1,4 @@ -<div class=""> - - <form name="questionForm" class="form-horizontal" role="form"> - <!-- Line with Title --> <div class="form-group row" ng-class="{'has-error' : questionForm.title.$invalid && !questionForm.title.$pristine }"> <label class="col-md-2 control-label">Title *</label> @@ -251,6 +247,3 @@ </div> <!-- End Line with Related Document --> - - </form> -</div> \ No newline at end of file diff --git a/coselmar-ui/src/main/webapp/views/questions/newquestion.html b/coselmar-ui/src/main/webapp/views/questions/newquestion.html index 7518ede..37db08d 100644 --- a/coselmar-ui/src/main/webapp/views/questions/newquestion.html +++ b/coselmar-ui/src/main/webapp/views/questions/newquestion.html @@ -3,14 +3,18 @@ <h2>Add a question</h2> </div> - <div style="padding-bottom: 50px" ng-include="src='views/questions/editquestion.html'" - ng-if="currentUser.role == 'SUPERVISOR'"> + <div style="padding-bottom: 50px" ng-if="currentUser.role == 'SUPERVISOR'"> + + <form name="questionForm" class="form-horizontal" role="form"> + + <div ng-include="src='views/questions/editquestion.html'"></div> <div class="form-group" ng-if="questionForm.$valid && question.themes.length > 0"> <div style="padding-left: 200px"> <input type="submit" value="Validate" class="btn btn-primary" ng-click="saveQuestion(questionForm.$valid)"/> </div> </div> + </form> </div> <div style="padding-bottom: 50px" ng-if="currentUser.role != 'SUPERVISOR'"> diff --git a/coselmar-ui/src/main/webapp/views/questions/question.html b/coselmar-ui/src/main/webapp/views/questions/question.html index 28351c4..b0d5ab5 100644 --- a/coselmar-ui/src/main/webapp/views/questions/question.html +++ b/coselmar-ui/src/main/webapp/views/questions/question.html @@ -14,14 +14,16 @@ </div> <div style="padding-bottom: 50px" ng-if="editMode == true"> + <form name="questionForm" class="form-horizontal" role="form"> <div ng-include="src='views/questions/editquestion.html'"></div> - <div class="form-group"><a class="btn btn-action btn-success" ng-click="saveQuestion()"> + <div class="form-group" style="padding-left: 200px"><a class="btn btn-action btn-success" ng-click="saveQuestion()"> <span class="fa fa-check-square-o" aria-hidden="true"></span>Validate changes </a></div> + </form> </div> <div class="text-center" ng-if="question.closingDate"> - Closed on {{question.closingDate}}. + Closed on {{question.closingDate | date:'medium' }}. </div> <div class="text-center" ng-if="!question.closingDate && currentUser.role == 'SUPERVISOR' && editMode == false"> -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.