From 1ebdf5222ef446eb558a9a45cc1604cf1936dded Mon Sep 17 00:00:00 2001 From: bgarciaentornos Date: Wed, 31 Jan 2024 12:47:01 +0100 Subject: [PATCH] S2U-26 Gradebook: support for group instances Co-authored-by: jumarub Co-authored-by: JuanDavid102 --- .../assignment/api/AssignmentService.java | 6 +- .../api/persistence/AssignmentRepository.java | 4 +- .../api/src/resources/assignment.properties | 5 +- .../src/resources/assignment_ca.properties | 4 + .../src/resources/assignment_es.properties | 4 + .../src/resources/assignment_eu.properties | 3 +- .../impl/AssignmentEventObserver.java | 89 +- .../impl/AssignmentServiceImpl.java | 48 +- .../persistence/AssignmentRepositoryImpl.java | 9 +- .../impl/AssignmentServiceTest.java | 4 +- .../AssignmentEntityProvider.java | 4 +- .../assignment/tool/AssignmentAction.java | 795 ++++++--- .../assignment/tool/AssignmentToolUtils.java | 203 ++- .../tool/RangeAndGroupsDelegate.java | 21 +- .../src/webapp/WEB-INF/applicationContext.xml | 1 + ...ignments_instructor_new_edit_assignment.vm | 3 + .../instructor_new_edit/grading_section.vm | 75 +- .../org/sakaiproject/lti13/LTI13Servlet.java | 6 +- .../basiclti/util/SakaiBLTIUtil.java | 89 +- .../org/sakaiproject/lti13/LineItemUtil.java | 31 +- .../sakaiproject/portlets/IMSBLTIPortlet.java | 15 +- .../config/bundle/default.sakai.properties | 18 +- .../turnitin/TurnitinReviewServiceImpl.java | 26 +- .../section/sakai/facade/SakaiUtil.java | 13 +- .../sakaiproject/grading/api/Assignment.java | 3 + .../grading/api/GradingAuthz.java | 67 +- .../api/GradingPersistenceManager.java | 1 + .../grading/api/GradingService.java | 483 +---- .../grading/api}/MessageHelper.java | 16 +- .../grading/api/model/Gradebook.java | 5 +- .../GradebookAssignmentRepository.java | 1 + .../src/main/bundle/gradebookng.properties | 3 + .../src/main/bundle/gradebookng_ca.properties | 3 + .../src/main/bundle/gradebookng_es.properties | 3 + .../src/main/bundle/gradebookng_eu.properties | 3 + .../grading/impl/GradebookDefinition.java | 44 - .../grading/impl/GradingAuthzImpl.java | 282 +-- .../impl/GradingPersistenceManagerImpl.java | 4 + .../grading/impl/GradingServiceImpl.java | 1568 +++++++---------- .../grading/impl/VersionedExternalizable.java | 134 -- .../GradebookAssignmentRepositoryImpl.java | 11 + .../src/main/webapp/WEB-INF/components.xml | 1 + .../impl/test/GradingServiceTests.java | 182 +- .../business/GradebookNgBusinessService.java | 1033 +++-------- .../business/LetterGradeComparator.java | 64 - .../gradebookng/business/model/GbGroup.java | 1 - .../business/util/CourseGradeFormatter.java | 19 +- .../business/util/FormatHelper.java | 9 +- .../business/util/ImportGradesHelper.java | 65 +- .../framework/GradebookNgEntityProducer.java | 136 +- .../rest/GradebookNgEntityProvider.java | 63 +- .../actions/CourseGradeBreakdownAction.java | 4 +- .../tool/actions/DeleteAssignmentAction.java | 6 +- .../tool/actions/EditAssignmentAction.java | 6 +- .../tool/actions/EditCommentAction.java | 1 + .../actions/EditCourseGradeCommentAction.java | 9 +- .../tool/actions/ExcuseGradeAction.java | 12 +- .../tool/actions/GradeUpdateAction.java | 12 +- .../tool/actions/InjectableAction.java | 9 + .../tool/actions/MoveAssignmentAction.java | 45 +- .../actions/MoveAssignmentLeftAction.java | 64 - .../actions/MoveAssignmentRightAction.java | 64 - .../actions/OverrideCourseGradeAction.java | 6 +- .../actions/SetScoreForUngradedAction.java | 1 + .../ViewAssignmentStatisticsAction.java | 6 +- .../actions/ViewCourseGradeLogAction.java | 4 +- .../ViewCourseGradeStatisticsAction.java | 6 +- .../tool/actions/ViewGradeSummaryAction.java | 1 + .../tool/actions/ViewRubricGradeAction.java | 4 +- .../tool/actions/ViewRubricPreviewAction.java | 4 +- .../tool/chart/AssignmentGradeChart.java | 18 +- .../gradebookng/tool/chart/BaseChart.java | 8 + .../tool/chart/CourseGradeChart.java | 21 +- .../tool/component/GbGradeTable.html | 2 +- .../tool/model/GbGradeTableData.java | 52 +- .../tool/model/GbGradebookData.java | 3 + .../gradebookng/tool/pages/BasePage.java | 101 +- .../gradebookng/tool/pages/GradebookPage.java | 181 +- .../tool/pages/ImportExportPage.java | 10 +- .../tool/pages/PermissionsPage.java | 20 +- .../tool/pages/QuickEntryPage.java | 35 +- .../gradebookng/tool/pages/SettingsPage.java | 11 +- .../gradebookng/tool/pages/StudentPage.java | 14 +- .../tool/panels/AddOrEditGradeItemPanel.java | 20 +- .../AddOrEditGradeItemPanelContent.java | 16 +- .../panels/AssignmentStatisticsPanel.java | 8 +- .../gradebookng/tool/panels/BasePanel.java | 50 +- .../tool/panels/BulkEditItemsPanel.java | 15 +- .../panels/CourseGradeBreakdownPanel.java | 41 +- .../panels/CourseGradeOverrideLogPanel.java | 2 +- .../tool/panels/CourseGradeOverridePanel.java | 10 +- .../panels/CourseGradeStatisticsPanel.java | 20 +- .../tool/panels/DeleteItemPanel.java | 6 +- .../panels/EditCourseGradeCommentPanel.java | 4 +- .../tool/panels/EditGradeCommentPanel.java | 6 +- .../tool/panels/GradeSummaryTablePanel.java | 15 +- .../InstructorGradeSummaryGradesPanel.java | 18 +- .../tool/panels/RubricGradePanel.java | 4 +- .../tool/panels/RubricPreviewPanel.java | 2 +- .../panels/SettingsGradingSchemaPanel.java | 9 +- .../panels/SortGradeItemsByCategoryPanel.java | 5 +- .../SortGradeItemsByGradeItemPanel.java | 5 +- .../tool/panels/SortGradeItemsPanel.java | 16 +- .../StudentAssignmentStatisticsPanel.java | 1 + .../panels/StudentCompareGradesPanel.java | 19 +- .../StudentCourseGradeStatisticsPanel.java | 11 +- .../StudentGradeSummaryGradesPanel.java | 28 +- .../tool/panels/StudentGradeSummaryPanel.java | 10 +- .../tool/panels/UpdateUngradedItemsPanel.java | 16 +- .../tool/panels/ZeroUngradedItemsPanel.java | 5 +- .../importExport/CreateGradeItemStep.java | 13 +- .../tool/panels/importExport/ExportPanel.java | 28 +- .../GradeImportConfirmationStep.java | 34 +- .../importExport/GradeImportUploadStep.java | 17 +- .../GradeItemImportSelectionStep.java | 3 + .../business/util/TestImportGradesHelper.java | 26 +- .../src/webapp/WEB-INF/applicationContext.xml | 1 - .../WEB-INF/tools/sakai.gradebookng.xml | 2 + .../webapp/scripts/gradebook-gbgrade-table.js | 21 +- .../service/Assignment2Entity.java | 2 +- .../service/ScormEntity.java | 7 - .../webapp/WEB-INF/opt-applicationContext.xml | 1 - .../service/GradebookIfc.java | 113 +- .../service/LessonBuilderEntityProducer.java | 12 +- .../tool/beans/GradingBean.java | 50 +- .../tool/beans/SimplePageBean.java | 155 +- .../messagecenter/bundle/Messages.properties | 5 + .../bundle/Messages_ca.properties | 1 + .../bundle/Messages_es.properties | 5 + .../messageforums/DiscussionForumTool.java | 124 +- .../ui/MessageForumStatisticsBean.java | 167 +- .../discussionForum/message/dfMsgGrade.jsp | 46 +- .../statistics/dfStatisticsListByTopic.jsp | 73 +- .../entity/TopicEntityProviderImpl.java | 5 +- .../plus/impl/PlusServiceImpl.java | 2 +- .../sakaiproject/plus/ProviderServlet.java | 2 +- .../portal/charon/handlers/SiteHandler.java | 2 +- .../charon/site/PortalSiteHelperImpl.java | 26 +- .../rubrics/impl/RubricsServiceImpl.java | 3 +- .../ifc/assessment/AssessmentMetaDataIfc.java | 1 + .../AssessmentSettingsMessages_es.properties | 3 + .../bean/author/AssessmentSettingsBean.java | 270 +-- .../PublishedAssessmentSettingsBean.java | 123 +- .../bean/author/RestoreAssessmentsBean.java | 15 +- .../author/PublishAssessmentListener.java | 1 - .../author/SaveAssessmentSettings.java | 40 +- .../SaveAssessmentSettingsListener.java | 60 +- .../author/SavePublishedSettingsListener.java | 376 ++-- samigo/samigo-app/src/webapp/js/authoring.js | 28 +- .../src/webapp/jsf/author/authorSettings.jsp | 59 +- .../webapp/jsf/author/publishedSettings.jsp | 56 +- .../facade/AssessmentBaseFacade.java | 29 +- .../assessment/facade/GradebookFacade.java | 8 - .../facade/PublishedAssessmentFacade.java | 8 +- .../PublishedAssessmentFacadeQueries.java | 17 +- .../helper/ifc/GradebookHelper.java | 3 +- .../helper/ifc/GradebookServiceHelper.java | 24 +- .../integrated/GradebookHelperImpl.java | 13 +- .../GradebookServiceHelperImpl.java | 257 ++- .../assessment/services/GradingService.java | 16 +- .../PublishedAssessmentService.java | 153 +- samigo/samlite-impl/pom.xml | 3 +- .../impl/ScormApplicationServiceImpl.java | 6 +- .../pages/PackageConfigurationPage.java | 11 +- .../ui/console/pages/PackageRemovePage.java | 3 +- .../impl/DateManagerServiceImpl.java | 165 +- .../impl/SiteManageServiceImpl.java | 7 +- .../impl/job/SeedSitesAndUsersJob.java | 4 +- site-manage/site-manage-tool/tool/pom.xml | 4 + .../src/bundle/sitesetupgeneric.properties | 15 + .../src/bundle/sitesetupgeneric_ca.properties | 14 + .../src/bundle/sitesetupgeneric_es.properties | 14 + .../src/bundle/sitesetupgeneric_eu.properties | 14 + .../site/tool/GradebookGroupEnabler.java | 126 ++ .../sakaiproject/site/tool/SiteAction.java | 400 +++-- .../tool/src/webapp/chef_header.vm | 1 + .../chef_site-addRemoveFeatureConfirm.vm | 36 +- .../vm/sitesetup/chef_site-importSites.vm | 23 + .../sitesetup/chef_site-importSitesMigrate.vm | 22 + .../vm/sitesetup/chef_site-modifyENW.vm | 12 +- .../vm/sitesetup/chef_site-siteInfo-list.vm | 10 + .../webapp/vm/sitesetup/gradebook_group.vm | 75 + .../src/main/bundle/gb-selector.properties | 7 + .../src/main/bundle/gb-selector_es.properties | 7 + vuecomponents/docs/i18n.md | 2 + .../components-api/gb-selector-input-sync.js | 33 + .../src/components/multi-gradebook.vue | 183 ++ .../webapi/beans/GradebookItemRestBean.java | 15 + .../webapi/beans/GradebookRestBean.java | 18 + .../webapi/controllers/GradesController.java | 135 +- .../webapi/controllers/LessonsController.java | 2 +- .../src/SakaiSubmissionMessager.js | 31 +- .../sakaiproject/webservices/Assignments.java | 110 +- .../webservices/SakaiGradebook.java | 54 +- 194 files changed, 5985 insertions(+), 4865 deletions(-) rename gradebookng/{tool/src/java/org/sakaiproject/gradebookng/business/util => api/src/main/java/org/sakaiproject/grading/api}/MessageHelper.java (71%) delete mode 100644 gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradebookDefinition.java delete mode 100644 gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/VersionedExternalizable.java delete mode 100644 gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/LetterGradeComparator.java delete mode 100644 gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentLeftAction.java delete mode 100644 gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentRightAction.java create mode 100644 site-manage/site-manage-tool/tool/src/java/org/sakaiproject/site/tool/GradebookGroupEnabler.java create mode 100644 site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/gradebook_group.vm create mode 100644 vuecomponents/bundle/src/main/bundle/gb-selector.properties create mode 100644 vuecomponents/bundle/src/main/bundle/gb-selector_es.properties create mode 100644 vuecomponents/tool/src/main/frontend/src/components-api/gb-selector-input-sync.js create mode 100644 vuecomponents/tool/src/main/frontend/src/components/multi-gradebook.vue create mode 100644 webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookItemRestBean.java create mode 100644 webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookRestBean.java diff --git a/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java b/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java index 4624a3b14ff8..349b1f95de2a 100644 --- a/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java +++ b/assignment/api/src/java/org/sakaiproject/assignment/api/AssignmentService.java @@ -823,14 +823,14 @@ public String getDeepLinkWithPermissions(String context, String assignmentId, bo public List getAllAcceptableAttachments(AssignmentSubmission submission); /** - * Get an assignment that is linked with a gradebook item + * Get assignments that are linked with a gradebook item * @param context the context (site id) * @param linkId the link id of the gradebook item, usually the gradebook item name or id - * @return the matching assignment if found or empty if none + * @return the matching assignments if found or null if none * @throws IdUnusedException if the assignment doesn't exist * @throws PermissionException if the current user is not allowed to access the assignment */ - Optional getAssignmentForGradebookLink(String context, String linkId) throws IdUnusedException, PermissionException; + List getAssignmentsForGradebookLink(String context, String linkId) throws IdUnusedException, PermissionException; /** * Returns a list of users that belong to multiple groups, if the user is considered a "student" in the group diff --git a/assignment/api/src/java/org/sakaiproject/assignment/api/persistence/AssignmentRepository.java b/assignment/api/src/java/org/sakaiproject/assignment/api/persistence/AssignmentRepository.java index ab006ee103a1..d8b0a6e38c26 100644 --- a/assignment/api/src/java/org/sakaiproject/assignment/api/persistence/AssignmentRepository.java +++ b/assignment/api/src/java/org/sakaiproject/assignment/api/persistence/AssignmentRepository.java @@ -87,12 +87,12 @@ AssignmentSubmission newSubmission(String assignmentId, void resetAssignment(Assignment assignment); /** - * Find an assignment that is linked with to a gradebook item + * Find assignments that are linked with to a gradebook item * @param context the context the assignment is in * @param linkId the linked id or name of the gradebook item * @return the assignment id or empty if none is found */ - Optional findAssignmentIdForGradebookLink(String context, String linkId); + List findAssignmentsForGradebookLink(String context, String linkId); Collection findGroupsForAssignmentById(String assignmentId); diff --git a/assignment/api/src/resources/assignment.properties b/assignment/api/src/resources/assignment.properties index 4292acd2ef3d..89f986437b23 100644 --- a/assignment/api/src/resources/assignment.properties +++ b/assignment/api/src/resources/assignment.properties @@ -219,7 +219,6 @@ gen.resub = Re-submitted gen.retu = Return gen.backtolist = Back to list gen.reorder = Reorder -gen.review = Review gen.peerreview.subm4 = Peer Review Submitted gen.peerreview.todo = Peer Review ({0}) Due {1} gen.reviewer.who = Reviewer: {0} ({1}) @@ -674,6 +673,9 @@ range.allgroups = site group = Group groups = Groups +group.sitegradebook.items.error=Selected groups must have a gradebook item associated with them +group.sitegradebook.nopermission=Assignments for the entire site cannot be created when using group based gradebooks. +group.sitegradebook.categories.error=The selected categories must be associated with their corresponding group. group.editsite.nopermission = Cannot edit the group state due to site permissions. group.list.summary = Table contains list of groups. First will contain checkboxes, second will contain the group name, third the group description. Header links can be used to sort group.list.descr = Description @@ -1163,6 +1165,7 @@ settings.access.checkFailure=Check failed, no response from server. selected.group = Selected Group selected.groups = Selected Groups +selected.groups.without.gradebook = You have made a selection for a group that doesn't have a gradebook. submission.inline=Inline Submission grade.type.unknown=Unknown Grade Type diff --git a/assignment/api/src/resources/assignment_ca.properties b/assignment/api/src/resources/assignment_ca.properties index 4ac6d5f42ec8..8329f591e49d 100644 --- a/assignment/api/src/resources/assignment_ca.properties +++ b/assignment/api/src/resources/assignment_ca.properties @@ -647,6 +647,9 @@ range.allgroups=tot l\u2019espai group=Grup groups=Grups +group.sitegradebook.items.error=Els grups seleccionats han de tindre associat un ítem del llibre de qualificacions +group.sitegradebook.nopermission=No es poden crear tasques de lloc en tindre qualificacions de grup. +group.sitegradebook.categories.error=Les categories seleccionades han d'estar associades al seu grup corresponent. group.editsite.nopermission=No teniu els permisos corresponents en aquest espai per editar l\u2019estat del grup group.list.summary=La taula cont\u00e9 una llista de grups. La primera columna contindr\u00e0 caselles de selecci\u00f3; la segona, el nom del grup; la tercera, la descripci\u00f3 del grup. Els enlla\u00e7os de l\u2019encap\u00e7alament es poden utilitzar per ordenar group.list.descr=Descripci\u00f3 @@ -1135,6 +1138,7 @@ settings.access.checkFailure=La comprovaci\u00f3 ha fallat, no hi ha hagut respo selected.group=Grup seleccionat selected.groups=Grups seleccionats +selected.groups.without.gradebook = Heu seleccionat grups sense un llibre de qualificacions existent, verifiqueu-ne la configuraci\u00f3. submission.inline=Lliurament grade.type.unknown=Tipus de qualificaci\u00f3 desconegut diff --git a/assignment/api/src/resources/assignment_es.properties b/assignment/api/src/resources/assignment_es.properties index 1cc3c0968b64..bfd351777f45 100644 --- a/assignment/api/src/resources/assignment_es.properties +++ b/assignment/api/src/resources/assignment_es.properties @@ -673,6 +673,9 @@ range.allgroups=sitio group=Grupo groups=Grupos +group.sitegradebook.items.error=Los grupos seleccionados deben tener asociado un item del libro de calificaciones +group.sitegradebook.nopermission=No se pueden crear tareas de sitio al tener calificaciones de grupo. +group.sitegradebook.categories.error=Las categorías seleccionadas deben estar asociadas a su grupo correspondiente. group.editsite.nopermission=No se puede editar el estado del grupo debido a los permisos del sitio. group.list.summary=Lista de grupos. La primera columna contiene casillas de selecci\u00f3n, la segunda el nombre del grupo y la tercera su descripci\u00f3n. Los enlaces de la cabecera de la tabla permiten ordenar sus entradas. group.list.descr=Descripci\u00f3n @@ -1162,6 +1165,7 @@ settings.access.checkFailure=Comprobaci\u00f3n fallida, no hay respuesta del ser selected.group=Grupo seleccionado selected.groups=Grupo(s) seleccionado(s) +selected.groups.without.gradebook = Has seleccionado grupos sin gradebook existente, por favor revisa la configuracin. submission.inline=Respuesta enviada grade.type.unknown=Tipo de nota desconocido diff --git a/assignment/api/src/resources/assignment_eu.properties b/assignment/api/src/resources/assignment_eu.properties index 33b9ff89faf0..ba5bc68f3562 100644 --- a/assignment/api/src/resources/assignment_eu.properties +++ b/assignment/api/src/resources/assignment_eu.properties @@ -1137,7 +1137,8 @@ settings.access.checkError=Ikasle hauek zenbait talde hautatutako partaide dira settings.access.checkFailure=Egiaztapenak huts egin du\: zerbitzariak ez du erantzun. selected.group=Talde hautatua -selected.groups=Talde hautatuak +selected.groups=Talde hautatuak +selected.groups.without.gradebook = Lehendik dagoen kalifikazio-libururik gabeko taldeak hautatu dituzu, egiaztatu zure ezarpenak. submission.inline=Inline bidalketa grade.type.unknown=Ez dago horrelako kalifikazio motarik diff --git a/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentEventObserver.java b/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentEventObserver.java index edbde8fd8e27..9a34cf05b2d5 100644 --- a/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentEventObserver.java +++ b/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentEventObserver.java @@ -18,6 +18,7 @@ import java.util.Observable; import java.util.Observer; import java.util.Optional; +import java.util.List; import java.util.Set; import java.util.stream.IntStream; @@ -65,69 +66,69 @@ public void update(Observable o, Object arg) { String[] parts = StringUtils.split(event.getResource(), '/'); if (parts.length >= 5) { final String source = parts[0]; - final String gradebookId = parts[1]; + final String gradebookUid = parts[1]; final String itemId = parts[2]; final String studentId = parts[3]; final String score = parts[4]; - log.debug("Updating score for user {} for item {} with score {} in gradebook {} by {}", studentId, itemId, score, gradebookId, source); + log.debug("Updating score for user {} for item {} with score {} in gradebook {} by {}", studentId, itemId, score, gradebookUid, source); + if ("gradebookng".equals(source)) { - Optional assignment = Optional.empty(); + List assignments = null; Optional submission = Optional.empty(); // Assignments stores the gradebook item name and not the id :(, so we need to look it up try { - org.sakaiproject.grading.api.Assignment gradebookAssignment = gradingService.getAssignmentByNameOrId(event.getContext(), itemId); - assignment = assignmentService.getAssignmentForGradebookLink(event.getContext(), gradebookAssignment.getName()); - if (assignment.isPresent()) { - final Assignment a = assignment.get(); - final User user = userDirectoryService.getUser(studentId); - submission = Optional.ofNullable(assignmentService.getSubmission(a.getId(), user.getId())); - submission = Optional.ofNullable(submission.orElseGet(() -> { - try { - return assignmentService.addSubmission(a.getId(), assignmentService.getSubmitterIdForAssignment(a, user.getId())); - } catch (PermissionException e) { - log.warn("Can't access submission for assignment {} and user {}, {}", a.getId(), user.getId(), e.getMessage()); - } - return null; - })); + org.sakaiproject.grading.api.Assignment gradebookAssignment = gradingService.getAssignmentByNameOrId(gradebookUid, event.getContext(), itemId); + assignments = assignmentService.getAssignmentsForGradebookLink(event.getContext(), gradebookAssignment.getName()); + if (assignments != null) { + for (Assignment a : assignments) { + final User user = userDirectoryService.getUser(studentId); + submission = Optional.ofNullable(assignmentService.getSubmission(a.getId(), user.getId())); + submission = Optional.ofNullable(submission.orElseGet(() -> { + try { + return assignmentService.addSubmission(a.getId(), assignmentService.getSubmitterIdForAssignment(a, user.getId())); + } catch (PermissionException e) { + log.warn("Can't access submission for assignment {} and user {}, {}", a.getId(), user.getId(), e.getMessage()); + } + return null; + })); - if (submission.isPresent()) { - AssignmentSubmission s = submission.get(); - final String grade; - if (Assignment.GradeType.SCORE_GRADE_TYPE.equals(a.getTypeOfGrade())) { - int dec = (int) Math.log10(a.getScaleFactor()); - StringBuilder scaledScore = new StringBuilder(score); - IntStream.range(0, dec).forEach(i -> scaledScore.append("0")); - grade = scaledScore.toString(); - } else { - grade = score; - } - if (a.getIsGroup()) { - // grades will show up as overrides for group assignments - Set submitters = s.getSubmitters(); - submitters.stream().filter(u -> studentId.equals(u.getSubmitter())).findAny().ifPresent(u -> u.setGrade(grade)); + if (submission.isPresent()) { + AssignmentSubmission s = submission.get(); + final String grade; + if (Assignment.GradeType.SCORE_GRADE_TYPE.equals(a.getTypeOfGrade())) { + int dec = (int) Math.log10(a.getScaleFactor()); + StringBuilder scaledScore = new StringBuilder(score); + IntStream.range(0, dec).forEach(i -> scaledScore.append("0")); + grade = scaledScore.toString(); + } else { + grade = score; + } + if (a.getIsGroup()) { + // grades will show up as overrides for group assignments + Set submitters = s.getSubmitters(); + submitters.stream().filter(u -> studentId.equals(u.getSubmitter())).findAny().ifPresent(u -> u.setGrade(grade)); + } else { + s.setGrade(grade); + } + s.setGraded(true); + s.setGradedBy(event.getUserId()); + assignmentService.updateSubmission(s); + log.debug("Updated score for user {} for submission {} with score {}", studentId, s.getId(), score); } else { - s.setGrade(grade); + log.warn("Submission not found for assignment {} and student {}, ", itemId, studentId); } - s.setGraded(true); - s.setGradedBy(event.getUserId()); - assignmentService.updateSubmission(s); - log.debug("Updated score for user {} for submission {} with score {}", studentId, s.getId(), score); - } else { - log.warn("Submission not found for assignment {} and student {}, ", itemId, studentId); } } else { log.debug("No matching assignment found with gradebook item id, {}", itemId); } } catch (IdUnusedException | PermissionException e) { - if (!assignment.isPresent()) { - log.warn("Can't retrieve assignment for gradebook item id {}, {}", itemId, e.getMessage()); - } else if (!submission.isPresent()) { - log.warn("Can't retrieve submission for user {} for assignment {}, {}", studentId, assignment.get().getId(), e.getMessage()); + if (!submission.isPresent()) { + log.warn("Can't retrieve submission for user {} for assignment {}, {}", studentId, itemId, e.getMessage()); } else { log.warn("Can't update submission for user {}, {}", studentId, e.getMessage()); } } catch (AssessmentNotFoundException anfe) { - log.warn("Can't retrieve gradebook assignment for gradebook {} and item {}, {}", gradebookId, itemId, anfe.getMessage()); + log.debug("Can't retrieve gradebook assignment for gradebook {} and item {}, {}", gradebookUid, itemId, anfe.getMessage()); } catch (UserNotDefinedException e) { log.warn("Can't retrieve user {}, {}", studentId, e.getMessage()); } diff --git a/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java b/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java index 192b02cb78b6..abd4ebd10d25 100644 --- a/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java +++ b/assignment/impl/src/java/org/sakaiproject/assignment/impl/AssignmentServiceImpl.java @@ -3303,14 +3303,11 @@ private void removeAssociatedTaggingItem(Assignment assignment) { } } + // for regular task deletion this has no effect as it has already been done on doDelete_assignment, it only works when it comes from import content + replace private void removeAssociatedGradebookItem(Assignment assignment) { - - String context = assignment.getContext(); String associatedGradebookAssignment = assignment.getProperties().get(AssignmentConstants.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); if (StringUtils.isNotBlank(associatedGradebookAssignment)) { - if (gradingService.isExternalAssignmentDefined(context, associatedGradebookAssignment)) { - gradingService.removeExternalAssignment(context, associatedGradebookAssignment); - } + gradingService.removeExternalAssignment(null, associatedGradebookAssignment, getToolId()); } } @@ -4378,13 +4375,13 @@ public Map transferCopyEntities(String fromContext, String toCon } else { // see if the old assignment's associated gradebook item is an internal gradebook entry or externally defined boolean isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(oAssignment.getContext(), associatedGradebookAssignment); + String siteId = nAssignment.getContext(); + String gradebookUid = siteId; if (isExternalAssignmentDefined) { if (!nAssignment.getDraft()) { - String gbUid = nAssignment.getContext(); // This assignment has been published, make sure the associated gb item is available org.sakaiproject.grading.api.Assignment gbAssignment - = gradingService.getAssignmentByNameOrId( - nAssignment.getContext(), associatedGradebookAssignment); + = gradingService.getAssignmentByNameOrId(gradebookUid, siteId, associatedGradebookAssignment); if (gbAssignment == null) { // The associated gb item hasn't been created here yet. @@ -4395,11 +4392,11 @@ public Map transferCopyEntities(String fromContext, String toCon = createCategoryForGbAssignmentIfNecessary( gbAssignment, oAssignment.getContext(), nAssignment.getContext()); - gradingService.addExternalAssessment(nAssignment.getContext() + gradingService.addExternalAssessment(gradebookUid, siteId , nAssignmentRef, null, nAssignment.getTitle() , nAssignment.getMaxGradePoint() / (double) nAssignment.getScaleFactor() , Date.from(nAssignment.getDueDate()), this.getToolId() - , null, false, categoryId.isPresent() ? categoryId.get() : null); + , null, false, categoryId.isPresent() ? categoryId.get() : null, null); nProperties.put(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT, nAssignmentRef); } @@ -4415,13 +4412,13 @@ public Map transferCopyEntities(String fromContext, String toCon try { org.sakaiproject.grading.api.Assignment gbAssignment = gradingService.getAssignmentByNameOrId( - nAssignment.getContext(), associatedGradebookAssignment); + gradebookUid, siteId, associatedGradebookAssignment); if (gbAssignment == null) { if (!nAssignment.getDraft()) { // The target gb item doesn't exist and we're in publish mode, so copy it over. gbAssignment = gradingService.getAssignmentByNameOrId( - oAssignment.getContext(), associatedGradebookAssignment); + gradebookUid, siteId, associatedGradebookAssignment); gbAssignment.setId(null); Optional categoryId = createCategoryForGbAssignmentIfNecessary( @@ -4431,7 +4428,7 @@ public Map transferCopyEntities(String fromContext, String toCon gbAssignment.setCategoryId(categoryId.get()); } - gradingService.addAssignment(nAssignment.getContext(), gbAssignment); + gradingService.addAssignment(gradebookUid, siteId, gbAssignment); nProperties.put(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT, gbAssignment.getId().toString()); } else { nProperties.put(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK, GRADEBOOK_INTEGRATION_NO); @@ -5013,10 +5010,9 @@ private Optional createCategoryForGbAssignmentIfNecessary( , String toGradebookId) { String categoryName = gbAssignment.getCategoryName(); - if (!StringUtils.isBlank(categoryName)) { List toCategoryDefinitions - = gradingService.getCategoryDefinitions(toGradebookId); + = gradingService.getCategoryDefinitions(toGradebookId, toGradebookId); if (toCategoryDefinitions == null) { toCategoryDefinitions = new ArrayList<>(); } @@ -5024,7 +5020,7 @@ private Optional createCategoryForGbAssignmentIfNecessary( if (!toCategoryDefinitions.stream().anyMatch(cd -> cd.getName().equals(categoryName))) { // The category doesn't exist yet CategoryDefinition fromCategoryDefinition - = gradingService.getCategoryDefinitions(fromGradebookId) + = gradingService.getCategoryDefinitions(fromGradebookId, fromGradebookId) .stream() .filter(cd -> cd.getName().equals(categoryName)) .findAny().get(); @@ -5037,19 +5033,18 @@ private Optional createCategoryForGbAssignmentIfNecessary( toCategoryDefinition.setDropHighest(fromCategoryDefinition.getDropHighest()); toCategoryDefinition.setDropLowest(fromCategoryDefinition.getDropLowest()); toCategoryDefinition.setKeepHighest(fromCategoryDefinition.getKeepHighest()); - - GradebookInformation toGbInformation = gradingService.getGradebookInformation(toGradebookId); - GradebookInformation fromGbInformation = gradingService.getGradebookInformation(fromGradebookId); + GradebookInformation toGbInformation = gradingService.getGradebookInformation(toGradebookId, toGradebookId); + GradebookInformation fromGbInformation = gradingService.getGradebookInformation(fromGradebookId, fromGradebookId); toGbInformation.setCategoryType(fromGbInformation.getCategoryType()); List categories = toGbInformation.getCategories(); categories.add(toCategoryDefinition); - gradingService.updateGradebookSettings(toGradebookId, toGbInformation); + gradingService.updateGradebookSettings(toGradebookId, toGradebookId, toGbInformation); } // A new category may have been added in the previous block. Pull them again, just to be sure. This will // ensure that any upstream caching is refreshed, too. Optional optional - = gradingService.getCategoryDefinitions(toGradebookId) + = gradingService.getCategoryDefinitions(toGradebookId, toGradebookId) .stream() .filter(cd -> cd.getName().equals(categoryName)).findAny(); if (optional.isPresent()) { @@ -5064,16 +5059,11 @@ private Optional createCategoryForGbAssignmentIfNecessary( } @Override - public Optional getAssignmentForGradebookLink(String context, String linkId) throws IdUnusedException, PermissionException { + public List getAssignmentsForGradebookLink(String context, String linkId) throws IdUnusedException, PermissionException { if (StringUtils.isNoneBlank(context, linkId)) { - Optional assignmentId = assignmentRepository.findAssignmentIdForGradebookLink(context, linkId); - if (assignmentId.isPresent()) { - return Optional.of(getAssignment(assignmentId.get())); - } else { - log.debug("No assignment id could be found for context {} and link {}", context, linkId); - } + return assignmentRepository.findAssignmentsForGradebookLink(context, linkId); } - return Optional.empty(); + return null; } @Override diff --git a/assignment/impl/src/java/org/sakaiproject/assignment/impl/persistence/AssignmentRepositoryImpl.java b/assignment/impl/src/java/org/sakaiproject/assignment/impl/persistence/AssignmentRepositoryImpl.java index acef53a54d6d..af754d36ac9a 100644 --- a/assignment/impl/src/java/org/sakaiproject/assignment/impl/persistence/AssignmentRepositoryImpl.java +++ b/assignment/impl/src/java/org/sakaiproject/assignment/impl/persistence/AssignmentRepositoryImpl.java @@ -305,15 +305,14 @@ public void resetAssignment(Assignment assignment) { } @Override - public Optional findAssignmentIdForGradebookLink(String context, String linkId) { - Object result = startCriteriaQuery() + public List findAssignmentsForGradebookLink(String context, String linkId) { + List result = startCriteriaQuery() .createAlias("properties", "p") .add(Restrictions.eq("context", context)) .add(Restrictions.eq("p." + CollectionPropertyNames.COLLECTION_INDICES, AssignmentConstants.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT)) .add(Restrictions.eq("p." + CollectionPropertyNames.COLLECTION_ELEMENTS, linkId)) - .setProjection(Projections.property("id")) - .uniqueResult(); - return result == null ? Optional.empty() : Optional.of(String.valueOf(result)); + .list(); + return result; } @Override diff --git a/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java b/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java index 0746fe164fad..272fe971b9a3 100644 --- a/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java +++ b/assignment/impl/src/test/org/sakaiproject/assignment/impl/AssignmentServiceTest.java @@ -1336,7 +1336,7 @@ public void countSubmissions() { } @Test - public void gradeUpdateFromAssignmentEventObeserver() { + public void gradeUpdateFromAssignmentEventObserver() { char ds = DecimalFormatSymbols.getInstance(Locale.ENGLISH).getDecimalSeparator(); when(formattedText.getDecimalSeparator()).thenReturn(Character.toString(ds)); configureScale(100, Locale.ENGLISH); @@ -1360,7 +1360,7 @@ public void gradeUpdateFromAssignmentEventObeserver() { org.sakaiproject.grading.api.Assignment gradebookAssignment = mock(org.sakaiproject.grading.api.Assignment.class); when(gradebookAssignment.getName()).thenReturn(itemId.toString()); - when(gradingService.getAssignmentByNameOrId(context, itemId.toString())).thenReturn(gradebookAssignment); + when(gradingService.getAssignmentByNameOrId(gradebookId, context, itemId.toString())).thenReturn(gradebookAssignment); User mockUser = mock(User.class); when(mockUser.getId()).thenReturn(submitterId); when(userDirectoryService.getUser(submitterId)).thenReturn(mockUser); diff --git a/assignment/tool/src/java/org/sakaiproject/assignment/entityproviders/AssignmentEntityProvider.java b/assignment/tool/src/java/org/sakaiproject/assignment/entityproviders/AssignmentEntityProvider.java index 9415ce0b13b6..5dd30d42db75 100644 --- a/assignment/tool/src/java/org/sakaiproject/assignment/entityproviders/AssignmentEntityProvider.java +++ b/assignment/tool/src/java/org/sakaiproject/assignment/entityproviders/AssignmentEntityProvider.java @@ -1197,7 +1197,6 @@ public ActionReturn getGrade(Map params) { @EntityCustomAction(action = "setGrade", viewKey = EntityView.VIEW_NEW) public ActionReturn setGrade(Map params) { - String userId = getCheckedCurrentUser(); String courseId = (String) params.get("courseId"); @@ -1922,11 +1921,10 @@ public SimpleAssignment(Assignment a, boolean hydrate) { } this.anonymousGrading = assignmentService.assignmentUsesAnonymousGrading(a); - String gradebookAssignmentProp = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); if (StringUtils.isNotBlank(gradebookAssignmentProp)) { // try to get internal gradebook assignment first - org.sakaiproject.grading.api.Assignment gAssignment = gradingService.getAssignment(a.getContext(), gradebookAssignmentProp); + org.sakaiproject.grading.api.Assignment gAssignment = gradingService.getAssignment(a.getContext(), a.getContext(), gradebookAssignmentProp); if (gAssignment != null) { // linked Gradebook item is internal this.gradebookItemId = gAssignment.getId(); diff --git a/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentAction.java b/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentAction.java index 6dfe1ec3f73e..488bb4a8edc0 100644 --- a/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentAction.java +++ b/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentAction.java @@ -21,6 +21,7 @@ import static org.sakaiproject.assignment.api.AssignmentConstants.ALLOW_RESUBMIT_CLOSE_MONTH; import static org.sakaiproject.assignment.api.AssignmentConstants.ALLOW_RESUBMIT_CLOSE_YEAR; import static org.sakaiproject.assignment.api.AssignmentConstants.ALLOW_EXTENSION_CLOSE_MONTH; +import static org.sakaiproject.assignment.api.AssignmentConstants.ALL; import static org.sakaiproject.assignment.api.AssignmentConstants.ALLOW_EXTENSION_CLOSE_DAY; import static org.sakaiproject.assignment.api.AssignmentConstants.ALLOW_EXTENSION_CLOSE_YEAR; import static org.sakaiproject.assignment.api.AssignmentConstants.ALLOW_EXTENSION_CLOSE_HOUR; @@ -36,11 +37,37 @@ import static org.sakaiproject.assignment.api.AssignmentConstants.GRADE_SUBMISSION_GRADE; import static org.sakaiproject.assignment.api.AssignmentConstants.GRADE_SUBMISSION_SUBMISSION_ID; import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_ADD_TO_GRADEBOOK; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_ALLOW_STUDENT_VIEW; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_DUE_DATE_SCHEDULED; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_OPEN_DATE_ANNOUNCED; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INSTITUTION; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_INTERNET; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_PUB; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_CHECK_TURNITIN; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_BIBLIOGRAPHIC; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_QUOTED; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_SELF_PLAG; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_SMALL_MATCHES; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_TYPE; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_EXCLUDE_VALUE; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_DUE; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_IMMEDIATELY; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_IMMEDIATELY_AND_DUE; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_REPORT_RADIO; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_STORE_INST_INDEX; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_STUDENT_PREVIEW; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_INSITUTION; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_NONE; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_RADIO; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_REVIEW_SERVICE_SUBMIT_STANDARD; import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_TAG_CREATOR; import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_TAG_GROUPS; +import static org.sakaiproject.assignment.api.AssignmentConstants.NEW_ASSIGNMENT_USE_REVIEW_SERVICE; import static org.sakaiproject.assignment.api.AssignmentConstants.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT; import static org.sakaiproject.assignment.api.AssignmentConstants.SHOW_TAGS_STUDENT; import static org.sakaiproject.assignment.api.AssignmentConstants.STATE_CONTEXT_STRING; +import static org.sakaiproject.assignment.api.AssignmentConstants.SUBMISSION_REVIEW_CHECK_SERVICE_EULA_AGREEMENT; +import static org.sakaiproject.assignment.api.AssignmentConstants.SUBMISSION_REVIEW_SERVICE_EULA_AGREEMENT; import static org.sakaiproject.assignment.api.AssignmentConstants.UNGRADED_GRADE_STRING; import static org.sakaiproject.assignment.api.AssignmentConstants.UNGRADED_GRADE_TYPE_STRING; import static org.sakaiproject.assignment.api.AssignmentServiceConstants.NEW_ASSIGNMENT_CHECK_ANONYMOUS_GRADING; @@ -154,16 +181,20 @@ import org.sakaiproject.assignment.api.model.PeerAssessmentAttachment; import org.sakaiproject.assignment.api.model.PeerAssessmentItem; import org.sakaiproject.assignment.api.reminder.AssignmentDueReminderService; +import org.sakaiproject.assignment.api.sort.AssignmentComparator; import org.sakaiproject.assignment.api.taggable.AssignmentActivityProducer; import org.sakaiproject.assignment.taggable.tool.DecoratedTaggingProvider; import org.sakaiproject.assignment.taggable.tool.DecoratedTaggingProvider.Pager; import org.sakaiproject.assignment.taggable.tool.DecoratedTaggingProvider.Sort; +import org.sakaiproject.assignment.tool.AssignmentAction.SubmitterSubmission; +import org.sakaiproject.assignment.tool.AssignmentAction.UploadGradeWrapper; import org.sakaiproject.authz.api.AuthzGroup; import org.sakaiproject.authz.api.AuthzGroupService; import org.sakaiproject.authz.api.GroupNotDefinedException; import org.sakaiproject.authz.api.Member; import org.sakaiproject.authz.api.Role; import org.sakaiproject.authz.api.SecurityAdvisor; +import org.sakaiproject.authz.api.SecurityAdvisor.SecurityAdvice; import org.sakaiproject.authz.api.SecurityService; import org.tsugi.basiclti.BasicLTIUtil; import org.tsugi.lti13.LTICustomVars; @@ -212,8 +243,13 @@ import org.sakaiproject.exception.PermissionException; import org.sakaiproject.exception.SakaiException; import org.sakaiproject.exception.ServerOverloadException; +import org.sakaiproject.grading.api.AssignmentHasIllegalPointsException; +import org.sakaiproject.grading.api.AssessmentNotFoundException; import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.SortType; +import org.sakaiproject.grading.api.model.Gradebook; +import org.sakaiproject.grading.api.model.GradebookAssignment; import org.sakaiproject.javax.PagingPosition; import org.sakaiproject.message.api.MessageHeader; import org.sakaiproject.rubrics.api.beans.AssociationTransferBean; @@ -222,8 +258,6 @@ import org.sakaiproject.scoringservice.api.ScoringAgent; import org.sakaiproject.scoringservice.api.ScoringComponent; import org.sakaiproject.scoringservice.api.ScoringService; -import org.sakaiproject.grading.api.AssessmentNotFoundException; -import org.sakaiproject.grading.api.AssignmentHasIllegalPointsException; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; @@ -1084,6 +1118,7 @@ public class AssignmentAction extends PagedResourceActionII { private static final String INVOKE_BY_PORTAL = "portal"; private static final String SUBMISSIONS_SEARCH_ONLY = "submissions_search_only"; private static final String TAG_SELECTOR = "tag_selector"; + private static final String GB_SELECTOR = "gb_selector"; /*************** search related *******************/ private static final String STATE_SEARCH = "state_search"; private static final String FORM_SEARCH = "form_search"; @@ -1241,7 +1276,7 @@ public AssignmentAction() { userTimeService = ComponentManager.get(UserTimeService.class); ltiService = ComponentManager.get(LTIService.class); tagService = ComponentManager.get(TagService.class); - rangeAndGroups = new RangeAndGroupsDelegate(assignmentService, rb, siteService, securityService, formattedText); + rangeAndGroups = new RangeAndGroupsDelegate(assignmentService, rb, siteService, securityService, formattedText, gradingService); } public void init(ServletConfig config) throws ServletException { @@ -2320,18 +2355,18 @@ private String build_student_view_submission_confirmation_context(VelocityPortle Site currentSite = siteService.getSite(siteId); // Assignments Tool Configuration ToolConfiguration toolConfig = currentSite.getToolForCommonId(AssignmentConstants.TOOL_ID); - + // Get visibility value of assignments tool String isAssignmentsVisible = toolConfig.getConfig().getProperty(ToolManager.PORTAL_VISIBLE); boolean isVisible = StringUtils.isBlank(isAssignmentsVisible) || StringUtils.equalsIgnoreCase(isAssignmentsVisible, Boolean.TRUE.toString()); - + // Checks if the assignments tool is visible from the LHS Menu. context.put("isAssignmentsToolVisible", isVisible); - + } catch(IdUnusedException e) { log.error(e.getMessage(), e); } - + state.removeAttribute(STATE_SUBMITTER); String template = (String) getContext(data).get("template"); return template + TEMPLATE_STUDENT_VIEW_SUBMISSION_CONFIRMATION; @@ -3209,7 +3244,6 @@ protected String build_instructor_new_edit_assignment_context(VelocityPortlet po protected void setAssignmentFormContext(SessionState state, Context context) { // put the names and values into vm file - context.put("name_UsePeerAssessment", NEW_ASSIGNMENT_USE_PEER_ASSESSMENT); context.put("name_PeerAssessmentAnonEval", NEW_ASSIGNMENT_PEER_ASSESSMENT_ANON_EVAL); context.put("name_PeerAssessmentStudentViewReviews", NEW_ASSIGNMENT_PEER_ASSESSMENT_STUDENT_VIEW_REVIEWS); @@ -3471,7 +3505,7 @@ protected void setAssignmentFormContext(SessionState state, Context context) { String gradebookUid = toolManager.getCurrentPlacement().getContext(); // how many gradebook assignment have been integrated with Assignment tool already - currentAssignmentGradebookIntegrationIntoContext(context, state, gradebookUid, a != null ? a.getTitle() : null); + currentAssignmentGradebookIntegrationIntoContext(context, state, a); if (StringUtils.isBlank((String) state.getAttribute(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK))) { state.setAttribute(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK, GRADEBOOK_INTEGRATION_NO); @@ -3481,6 +3515,12 @@ protected void setAssignmentFormContext(SessionState state, Context context) { context.put("name_Addtogradebook", NEW_ASSIGNMENT_ADD_TO_GRADEBOOK); context.put("name_AssociateGradebookAssignment", PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + String siteId = (String) state.getAttribute(STATE_CONTEXT_STRING); + + if (gradingService.isGradebookGroupEnabled(siteId)) { + context.put("gb_selector", GB_SELECTOR); + } + context.put("gradebookChoice", state.getAttribute(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK)); if (state.getAttribute(EDIT_ASSIGNMENT_ID) == null) { // This is a new assignment. Pick add new item to gradebook radio option. @@ -3490,6 +3530,7 @@ protected void setAssignmentFormContext(SessionState state, Context context) { context.put("gradebookChoice_add", GRADEBOOK_INTEGRATION_ADD); context.put("gradebookChoice_associate", GRADEBOOK_INTEGRATION_ASSOCIATE); String associateGradebookAssignment = (String) state.getAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + if (StringUtils.isNotBlank(associateGradebookAssignment)) { context.put("associateGradebookAssignment", associateGradebookAssignment); if (a != null) { @@ -3508,7 +3549,7 @@ protected void setAssignmentFormContext(SessionState state, Context context) { } else { // check internally maintained by gradebook try { - if (gradingService.getAssignmentByNameOrId(gradebookUid, associateGradebookAssignment) != null) { + if (gradingService.getAssignmentByNameOrId(gradebookUid, gradebookUid, associateGradebookAssignment) != null) { valid = true; } } catch (AssessmentNotFoundException anfe) { @@ -3682,94 +3723,159 @@ private String getContentReviewAcceptedFileTypesMessage() { * @param gradebookUid * @param aTitle */ - private void currentAssignmentGradebookIntegrationIntoContext(Context context, SessionState state, String gradebookUid, String aTitle) { + private void currentAssignmentGradebookIntegrationIntoContext(Context context, SessionState state, Assignment assignment) { String contextString = (String) state.getAttribute(STATE_CONTEXT_STRING); - // get all assignment - HashMap gAssignmentIdTitles = new HashMap<>(); - HashMap gradebookAssignmentsSelectedDisabled = new HashMap<>(); - HashMap gradebookAssignmentsLabel = new HashMap<>(); + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(contextString); + context.put("isGradebookGroupEnabled", isGradebookGroupEnabled); - for (Assignment a : assignmentService.getAssignmentsForContext(contextString)) { - String gradebookItem = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); - if (StringUtils.isNotBlank(gradebookItem)) { - String associatedAssignmentTitles = ""; - if (gAssignmentIdTitles.containsKey(gradebookItem)) { - // get the current associated assignment titles first - associatedAssignmentTitles = gAssignmentIdTitles.get(gradebookItem) + ", "; - } + List gradebookList = gradingService.getGradebookGroupInstances(contextString); - // append the current assignment title - associatedAssignmentTitles += a.getTitle(); + for (Gradebook gb : gradebookList) { + List gradebookAssignments = gradingService.getAssignments(gb.getUid(), contextString, SortType.SORT_BY_NONE); - // put the current associated assignment titles back - gAssignmentIdTitles.put(gradebookItem, associatedAssignmentTitles); + if (gradebookAssignments != null && gradebookAssignments.size() > 0) { + context.put("existAnyItemGradebook", true); + break; } } - // get all assignments in Gradebook - List gradebookAssignments = gradingService.getAssignments(gradebookUid); + // Determine if we're hiding the option to link to existing gradebook items + context.put("allowLinkToExistingGradebookItem", + serverConfigurationService.getBoolean(AssignmentConstants.SAK_PROP_ALLOW_LINK_TO_EXISTING_GB_ITEM, + AssignmentConstants.SAK_PROP_ALLOW_LINK_TO_EXISTING_GB_ITEM_DFLT)); - // filtering out those from Samigo - for (Iterator i = gradebookAssignments.iterator(); i.hasNext(); ) { - org.sakaiproject.grading.api.Assignment gAssignment = (org.sakaiproject.grading.api.Assignment) i.next(); - if (!gAssignment.getExternallyMaintained() || gAssignment.getExternallyMaintained() && gAssignment.getExternalAppName().equals(assignmentService.getToolId())) { + if (isGradebookGroupEnabled) { + String gbItems = null; - // gradebook item has been associated or not - String gaId = gAssignment.getExternallyMaintained() ? gAssignment.getExternalId() : gAssignment.getId().toString(); - String status = ""; - if (gAssignmentIdTitles.containsKey(gaId)) { - String assignmentTitle = gAssignmentIdTitles.get(gaId); - if (aTitle != null && aTitle.equals(assignmentTitle)) { - // this gradebook item is associated with current assignment, make it selected - status = "selected"; + if (assignment != null) { + gbItems = assignment.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + } else { + Object associateGradebook = state.getAttribute(GB_SELECTOR); + gbItems = associateGradebook != null ? associateGradebook.toString() : null; + } + + if (gbItems != null && !gbItems.isBlank()) { + List itemList = Arrays.asList(gbItems.split(",")); + + String selectedGradebook = ""; + + for (String item : itemList) { + List gradebookUids = gradingService.getGradebookUidByExternalId(item); + + boolean isExternalAssignmentDefined = false; + + for (String gradebookUid : gradebookUids) { + isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, item); + + if (isExternalAssignmentDefined) { + org.sakaiproject.grading.api.Assignment a = gradingService.getExternalAssignment(gradebookUid, item); + + selectedGradebook = assignmentToolUtils.fillSelectedGradebook(contextString, a.getId(), selectedGradebook); + } } - } - // check with the state variable - if (StringUtils.equals((String) state.getAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT), gaId)) { - status = "selected"; + if (!isExternalAssignmentDefined) { + Long itemId = Long.parseLong(item); + + selectedGradebook = assignmentToolUtils.fillSelectedGradebook(contextString, itemId, selectedGradebook); + } } - gradebookAssignmentsSelectedDisabled.put(formattedText.escapeHtml(gaId), status); + context.put("selectedGradebook", selectedGradebook); + } else { + context.put("selectedCategories", state.getAttribute(NEW_ASSIGNMENT_CATEGORY)); + } + } else { + String aTitle = assignment != null ? assignment.getTitle() : null; + + HashMap gAssignmentIdTitles = new HashMap<>(); - // gradebook assignment label - String label = gAssignment.getName(); - if (gAssignmentIdTitles.containsKey(gaId)) { - label += " ( " + rb.getFormattedMessage("usedGradebookAssignment", new Object[]{gAssignmentIdTitles.get(gaId)}) + " )"; + HashMap gradebookAssignmentsSelectedDisabled = new HashMap<>(); + HashMap gradebookAssignmentsLabel = new HashMap<>(); + + for (Assignment a : assignmentService.getAssignmentsForContext(contextString)) { + String gradebookItem = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + if (StringUtils.isNotBlank(gradebookItem)) { + String associatedAssignmentTitles = ""; + if (gAssignmentIdTitles.containsKey(gradebookItem)) { + // get the current associated assignment titles first + associatedAssignmentTitles = gAssignmentIdTitles.get(gradebookItem) + ", "; + } + + // append the current assignment title + associatedAssignmentTitles += a.getTitle(); + + // put the current associated assignment titles back + gAssignmentIdTitles.put(gradebookItem, associatedAssignmentTitles); } - gradebookAssignmentsLabel.put(formattedText.escapeHtml(gaId), label); } - } - // Items sorted by name - gradebookAssignmentsLabel = gradebookAssignmentsLabel.entrySet().stream() - .sorted(Entry.comparingByValue(Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER))) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue, - (e1, e2) -> e1, LinkedHashMap::new)); + // get all assignments in Gradebook + List gradebookAssignments = gradingService.getAssignments(contextString, contextString, SortType.SORT_BY_NONE); - context.put("gradebookAssignmentsSelectedDisabled", gradebookAssignmentsSelectedDisabled); - context.put("gradebookAssignmentsLabel", gradebookAssignmentsLabel); + // filtering out those from Samigo + for (Iterator i = gradebookAssignments.iterator(); i.hasNext(); ) { + org.sakaiproject.grading.api.Assignment gAssignment = (org.sakaiproject.grading.api.Assignment) i.next(); + if (!gAssignment.getExternallyMaintained() || gAssignment.getExternallyMaintained() && gAssignment.getExternalAppName().equals(assignmentService.getToolId())) { - // Determine if we're hiding the option to link to existing gradebook items - context.put("allowLinkToExistingGradebookItem", serverConfigurationService.getBoolean(AssignmentConstants.SAK_PROP_ALLOW_LINK_TO_EXISTING_GB_ITEM, AssignmentConstants.SAK_PROP_ALLOW_LINK_TO_EXISTING_GB_ITEM_DFLT)); + // gradebook item has been associated or not + String gaId = gAssignment.getExternallyMaintained() ? gAssignment.getExternalId() : gAssignment.getId().toString(); + String status = ""; + if (gAssignmentIdTitles.containsKey(gaId)) { + String assignmentTitle = gAssignmentIdTitles.get(gaId); + if (aTitle != null && aTitle.equals(assignmentTitle)) { + // this gradebook item is associated with current assignment, make it selected + status = "selected"; + } + } + + // check with the state variable + if (StringUtils.equals((String) state.getAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT), gaId)) { + status = "selected"; + } + + gradebookAssignmentsSelectedDisabled.put(formattedText.escapeHtml(gaId), status); + + // gradebook assignment label + String label = gAssignment.getName(); + if (gAssignmentIdTitles.containsKey(gaId)) { + label += " ( " + rb.getFormattedMessage("usedGradebookAssignment", new Object[]{gAssignmentIdTitles.get(gaId)}) + " )"; + } + gradebookAssignmentsLabel.put(formattedText.escapeHtml(gaId), label); + } + } + + // Items sorted by name + gradebookAssignmentsLabel = gradebookAssignmentsLabel.entrySet().stream() + .sorted(Entry.comparingByValue(Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER))) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue, + (e1, e2) -> e1, LinkedHashMap::new)); + + context.put("gradebookAssignmentsSelectedDisabled", gradebookAssignmentsSelectedDisabled); + context.put("gradebookAssignmentsLabel", gradebookAssignmentsLabel); + } } private void putGradebookCategoryInfoIntoContext(SessionState state, Context context) { - Map categoryTable = getCategoryTable(); - if (categoryTable != null) { - long categoryTableSize = categoryTable.size(); - context.put("value_totalCategories", Long.valueOf(categoryTableSize)); - - // selected category - context.put("value_Category", state.getAttribute(NEW_ASSIGNMENT_CATEGORY)); - - List categoryList = new ArrayList<>(categoryTable.keySet()); - Collections.sort(categoryList); - context.put("categoryKeys", categoryList); - context.put("categoryTable", categoryTable); - } else { - context.put("value_totalCategories", Long.valueOf(0)); + String siteId = (String) state.getAttribute(STATE_CONTEXT_STRING); + + if (!gradingService.isGradebookGroupEnabled(siteId)) { + Map categoryTable = getCategoryTable(); + if (categoryTable != null) { + long categoryTableSize = categoryTable.size(); + context.put("value_totalCategories", Long.valueOf(categoryTableSize)); + + // selected category + context.put("value_Category", state.getAttribute(NEW_ASSIGNMENT_CATEGORY)); + + List categoryList = new ArrayList<>(categoryTable.keySet()); + Collections.sort(categoryList); + context.put("categoryKeys", categoryList); + context.put("categoryTable", categoryTable); + } else { + context.put("value_totalCategories", Long.valueOf(0)); + } } } @@ -4020,54 +4126,11 @@ protected String build_instructor_grade_submission_context(VelocityPortlet portl String assignmentRef = (String) state.getAttribute(GRADE_SUBMISSION_ASSIGNMENT_ID); Optional assignment = Optional.ofNullable(getAssignment(assignmentRef, "build_instructor_grade_submission_context", state)); - if (assignment.isPresent()) { - Assignment a = assignment.get(); - context.put("assignment", a); - context.put("assignmentReference", assignmentRef); - gradeType = a.getTypeOfGrade(); - scaleFactor = a.getScaleFactor() != null ? a.getScaleFactor() : scaleFactor; - - state.setAttribute(NEW_ASSIGNMENT_CHECK_ANONYMOUS_GRADING, assignmentService.assignmentUsesAnonymousGrading(a)); - - boolean allowToGrade = true; - String assignmentAssociateGradebook = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); - if (StringUtils.isNotBlank(assignmentAssociateGradebook)) { - String gradebookUid = toolManager.getCurrentPlacement().getContext(); - // If the assignment reference is not equal to the associated gradebook item, then a custom gb item is being used - // S2U-34 In the 22x version this check was looking if the retrieved object from the gradingservice is null, now we check if an exception is thrown - if (!assignmentRef.equals(assignmentAssociateGradebook)) { - try { - org.sakaiproject.grading.api.Assignment gbAssignment = gradingService.getAssignment(gradebookUid, - assignmentAssociateGradebook); - - Long associateGradebookAssignmentId = gbAssignment.getId(); - context.put("associatedToGbItem", true); - context.put("associatedToGbEntityId", associateGradebookAssignmentId); - } catch (AssessmentNotFoundException e) { - log.error("Assignment not found while building grade submission context for custom gradebook item due to: {} {}", - e.toString(), ExceptionUtils.getStackTrace(e)); - } - } - - if (!gradingService.currentUserHasGradingPerm(gradebookUid)) { - context.put("notAllowedToGradeWarning", rb.getString("not_allowed_to_grade_in_gradebook")); - allowToGrade = false; - } - } - context.put("allowToGrade", allowToGrade); - - Map attachmentReferences = new HashMap<>(); - a.getAttachments().forEach(r -> attachmentReferences.put(r, entityManager.newReference(r))); - context.put("assignmentAttachmentReferences", attachmentReferences); - - if (a.getTypeOfGrade() == Assignment.GradeType.SCORE_GRADE_TYPE) { - context.put("value_grade", displayGrade(state, (String) state.getAttribute(GRADE_SUBMISSION_GRADE), scaleFactor)); - } - } String submissionRef = (String) state.getAttribute(GRADE_SUBMISSION_SUBMISSION_ID); // assignment submission Optional submission = Optional.ofNullable(getSubmission(submissionRef, "build_instructor_grade_submission_context", state)); + Optional submitterId = null; if (submission.isPresent()) { AssignmentSubmission s = submission.get(); context.put("submission", s); @@ -4080,7 +4143,10 @@ protected String build_instructor_grade_submission_context(VelocityPortlet portl context.put("submitterNames", getSubmitterFormattedNames(s, true)); context.put("submissionStatus", assignmentService.getSubmissionStatus(s.getId(), true)); - s.getSubmitters().stream().findAny().ifPresent(u -> context.put("submitterId", u.getSubmitter())); + submitterId = s.getSubmitters().stream().findAny(); + if (submitterId.isPresent()) { + context.put("submitterId", submitterId.get().getSubmitter()); + } s.getSubmitters().stream().findAny().ifPresent(spent -> context.put("submitterTimeSpent", spent.getTimeSpent())); if (assignment.isPresent()) { @@ -4195,6 +4261,66 @@ protected String build_instructor_grade_submission_context(VelocityPortlet portl rangeAndGroups.buildInstructorGradeSubmissionContextGroupCheck(assignment, s.getGroupId(), state); } + if (assignment.isPresent()) { + Assignment a = assignment.get(); + context.put("assignment", a); + context.put("assignmentReference", assignmentRef); + gradeType = a.getTypeOfGrade(); + scaleFactor = a.getScaleFactor() != null ? a.getScaleFactor() : scaleFactor; + + state.setAttribute(NEW_ASSIGNMENT_CHECK_ANONYMOUS_GRADING, assignmentService.assignmentUsesAnonymousGrading(a)); + + boolean allowToGrade = true; + String assignmentAssociateGradebook = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + + if (StringUtils.isNotBlank(assignmentAssociateGradebook) && submitterId.isPresent()) { + String gradebookUid = toolManager.getCurrentPlacement().getContext(); + String siteId = toolManager.getCurrentPlacement().getContext(); + // S2U-26 even if a user can potentially have multiple gradebooks, we're only allowing one return column + if (gradingService.isGradebookGroupEnabled(siteId)) { + List userGradebooks = gradingService.getGradebookInstancesForUser(siteId, submitterId.get().getSubmitter()); + gradebookUid = userGradebooks.get(0); + } + // If the assignment reference is not equal to the associated gradebook item, then a custom gb item is being used + // S2U-34 In the 22x version this check was looking if the retrieved object from the gradingservice is null, now we check if an exception is thrown + if (!assignmentRef.equals(assignmentAssociateGradebook)) { + try { + org.sakaiproject.grading.api.Assignment gbAssignment = null; + + List associateGbList = Arrays.asList(assignmentAssociateGradebook.split(",")); + for (String associateString : associateGbList) { + org.sakaiproject.grading.api.Assignment gbAssignmentFound = gradingService.getAssignment(gradebookUid, siteId, associateString); + + if (gbAssignmentFound != null) { + gbAssignment = gbAssignmentFound; + break; + } + } + + Long associateGradebookAssignmentId = gbAssignment.getId(); + context.put("associatedToGbItem", true); + context.put("associatedToGbEntityId", associateGradebookAssignmentId); + } catch (AssessmentNotFoundException e) { + log.error("Assignment not found while building grade submission context for custom gradebook item due to: {} {}", e.toString(), ExceptionUtils.getStackTrace(e)); + } + } + + if (!gradingService.currentUserHasGradingPerm(siteId)) { + context.put("notAllowedToGradeWarning", rb.getString("not_allowed_to_grade_in_gradebook")); + allowToGrade = false; + } + } + context.put("allowToGrade", allowToGrade); + + Map attachmentReferences = new HashMap<>(); + a.getAttachments().forEach(r -> attachmentReferences.put(r, entityManager.newReference(r))); + context.put("assignmentAttachmentReferences", attachmentReferences); + + if (a.getTypeOfGrade() == Assignment.GradeType.SCORE_GRADE_TYPE) { + context.put("value_grade", displayGrade(state, (String) state.getAttribute(GRADE_SUBMISSION_GRADE), scaleFactor)); + } + } + context.put("user", state.getAttribute(STATE_USER)); context.put("submissionTypeTable", submissionTypeTable()); context.put("instructorAttachments", state.getAttribute(ATTACHMENTS)); @@ -5091,6 +5217,9 @@ private String build_instructor_grade_assignment_context(VelocityPortlet portlet } context.put("value_grades", ugrades); + } + + if (assignment.getIsGroup() || gradingService.isGradebookGroupEnabled(assignment.getContext())) { rangeAndGroups.buildInstructorGradeAssignmentContext(state, context, assignment); } @@ -5919,8 +6048,8 @@ private String build_instructor_report_submissions(VelocityPortlet portlet, Cont private boolean canGrade() { boolean rv = false; try { - String gradebookUid = toolManager.getCurrentPlacement().getContext(); - if (gradingService.currentUserHasEditPerm(gradebookUid) || gradingService.currentUserHasGradingPerm(gradebookUid)) { + String siteId = toolManager.getCurrentPlacement().getContext(); + if (gradingService.currentUserHasEditPerm(siteId) || gradingService.currentUserHasGradingPerm(siteId)) { rv = true; } } catch (Exception e) { @@ -6779,7 +6908,10 @@ public void doSave_toggle_remove_review(RunData data) { if (assignmentRef != null) { String associateGradebookAssignment = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); // update grade in gradebook - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), assignmentRef, associateGradebookAssignment, null, null, null, -1, null, submissionId, "update", -1)); + List gradebookUids = gradingService.getGradebookUidByExternalId(associateGradebookAssignment); + for (String gradebookUid : gradebookUids) { + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, assignmentRef, associateGradebookAssignment, null, null, null, -1, null, submissionId, "update", -1)); + } } } } @@ -7795,20 +7927,43 @@ private void setNewAssignmentParameters(RunData data, boolean validify) { // Skip category if it was never set. Long catInt = -1L; + String newCategoryString = "-1"; + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(siteId); + if (params.getString(NEW_ASSIGNMENT_CATEGORY) != null && GRADEBOOK_INTEGRATION_ADD.equals(grading)) { - catInt = Long.valueOf(params.getString(NEW_ASSIGNMENT_CATEGORY)); + String categorySelected = params.getString(NEW_ASSIGNMENT_CATEGORY); + + if (isGradebookGroupEnabled) { + newCategoryString = categorySelected; + state.setAttribute(NEW_ASSIGNMENT_CATEGORY, categorySelected); + } else { + catInt = Long.valueOf(categorySelected); + state.setAttribute(NEW_ASSIGNMENT_CATEGORY, catInt); + } } - state.setAttribute(NEW_ASSIGNMENT_CATEGORY, catInt); // only when choose to associate with assignment in Gradebook String associateAssignment = params.getString(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + String gbSelector = params.getString(GB_SELECTOR); + + Map gradebookPointsMap = new HashMap<>(); - Double droppedCategoryPoints = -1D; + // FIXME Official bug: If we save an assignment and an error occurs that returns us to the form, + // the fields must be pre-selected, including the single selector for gradebook items and categories. + // Currently, if an error occurs in the task, the selector remains unfilled. if (grading != null && gradeType != Assignment.GradeType.UNGRADED_GRADE_TYPE) { if (grading.equals(GRADEBOOK_INTEGRATION_ASSOCIATE)) { - state.setAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT, associateAssignment); + if (isGradebookGroupEnabled) { + state.setAttribute(GB_SELECTOR, gbSelector); + } else { + state.setAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT, associateAssignment); + } } else { - state.removeAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + if (isGradebookGroupEnabled) { + state.removeAttribute(GB_SELECTOR); + } else { + state.removeAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + } } if (!grading.equals(GRADEBOOK_INTEGRATION_NO)) { @@ -7816,58 +7971,111 @@ private void setNewAssignmentParameters(RunData data, boolean validify) { if (gradeType != Assignment.GradeType.SCORE_GRADE_TYPE) { addAlert(state, rb.getString("addtogradebook.wrongGradeScale")); } - // if chosen as "associate", have to choose one assignment from Gradebook - if (grading.equals(GRADEBOOK_INTEGRATION_ASSOCIATE) && StringUtils.trimToNull(associateAssignment) == null) { - addAlert(state, rb.getString("grading.associate.alert")); - } else { - Long thisCatRef = -1L; - List categoryDefinitions = gradingService.getCategoryDefinitions(siteId); - if (catInt != -1) { - thisCatRef = catInt; - } else if (assignmentRef.isEmpty()) { - thisCatRef = catInt; - } else { - for (CategoryDefinition thisCategoryDefinition : categoryDefinitions) { - if (thisCategoryDefinition.isAssignmentInThisCategory(assignmentRef)) { - thisCatRef = thisCategoryDefinition.getId(); + String[] groupChoice = params.getStrings("selectedGroups"); + + String associateGradebookAssignment = (String) state.getAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + if ((grading.equals(GRADEBOOK_INTEGRATION_ASSOCIATE) && + ((isGradebookGroupEnabled && StringUtils.trimToNull(gbSelector) == null) || + (!isGradebookGroupEnabled && StringUtils.trimToNull(associateGradebookAssignment) == null)))) { + addAlert(state, rb.getString("grading.associate.alert")); + } + + switch (grading) { + case GRADEBOOK_INTEGRATION_ADD: + if (isGradebookGroupEnabled) { + String assignTo = params.getString("assignTo"); + + if (!assignTo.equals("individuals")) { + String categorySelected = params.getString(NEW_ASSIGNMENT_CATEGORY); + List selectedCategories = Arrays.asList(categorySelected.split(",")); + + boolean areCategoriesInGroups = + gradingService.checkMultiSelectorList(siteId, + groupChoice != null ? Arrays.asList(groupChoice) : new ArrayList<>(), selectedCategories, true); + + if (!areCategoriesInGroups) { + addAlert(state, rb.getFormattedMessage("group.sitegradebook.categories.error")); + } } + + List gbList = gradingService.getGradebookGroupInstances(siteId); + List existingGradebookUids = gbList.stream().map(Gradebook::getUid).collect(Collectors.toList()); + + for (String gbUid : existingGradebookUids) { + gradingService.buildGradebookPointsMap(gbUid, siteId, assignmentRef, gradebookPointsMap, newCategoryString); + } + } else { + gradingService.buildGradebookPointsMap(siteId, siteId, assignmentRef, gradebookPointsMap, catInt.toString()); } - } - if (thisCatRef != -1) { - for(CategoryDefinition thisCategoryDefinition : categoryDefinitions) { - if (Objects.equals(thisCategoryDefinition.getId(), thisCatRef)) { - if (thisCategoryDefinition.getDropKeepEnabled() && !thisCategoryDefinition.getEqualWeight()) { - Double thisCategoryPoints = thisCategoryDefinition.getPointsForCategory(); - if (thisCategoryPoints != null) { - droppedCategoryPoints = thisCategoryPoints; - } + break; + case GRADEBOOK_INTEGRATION_ASSOCIATE: + if (isGradebookGroupEnabled) { + String assignTo = params.getString("assignTo"); + + if (!assignTo.equals("individuals")) { + List gbItemList = Arrays.asList(gbSelector.split(",")); + + boolean areItemsInGroups = + gradingService.checkMultiSelectorList(siteId, + groupChoice != null ? Arrays.asList(groupChoice) : new ArrayList<>(), gbItemList, false); + + if (!areItemsInGroups) { + addAlert(state, rb.getFormattedMessage("group.sitegradebook.items.error")); } } } - } - } - // check if chosen a previously associated object - String associatedAssignmentTitles = ""; - // check assignments from the site - for (Assignment a : assignmentService.getAssignmentsForContext(siteId)) { - if (assignmentId.equals(a.getId())) { - continue; - } - String gradebookItem = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); - if (gradebookItem != null && StringUtils.equals(associateAssignment, gradebookItem)) { - associatedAssignmentTitles += a.getTitle(); - } - } - if (StringUtils.isNotBlank(associatedAssignmentTitles) && state.getAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED) == null) { - state.setAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED, Boolean.TRUE); - } else { - // clean the attribute after user confirm - state.removeAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED); - } - if (state.getAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED) != null && validify) { - addAlert(state, rb.getString("addtogradebook.previouslyAssoc")); + List gradebookReferenceList = new ArrayList<>(); + + if (isGradebookGroupEnabled) { + List gbItemList = Arrays.asList(gbSelector.split(",")); + + for (String gbItem : gbItemList) { + Long itemId = Long.parseLong(gbItem); + + GradebookAssignment gradebookAssignment = gradingService.getGradebookAssigment(siteId, itemId); + + String reference = gradebookAssignment.getExternallyMaintained() ? + gradebookAssignment.getExternalId() : gradebookAssignment.getId().toString(); + + gradebookReferenceList.add(reference); + } + } else { + gradebookReferenceList.add(associateAssignment); + } + + String associatedAssignmentTitles = ""; + // check assignments from the site + for (Assignment a : assignmentService.getAssignmentsForContext(siteId)) { + if (assignmentId.equals(a.getId())) { + continue; + } + + String selectedAssociateAssignment = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + + for (String gradebookReference : gradebookReferenceList) { + if (selectedAssociateAssignment != null) { + List selectedAssociateAssignmentList = Arrays.asList(selectedAssociateAssignment.split(",")); + + if (selectedAssociateAssignmentList.contains(gradebookReference)) { + associatedAssignmentTitles += a.getTitle(); + } + } + } + } + if (StringUtils.isNotBlank(associatedAssignmentTitles) && state.getAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED) == null) { + state.setAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED, Boolean.TRUE); + } else { + // clean the attribute after user confirm + state.removeAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED); + } + if (state.getAttribute(NEW_ASSIGNMENT_PREVIOUSLY_ASSOCIATED) != null && validify) { + addAlert(state, rb.getString("addtogradebook.previouslyAssoc")); + } + break; + default: + break; } } } @@ -7890,6 +8098,7 @@ private void setNewAssignmentParameters(RunData data, boolean validify) { } state.setAttribute(TAG_SELECTOR, params.getString(TAG_SELECTOR)); + state.setAttribute(GB_SELECTOR, params.getString(GB_SELECTOR)); //Peer Assessment boolean peerAssessment = false; @@ -8222,10 +8431,14 @@ private void setNewAssignmentParameters(RunData data, boolean validify) { // when scale is points, grade must be integer and less than maximum value gradePoints = scalePointGrade(state, gradePoints, scaleFactor); state.setAttribute(NEW_ASSIGNMENT_GRADE_POINTS, gradePoints); - if (droppedCategoryPoints != -1) { - Double enteredPoints = new Double(displayGrade(state, gradePoints, scaleFactor)); - if (!enteredPoints.equals(droppedCategoryPoints)) { - addAlert(state, rb.getFormattedMessage("pleasee6", new Object[] {droppedCategoryPoints.toString()})); + + if (gradebookPointsMap.size() > 0) { + Double enteredPoints = Double.parseDouble(displayGrade(state, gradePoints, scaleFactor)); + for (Map.Entry entry : gradebookPointsMap.entrySet()) { + Double gradebookCategoryPoints = entry.getValue(); + if (!enteredPoints.equals(gradebookCategoryPoints)) { + addAlert(state, rb.getFormattedMessage("pleasee6", new Object[] {gradebookCategoryPoints.toString()})); + } } } } @@ -8673,6 +8886,7 @@ private void post_save_assignment(RunData data, String postOrSave) { ParameterParser params = data.getParameters(); String siteId = (String) state.getAttribute(STATE_CONTEXT_STRING); + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(siteId); boolean post = (postOrSave != null) && "post".equals(postOrSave); @@ -8797,6 +9011,8 @@ private void post_save_assignment(RunData data, String postOrSave) { Boolean checkAddInstructorTags = state.getAttribute(NEW_ASSIGNMENT_CHECK_ADD_INSTRUCTOR_TAGS) != null ? (Boolean) state.getAttribute(NEW_ASSIGNMENT_CHECK_ADD_INSTRUCTOR_TAGS) : null; Boolean checkAddGroupTags = state.getAttribute(NEW_ASSIGNMENT_CHECK_ADD_GROUP_TAGS) != null ? (Boolean) state.getAttribute(NEW_ASSIGNMENT_CHECK_ADD_GROUP_TAGS) : null; + RangeAndGroupsDelegate.RangeAndGroupSettings rangeAndGroupSettings = rangeAndGroups.postSaveAssignmentSettings(state, siteService, siteId); + String addtoGradebook = GRADEBOOK_INTEGRATION_NO; if (((Boolean) state.getAttribute(NEW_ASSIGNMENT_GRADE_ASSIGNMENT))) { addtoGradebook = StringUtils.isNotBlank((String) state.getAttribute(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK)) ? (String) state.getAttribute(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK) : GRADEBOOK_INTEGRATION_NO; @@ -8806,9 +9022,65 @@ private void post_save_assignment(RunData data, String postOrSave) { addtoGradebook = GRADEBOOK_INTEGRATION_NO; } - long category = state.getAttribute(NEW_ASSIGNMENT_CATEGORY) != null ? (Long) state.getAttribute(NEW_ASSIGNMENT_CATEGORY) : -1; + List selectedGradebookUids = new ArrayList<>(); + List selectedGroups = rangeAndGroupSettings.groups.stream().map(Group::getId).collect(Collectors.toList()); - String associateGradebookAssignment = (String) state.getAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + buildGradebookUidList(state, siteId, selectedGradebookUids, addtoGradebook, selectedGroups, isGradebookGroupEnabled); + + Map gradebookCategorieMap = new HashMap<>(); + Map gradebookItemMap = new HashMap<>(); + + if (GRADEBOOK_INTEGRATION_ADD.equals(addtoGradebook)) { + if (isGradebookGroupEnabled) { + String categoriesString = (String) state.getAttribute(NEW_ASSIGNMENT_CATEGORY); + + if (categoriesString == null || categoriesString.isBlank()) { + selectedGradebookUids.forEach(gbUid -> gradebookCategorieMap.put(gbUid, "-1")); + } else { + List selectedCategories = Arrays.asList(categoriesString.split(",")); + + for (String gbUid : selectedGradebookUids) { + List categoryDefinitions = gradingService.getCategoryDefinitions(gbUid, siteId); + + String categoryId = categoryDefinitions.stream() + .filter(category -> selectedCategories.contains(category.getId().toString())) + .map(category -> category.getId().toString()) + .findFirst() + .orElse("-1"); + + gradebookCategorieMap.put(gbUid, categoryId); + } + } + } else { + gradebookCategorieMap.put(siteId, + state.getAttribute(NEW_ASSIGNMENT_CATEGORY) != null + ? ((Long) state.getAttribute(NEW_ASSIGNMENT_CATEGORY)).toString() + : "-1"); + } + } else if (GRADEBOOK_INTEGRATION_ASSOCIATE.equals(addtoGradebook)) { + if (isGradebookGroupEnabled) { + String itemString = (String) state.getAttribute(GB_SELECTOR); + + if (itemString != null && StringUtils.isNotBlank(itemString)) { + List itemList = Arrays.asList(itemString.split(",")); + + for (String item : itemList) { + Long itemId = Long.parseLong(item); + + GradebookAssignment gradebookAssignment = gradingService.getGradebookAssigment(siteId, itemId); + + String reference = gradebookAssignment.getExternallyMaintained() ? + gradebookAssignment.getExternalId() : gradebookAssignment.getId().toString(); + + gradebookItemMap.put(reference, + gradingService.getGradebookUidByAssignmentById(siteId, itemId)); + } + } + } else { + String associateGradebookAssignment = (String) state.getAttribute(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); + gradebookItemMap.put(associateGradebookAssignment, siteId); + } + } String allowResubmitNumber = state.getAttribute(AssignmentConstants.ALLOW_RESUBMIT_NUMBER) != null ? (String) state.getAttribute(AssignmentConstants.ALLOW_RESUBMIT_NUMBER) : null; @@ -8893,8 +9165,6 @@ private void post_save_assignment(RunData data, String postOrSave) { // the attachments List attachments = (List) state.getAttribute(NEW_ASSIGNMENT_ATTACHMENT); - RangeAndGroupsDelegate.RangeAndGroupSettings rangeAndGroupSettings = rangeAndGroups.postSaveAssignmentSettings(state, siteService, siteId); - if ((state.getAttribute(STATE_MESSAGE) == null) && (a != null)) { aOldTitle = a.getTitle(); @@ -8914,7 +9184,11 @@ private void post_save_assignment(RunData data, String postOrSave) { String oAssociateGradebookAssignment = aProperties.get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); Instant resubmitCloseTime = getTimeFromState(state, ALLOW_RESUBMIT_CLOSE_MONTH, ALLOW_RESUBMIT_CLOSE_DAY, ALLOW_RESUBMIT_CLOSE_YEAR, ALLOW_RESUBMIT_CLOSE_HOUR, ALLOW_RESUBMIT_CLOSE_MIN); - editAssignmentProperties(a, checkAddDueTime, checkAutoAnnounce, addtoGradebook, associateGradebookAssignment, allowResubmitNumber, aProperties, post, resubmitCloseTime, checkAnonymousGrading); + String gradebookItemKeys = gradebookItemMap.keySet().stream().collect(Collectors.joining(",")); + + editAssignmentProperties(a, checkAddDueTime, checkAutoAnnounce, + addtoGradebook, gradebookItemKeys, allowResubmitNumber, + aProperties, post, resubmitCloseTime, checkAnonymousGrading); //TODO: ADD_DUE_DATE if (state.getAttribute(AssignmentConstants.ASSIGNMENT_OPENDATE_NOTIFICATION) != null) { @@ -9024,7 +9298,28 @@ private void post_save_assignment(RunData data, String postOrSave) { // integrate with Gradebook try { - initIntegrateWithGradebook(state, siteId, aOldTitle, oAssociateGradebookAssignment, a, title, dueTime, gradeType, gradePoints, addtoGradebook, associateGradebookAssignment, rangeAndGroupSettings.range, category); + if (GRADEBOOK_INTEGRATION_ADD.equals(addtoGradebook) && gradebookCategorieMap.size() > 0) { + for (Map.Entry entry : gradebookCategorieMap.entrySet()) { + String gbUid = entry.getKey(); + String categorieId = entry.getValue(); + + initIntegrateWithGradebook(state, gbUid, + aOldTitle, oAssociateGradebookAssignment, + a, title, dueTime, gradeType, gradePoints, + addtoGradebook, null, + Long.parseLong(categorieId)); + } + } else if (GRADEBOOK_INTEGRATION_ASSOCIATE.equals(addtoGradebook) && gradebookItemMap.size() > 0) { + for (Map.Entry entry : gradebookItemMap.entrySet()) { + String reference = entry.getKey(); + String gradebookUid = entry.getValue(); + + initIntegrateWithGradebook(state, gradebookUid, + aOldTitle, oAssociateGradebookAssignment, + a, title, dueTime, gradeType, gradePoints, + addtoGradebook, reference, -1L); + } + } } catch (AssignmentHasIllegalPointsException e) { addAlert(state, rb.getString("addtogradebook.illegalPoints")); log.warn(this + ":post_save_assignment " + e.getMessage()); @@ -9379,12 +9674,10 @@ private void addRemoveSubmissionsForNonElectronicAssignment(SessionState state, } } - private void initIntegrateWithGradebook(SessionState state, String siteId, String aOldTitle, String oAssociateGradebookAssignment, Assignment assignment, String title, Instant dueTime, Assignment.GradeType gradeType, String gradePoints, String addtoGradebook, String associateGradebookAssignment, String range, long category) { + private void initIntegrateWithGradebook(SessionState state, String gradebookUid, String aOldTitle, String oAssociateGradebookAssignment, Assignment assignment, String title, Instant dueTime, Assignment.GradeType gradeType, String gradePoints, String addtoGradebook, String associateGradebookAssignment, long category) { String context = (String) state.getAttribute(STATE_CONTEXT_STRING); String assignmentReference = AssignmentReferenceReckoner.reckoner().assignment(assignment).reckon().getReference(); - // only if the gradebook is defined - String gradebookUid = toolManager.getCurrentPlacement().getContext(); String addUpdateRemoveAssignment = "remove"; if (!addtoGradebook.equals(GRADEBOOK_INTEGRATION_NO)) { // if integrate with Gradebook @@ -9396,52 +9689,54 @@ private void initIntegrateWithGradebook(SessionState state, String siteId, Strin if (!"remove".equals(addUpdateRemoveAssignment) && gradeType == Assignment.GradeType.SCORE_GRADE_TYPE) { try { - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), assignmentReference, associateGradebookAssignment, addUpdateRemoveAssignment, aOldTitle, title, Integer.parseInt(gradePoints), dueTime, null, null, category)); + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, assignmentReference, associateGradebookAssignment, addUpdateRemoveAssignment, aOldTitle, title, Integer.parseInt(gradePoints), dueTime, null, null, category)); // add all existing grades, if any, into Gradebook - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), assignmentReference, associateGradebookAssignment, null, null, null, -1, null, null, "update", category)); + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, assignmentReference, associateGradebookAssignment, null, null, null, -1, null, null, "update", category)); // if the assignment has been assoicated with a different entry in gradebook before, remove those grades from the entry in Gradebook - if (StringUtils.trimToNull(oAssociateGradebookAssignment) != null && !oAssociateGradebookAssignment.equals(associateGradebookAssignment)) { - // remove all previously associated grades, if any, into Gradebook - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), assignmentReference, oAssociateGradebookAssignment, null, null, null, -1, null, null, "remove", category)); + if (StringUtils.trimToNull(oAssociateGradebookAssignment) != null) { + List oldGradebookAssignmentList = Arrays.asList(oAssociateGradebookAssignment.split(",")); + + String reference = associateGradebookAssignment; + + boolean isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, associateGradebookAssignment); + + if (isExternalAssignmentDefined) { + org.sakaiproject.grading.api.Assignment gAssignment = gradingService.getExternalAssignment(gradebookUid, reference); + + reference = gAssignment.getExternallyMaintained() ? gAssignment.getExternalId() : gAssignment.getId().toString(); + } else { + String siteId = (String) state.getAttribute(STATE_CONTEXT_STRING); + Long itemId = Long.parseLong(reference); - // if the old assoicated assignment entry in GB is an external one, but doesn't have anything assoicated with it in Assignment tool, remove it - removeNonAssociatedExternalGradebookEntry(context, assignmentReference, oAssociateGradebookAssignment, gradebookUid); + GradebookAssignment gradebookAssignment = gradingService.getGradebookAssigment(siteId, itemId); + reference = gradebookAssignment.getExternallyMaintained() ? gradebookAssignment.getExternalId() : gradebookAssignment.getId().toString(); + } + + boolean gradebookAssignmentExists = oldGradebookAssignmentList.contains(reference); + + if (!gradebookAssignmentExists) { + // remove all previously associated grades, if any, into Gradebook + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, assignmentReference, oAssociateGradebookAssignment, null, null, null, -1, null, null, "remove", category)); + + // if the old associated assignment entry in GB is an external one, but doesn't have anything assoicated with it in Assignment tool, remove it + assignmentToolUtils.removeNonAssociatedExternalGradebookEntry(context, assignmentReference, oAssociateGradebookAssignment, gradebookUid); + } } } catch (NumberFormatException nE) { alertInvalidPoint(state, gradePoints, assignment.getScaleFactor()); log.warn(this + ":initIntegrateWithGradebook " + nE.getMessage()); } } else { - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), assignmentReference, associateGradebookAssignment, "remove", null, null, -1, null, null, null, category)); + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, assignmentReference, associateGradebookAssignment, "remove", null, null, -1, null, null, null, category)); } } else { // remove all previously associated grades, if any, into Gradebook - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), assignmentReference, oAssociateGradebookAssignment, null, null, null, -1, null, null, "remove", category)); + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, assignmentReference, oAssociateGradebookAssignment, null, null, null, -1, null, null, "remove", category)); // need to remove the associated gradebook entry if 1) it is external and 2) no other assignment are associated with it - removeNonAssociatedExternalGradebookEntry(context, assignmentReference, oAssociateGradebookAssignment, gradebookUid); - } - } - - private void removeNonAssociatedExternalGradebookEntry(String context, String assignmentReference, String associateGradebookAssignment, String gradebookUid) { - boolean isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, associateGradebookAssignment); - if (isExternalAssignmentDefined) { - boolean found = false; - // iterate through all assignments currently in the site, see if any is associated with this GB entry - for (Assignment assignment : assignmentService.getAssignmentsForContext(context)) { - String reference = AssignmentReferenceReckoner.reckoner().assignment(assignment).reckon().getReference(); - if (StringUtils.equals(assignment.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT), associateGradebookAssignment) - && !StringUtils.equals(reference, assignmentReference)) { - found = true; - break; - } - } - // so if none of the assignment in this site is associated with the entry, remove the entry - if (!found) { - gradingService.removeExternalAssignment(gradebookUid, associateGradebookAssignment); - } + assignmentToolUtils.removeNonAssociatedExternalGradebookEntry(context, assignmentReference, oAssociateGradebookAssignment, gradebookUid); } } @@ -10005,7 +10300,7 @@ private void commitAssignment(SessionState state, addAlert(state, rb.getString("youarenot_addAssignmentContent")); } - if (a.getIsGroup()) { + if (a.getIsGroup() || gradingService.isGradebookGroupEnabled(a.getContext())) { rangeAndGroups.checkAssignmentForUsersInMultipleGroups(a, state); } @@ -10750,8 +11045,10 @@ public void doDelete_assignment(RunData data) { rubricsService.softDeleteRubricAssociation(AssignmentConstants.TOOL_ID, id); // remove from Gradebook - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), ref, associateGradebookAssignment, "remove", null, null, -1, null, null, null, -1)); - + List gradebookUids = gradingService.getGradebookUidByExternalId(associateGradebookAssignment); + for (String gradebookUid : gradebookUids) { + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, ref, associateGradebookAssignment, "remove", null, null, -1, null, null, null, -1)); + } // we use to check "assignment.delete.cascade.submission" setting. But the implementation now is always remove submission objects when the assignment is removed. // delete assignment and its submissions altogether deleteAssignmentObjects(state, assignment); @@ -10990,6 +11287,23 @@ public void doHardRemove_confirm_assignment(RunData data) { } } // doHardRemove_confirm_assignment + public void buildGradebookUidList(SessionState state, String siteId, List selectedGradebookUids, String addtoGradebook, + List selectedGroups, boolean isGradebookGroupEnabled) { + if (!GRADEBOOK_INTEGRATION_NO.equals(addtoGradebook)) { + if (!isGradebookGroupEnabled) { + selectedGradebookUids.add(siteId); + } else { + List gbList = gradingService.getGradebookGroupInstances(siteId); + List existingGradebookUids = gbList.stream().map(Gradebook::getUid).collect(Collectors.toList()); + if (!existingGradebookUids.containsAll(selectedGroups)) { + addAlert(state, rb.getString("selected.groups.without.gradebook")); + } else { + selectedGradebookUids.addAll(selectedGroups); + } + } + } + } + /** * Action is to show the restore assigment confirmation screen */ @@ -11024,12 +11338,26 @@ public void doRestore_confirm_assignment(RunData data) { // Restore gradebook item only if assignment was previously associated if (StringUtils.equals(a.getProperties().get(NEW_ASSIGNMENT_ADD_TO_GRADEBOOK), GRADEBOOK_INTEGRATION_ASSOCIATE)) { String siteId = (String) state.getAttribute(STATE_CONTEXT_STRING); + Site site = siteService.getSite(siteId); + + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(siteId); + String title = a.getTitle(); String associateGradebookAssignment = null; // Stored in properties, but we need to pass null so the gradebook integration algorithm creates the item rather than updating the (non-existing) original String addToGradebook = GRADEBOOK_INTEGRATION_ADD; // Stored in properties as "associate" already, but we need to pass "add" to recreate the original long category = -1L; // We have to default to no category because the original gradebook item was hard deleted and category ID is not stored in assignment properties - initIntegrateWithGradebook(state, siteId, title, associateGradebookAssignment, a, title, a.getDueDate(), a.getTypeOfGrade(), a.getMaxGradePoint().toString(), - addToGradebook, associateGradebookAssignment, a.getTypeOfAccess().toString(), category); + + List asnGroups = a.getGroups().stream().map(groupId -> site.getGroup(groupId)).filter(Objects::nonNull).collect(Collectors.toList()); + List groupIdList = asnGroups.stream().map(Group::getId).collect(Collectors.toList()); + + List selectedGradebookUids = new ArrayList<>(); + + buildGradebookUidList(state, siteId, selectedGradebookUids, addToGradebook, groupIdList, isGradebookGroupEnabled); + + for (String gbUid : selectedGradebookUids) { + initIntegrateWithGradebook(state, gbUid, title, associateGradebookAssignment, a, title, a.getDueDate(), a.getTypeOfGrade(), a.getMaxGradePoint().toString(), + addToGradebook, associateGradebookAssignment, category); + } } } } catch (IdUnusedException | PermissionException e) { @@ -11218,8 +11546,10 @@ public void doRelease_grades(RunData data) { if (integrateWithGradebook != null && !integrateWithGradebook.equals(GRADEBOOK_INTEGRATION_NO)) { // integrate with Gradebook String associateGradebookAssignment = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); - - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), aReference, associateGradebookAssignment, null, null, null, -1, null, null, "update", -1)); + List gradebookUids = gradingService.getGradebookUidByExternalId(associateGradebookAssignment); + for (String gradebookUid : gradebookUids) { + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, aReference, associateGradebookAssignment, null, null, null, -1, null, null, "update", -1)); + } } } } @@ -11986,7 +12316,10 @@ public boolean saveReviewGradeForm(RunData data, SessionState state, String grad String aReference = AssignmentReferenceReckoner.reckoner().assignment(a).reckon().getReference(); String associateGradebookAssignment = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); // update grade in gradebook - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), aReference, associateGradebookAssignment, null, null, null, -1, null, submissionId, "update", -1)); + List gradebookUids = gradingService.getGradebookUidByExternalId(associateGradebookAssignment); + for (String gradebookUid : gradebookUids) { + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, aReference, associateGradebookAssignment, null, null, null, -1, null, submissionId, "update", -1)); + } } } } @@ -12943,6 +13276,7 @@ private void resetAssignment(SessionState state) { state.removeAttribute(RUBRIC_ASSOCIATION); state.removeAttribute(TAG_SELECTOR); + state.removeAttribute(GB_SELECTOR); } // resetAssignment /** @@ -13005,11 +13339,11 @@ private Map submissionTypeTable() { * @return */ private Map getCategoryTable() { - Map catTable = new HashMap<>(); String gradebookUid = toolManager.getCurrentPlacement().getContext(); + if (canGrade() && gradingService.isCategoriesEnabled(gradebookUid)) { - catTable = gradingService.getCategoryDefinitions(gradebookUid).stream() + catTable = gradingService.getCategoryDefinitions(gradebookUid, gradebookUid).stream() .collect(Collectors.toMap(c -> c.getId(), c -> c.getName())); catTable.put(-1L, rb.getString("grading.unassigned")); } @@ -14732,7 +15066,10 @@ else if (submission.getDateSubmitted() == null && (submission.getSubmittedText() if (releaseGrades && graded) { // update grade in gradebook if (associateGradebookAssignment != null) { - addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), aReference, associateGradebookAssignment, null, null, null, -1, null, sReference, "update", -1)); + List gradebookUids = gradingService.getGradebookUidByExternalId(associateGradebookAssignment); + for (String gradebookUid : gradebookUids) { + addAlerts(state, assignmentToolUtils.integrateGradebook(stateToMap(state), gradebookUid, aReference, associateGradebookAssignment, null, null, null, -1, null, sReference, "update", -1)); + } } } } catch (PermissionException e) { @@ -15700,13 +16037,13 @@ protected void setScoringAgentProperties(Context context, Assignment assignment, org.sakaiproject.grading.api.Assignment gbItem = null; try { - gbItem = gradingService.getAssignment(gradebookUid, gbItemName); + gbItem = gradingService.getAssignment(gradebookUid, gradebookUid, gbItemName); } catch (SecurityException se) { // the gradebook method above is overzealous about security when retrieving the gb item by name. It doesn't // allow student-role users to access the assignment via this method. So we // have to retrieve all viewable gb items and filter to get the one we want, unfortunately, if we hit an exception. // If gb item isn't released in the gb, scoring agent info will not be available. - List viewableGbItems = gradingService.getViewableAssignmentsForCurrentUser(gradebookUid); + List viewableGbItems = gradingService.getViewableAssignmentsForCurrentUser(gradebookUid, gradebookUid, SortType.SORT_BY_NONE); if (viewableGbItems != null && !viewableGbItems.isEmpty()) { for (org.sakaiproject.grading.api.Assignment viewableGbItem : viewableGbItems) { if (gbItemName.equals(viewableGbItem.getName())) { diff --git a/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentToolUtils.java b/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentToolUtils.java index e30c4118f6fa..480720ae2664 100644 --- a/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentToolUtils.java +++ b/assignment/tool/src/java/org/sakaiproject/assignment/tool/AssignmentToolUtils.java @@ -26,6 +26,8 @@ import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -44,18 +46,25 @@ import org.sakaiproject.assignment.api.model.Assignment; import org.sakaiproject.assignment.api.model.AssignmentSubmission; import org.sakaiproject.assignment.api.model.AssignmentSubmissionSubmitter; +import org.sakaiproject.assignment.tool.AssignmentAction.SubmitterSubmission; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.entity.api.Reference; +import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.grading.api.AssessmentNotFoundException; import org.sakaiproject.grading.api.AssignmentHasIllegalPointsException; +import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.GradingService; import org.sakaiproject.grading.api.InvalidGradeItemNameException; +import org.sakaiproject.grading.api.model.GradebookAssignment; import org.sakaiproject.lti.api.LTIService; import org.sakaiproject.rubrics.api.RubricsConstants; import org.sakaiproject.rubrics.api.RubricsService; import org.sakaiproject.rubrics.api.model.ToolItemRubricAssociation; +import org.sakaiproject.site.api.Group; +import org.sakaiproject.site.api.Site; +import org.sakaiproject.site.api.SiteService; import org.sakaiproject.time.api.TimeService; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.user.api.User; @@ -76,6 +85,7 @@ public class AssignmentToolUtils { formattedText = ComponentManager.get(FormattedText.class); } + private SiteService siteService; private AssignmentService assignmentService; private UserDirectoryService userDirectoryService; private GradingService gradingService; @@ -393,7 +403,71 @@ public void gradeSubmission(AssignmentSubmission submission, String gradeOption, String associateGradebookAssignment = a.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); String op = gradeOption.equals("remove") ? "remove" : "update"; - alerts.addAll(integrateGradebook(options, aReference, associateGradebookAssignment, null, null, null, -1, null, sReference, op, -1)); + + String siteId = a.getContext(); + + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(siteId); + + // This block is responsible for dividing between cases where "isGradebookGroupEnabled" + // is true and others where it is false. + if (!isGradebookGroupEnabled) { + // In this case, the "associateGradebookAssignment" association is unique, + // so no further action is needed. + alerts.addAll(integrateGradebook(options, siteId, aReference, associateGradebookAssignment, null, null, null, -1, null, sReference, op, -1)); + } else { + try { + // First, we need to retrieve the groups of the submitters of the submission. + // To do this, we will iterate through the collection of submitters and check + // with the users of each group in the site. + List groupList = new ArrayList<>(); + + Collection groupRefs = a.getGroups(); + Set submitterSet = submission.getSubmitters(); + + Site site = siteService.getSite(siteId); + + for (AssignmentSubmissionSubmitter ass : submitterSet) { + String submitterId = ass.getSubmitter(); + + for (String groupRef : groupRefs) { + Group group = site.getGroup(groupRef); + Set userList = group.getUsers(); + + if (userList != null && userList.size() >= 1 && userList.contains(submitterId)) { + groupList.add(group.getId()); + } + } + } + + for (String gradebookUid : groupList) { + // Since there is a possibility that the "associateGradebookAssignment" + // variable is comma-separated, we need to split it into a list. + List itemList = Arrays.asList(associateGradebookAssignment.split(",")); + + for (String item : itemList) { + // We need to check whether it is a reference or a gradebook item ID. + boolean isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, item); + + if (isExternalAssignmentDefined) { + // In this case, no further actions are required. + alerts.addAll(integrateGradebook(options, gradebookUid, aReference, item, null, null, null, -1, null, sReference, op, -1)); + } else { + // In this case, we need to find the item in the list that matches the group being iterated. + Long itemId = Long.parseLong(item); + + GradebookAssignment gradebookAssignment = gradingService.getGradebookAssigment(gradebookUid, itemId); + + if (gradebookAssignment != null && gradebookAssignment.getGradebook() != null && + gradebookAssignment.getGradebook().getUid().equals(gradebookUid)) { + alerts.addAll(integrateGradebook(options, gradebookUid, aReference, item, null, null, null, -1, null, sReference, op, -1)); + } + } + } + } + } catch (Exception ex) { + log.warn("Site not found [{}], {}", siteId, ex); + } + } } } // gradeSubmission @@ -440,13 +514,12 @@ private Instant getTimeFromOptions(Map options, String monthStri * @param submissionRef Any submission grade need to be updated? Do bulk update if null * @param updateRemoveSubmission "update" for update submission;"remove" for remove submission */ - List integrateGradebook(Map options, String assignmentRef, String associateGradebookAssignment, + List integrateGradebook(Map options, String gradebookUid, String assignmentRef, String associateGradebookAssignment, String addUpdateRemoveAssignment, String oldAssignment_title, String newAssignment_title, int newAssignment_maxPoints, Instant newAssignment_dueTime, String submissionRef, String updateRemoveSubmission, long category) { associateGradebookAssignment = StringUtils.trimToNull(associateGradebookAssignment); - // add or remove external grades to gradebook // a. if Gradebook does not exists, do nothing, 'cos setting should have been hidden // b. if Gradebook exists, just call addExternal and removeExternal and swallow any exception. The @@ -460,14 +533,17 @@ List integrateGradebook(Map options, String assignmentRe String submissionId = AssignmentReferenceReckoner.reckoner().reference(submissionRef).reckon().getId(); try { - String gradebookUid = (String) options.get("siteId"); - if (gradebookUid == null) { - gradebookUid = toolManager.getCurrentPlacement().getContext(); + String siteId = (String) options.get("siteId"); + if (siteId == null) { + siteId = toolManager.getCurrentPlacement().getContext(); } - if (gradingService.currentUserHasGradingPerm(gradebookUid)) { + if (gradebookUid == null) { + gradebookUid = siteId; + } + if (gradingService.currentUserHasGradingPerm(siteId)) { boolean isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, assignmentRef); boolean isExternalAssociateAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, associateGradebookAssignment); - boolean isAssignmentDefined = gradingService.isAssignmentDefined(gradebookUid, associateGradebookAssignment); + boolean isAssignmentDefined = gradingService.isAssignmentDefined(gradebookUid, siteId, associateGradebookAssignment); if (addUpdateRemoveAssignment != null) { Assignment a = assignmentService.getAssignment(assignmentId); @@ -477,7 +553,7 @@ List integrateGradebook(Map options, String assignmentRe // add assignment into gradebook try { // add assignment to gradebook - gradingService.addExternalAssessment(gradebookUid, assignmentRef, null, newAssignment_title, newAssignment_maxPoints / (double) a.getScaleFactor(), Date.from(newAssignment_dueTime), assignmentToolId, null, false, category != -1 ? category : null, assignmentRef); + gradingService.addExternalAssessment(gradebookUid, siteId, assignmentRef, null, newAssignment_title, newAssignment_maxPoints / (double) a.getScaleFactor(), Date.from(newAssignment_dueTime), assignmentToolId, null, false, category != -1 ? category : null, assignmentRef); } catch (AssignmentHasIllegalPointsException e) { alerts.add(rb.getString("addtogradebook.illegalPoints")); log.warn("integrateGradebook: {}", e.toString()); @@ -497,7 +573,7 @@ List integrateGradebook(Map options, String assignmentRe // if there is an external entry created in Gradebook based on this assignment, update it try { // update attributes if the GB assignment was created for the assignment - gradingService.updateExternalAssessment(gradebookUid, associateGradebookAssignment, null, null, newAssignment_title, newAssignment_maxPoints / (double) a.getScaleFactor(), Date.from(newAssignment_dueTime), false); + gradingService.updateExternalAssessment(gradebookUid, associateGradebookAssignment, null, null, newAssignment_title, null, newAssignment_maxPoints / (double) a.getScaleFactor(), Date.from(newAssignment_dueTime), false); } catch (Exception e) { alerts.add(rb.getFormattedMessage("cannotfin_assignment", assignmentRef)); log.warn("{}", rb.getFormattedMessage("cannotfin_assignment", assignmentRef)); @@ -547,26 +623,26 @@ else if ("remove".equals(addUpdateRemoveAssignment)) { if (associateGradebookAssignment != null) { if (isExternalAssociateAssignmentDefined) { // the associated assignment is externally maintained - gradingService.updateExternalAssessmentScoresString(gradebookUid, associateGradebookAssignment, sm); - gradingService.updateExternalAssessmentComments(gradebookUid, associateGradebookAssignment, cm); + gradingService.updateExternalAssessmentScoresString(gradebookUid, siteId, associateGradebookAssignment, sm); + gradingService.updateExternalAssessmentComments(gradebookUid, siteId, associateGradebookAssignment, cm); } else if (isAssignmentDefined) { - Long associateGradebookAssignmentId = gradingService.getAssignment(gradebookUid, associateGradebookAssignment).getId(); + Long associateGradebookAssignmentId = gradingService.getAssignment(gradebookUid, siteId, associateGradebookAssignment).getId(); // the associated assignment is internal one, update records one by one for (Map.Entry entry : sm.entrySet()) { String submitterId = (String) entry.getKey(); String grade = StringUtils.trimToNull(displayGrade((String) sm.get(submitterId), a.getScaleFactor())); - if (grade != null && gradingService.isUserAbleToGradeItemForStudent(gradebookUid, associateGradebookAssignmentId, submitterId)) { - gradingService.setAssignmentScoreString(gradebookUid, associateGradebookAssignmentId, submitterId, grade, ""); + if (grade != null) { + gradingService.setAssignmentScoreString(gradebookUid, siteId, associateGradebookAssignmentId, submitterId, grade, ""); String comment = StringUtils.isNotEmpty(cm.get(submitterId)) ? cm.get(submitterId) : ""; if (StringUtils.isNotBlank(comment)) { - gradingService.setAssignmentScoreComment(gradebookUid, associateGradebookAssignmentId, submitterId, comment); + gradingService.setAssignmentScoreComment(gradebookUid, associateGradebookAssignmentId, submitterId, comment); } } } } } else if (isExternalAssignmentDefined) { - gradingService.updateExternalAssessmentScoresString(gradebookUid, assignmentRef, sm); - gradingService.updateExternalAssessmentComments(gradebookUid, assignmentRef, cm); + gradingService.updateExternalAssessmentScoresString(gradebookUid, siteId, assignmentRef, sm); + gradingService.updateExternalAssessmentComments(gradebookUid, siteId, assignmentRef, cm); } } } else { @@ -581,27 +657,25 @@ else if ("remove".equals(addUpdateRemoveAssignment)) { //Gradebook only supports plaintext strings String commentString = formattedText.convertFormattedTextToPlaintext(aSubmission.getFeedbackComment()); if (associateGradebookAssignment != null) { - if (gradingService.isExternalAssignmentDefined(gradebookUid, associateGradebookAssignment)) { + if (isExternalAssociateAssignmentDefined) { // the associated assignment is externally maintained - gradingService.updateExternalAssessmentScore(gradebookUid, associateGradebookAssignment, submitter.getSubmitter(), + gradingService.updateExternalAssessmentScore(gradebookUid, siteId, associateGradebookAssignment, submitter.getSubmitter(), (gradeStringToUse != null && aSubmission.getGradeReleased()) ? gradeStringToUse : ""); - gradingService.updateExternalAssessmentComment(gradebookUid, associateGradebookAssignment, submitter.getSubmitter(), + gradingService.updateExternalAssessmentComment(gradebookUid, siteId, associateGradebookAssignment, submitter.getSubmitter(), (commentString != null && aSubmission.getGradeReleased()) ? commentString : ""); - } else if (gradingService.isAssignmentDefined(gradebookUid, associateGradebookAssignment)) { + } else if (isAssignmentDefined) { // the associated assignment is internal one, update records - final Long associateGradebookAssignmentId = gradingService.getAssignment(gradebookUid, associateGradebookAssignment).getId(); + final Long associateGradebookAssignmentId = gradingService.getAssignment(gradebookUid, siteId, associateGradebookAssignment).getId(); final String submitterId = submitter.getSubmitter(); - if (gradingService.isUserAbleToGradeItemForStudent(gradebookUid, associateGradebookAssignmentId, submitterId)) { - gradingService.setAssignmentScoreString(gradebookUid, associateGradebookAssignmentId, submitterId, - (gradeStringToUse != null && aSubmission.getGradeReleased()) ? gradeStringToUse : "", ""); - gradingService.setAssignmentScoreComment(gradebookUid, associateGradebookAssignmentId, submitterId, - (commentString != null && aSubmission.getGradeReleased()) ? commentString : ""); - } + gradingService.setAssignmentScoreString(gradebookUid, siteId, associateGradebookAssignmentId, submitterId, + (gradeStringToUse != null && aSubmission.getGradeReleased()) ? gradeStringToUse : "", ""); + gradingService.setAssignmentScoreComment(gradebookUid, associateGradebookAssignmentId, submitterId, + (commentString != null && aSubmission.getGradeReleased()) ? commentString : ""); } } else { - gradingService.updateExternalAssessmentScore(gradebookUid, assignmentRef, submitter.getSubmitter(), + gradingService.updateExternalAssessmentScore(gradebookUid, siteId, assignmentRef, submitter.getSubmitter(), (gradeStringToUse != null && aSubmission.getGradeReleased()) ? gradeStringToUse : ""); - gradingService.updateExternalAssessmentComment(gradebookUid, assignmentRef, submitter.getSubmitter(), + gradingService.updateExternalAssessmentComment(gradebookUid, siteId, assignmentRef, submitter.getSubmitter(), (commentString != null && aSubmission.getGradeReleased()) ? commentString : ""); } } @@ -621,18 +695,13 @@ else if ("remove".equals(addUpdateRemoveAssignment)) { for (User submitter :submitters) { if (isExternalAssociateAssignmentDefined) { // if the old associated assignment is an external maintained one - gradingService.updateExternalAssessmentScore(gradebookUid, associateGradebookAssignment, submitter.getId(), null); - } else if (isAssignmentDefined) { - final String submitterId = submitter.getId(); - final Long associateGradebookAssignmentId = gradingService.getAssignment(gradebookUid, associateGradebookAssignment).getId(); - if (gradingService.isUserAbleToGradeItemForStudent(gradebookUid, associateGradebookAssignmentId, submitterId)) { - gradingService.setAssignmentScoreString(gradebookUid, associateGradebookAssignment, submitter.getId(), "0", assignmentToolId); - } + gradingService.updateExternalAssessmentScore(gradebookUid, siteId, associateGradebookAssignment, submitter.getId(), null); } } } } } else { + // remove only one submission grade AssignmentSubmission aSubmission = assignmentService.getSubmission(submissionId); if (aSubmission != null) { @@ -640,14 +709,7 @@ else if ("remove".equals(addUpdateRemoveAssignment)) { for (User submitter :submitters) { if (isExternalAssociateAssignmentDefined) { // external assignment - gradingService.updateExternalAssessmentScore(gradebookUid, assignmentRef, submitter.getId(), null); - } else if (isAssignmentDefined) { - // gb assignment - final String submitterId = submitter.getId(); - final Long associateGradebookAssignmentId = gradingService.getAssignment(gradebookUid, associateGradebookAssignment).getId(); - if (gradingService.isUserAbleToGradeItemForStudent(gradebookUid, associateGradebookAssignmentId, submitterId)) { - gradingService.setAssignmentScoreString(gradebookUid, associateGradebookAssignment, submitter.getId(), "0", ""); - } + gradingService.updateExternalAssessmentScore(gradebookUid, siteId, assignmentRef, submitter.getId(), null); } } } @@ -666,7 +728,7 @@ else if ("remove".equals(addUpdateRemoveAssignment)) { */ public org.sakaiproject.grading.api.Assignment findGradeBookColumn(String gradebookUid, String assignmentName) { try { - return gradingService.getAssignmentByNameOrId(gradebookUid, assignmentName); + return gradingService.getAssignmentByNameOrId(gradebookUid, gradebookUid, assignmentName); } catch (AssessmentNotFoundException anfe) { return null; } @@ -772,13 +834,14 @@ private String displayGrade(String grade, Integer factor) { return assignmentService.getGradeDisplay(grade, Assignment.GradeType.SCORE_GRADE_TYPE, factor); } - private void removeNonAssociatedExternalGradebookEntry(String context, String assignmentReference, String associateGradebookAssignment, String gradebookUid) { + public void removeNonAssociatedExternalGradebookEntry(String context, String assignmentReference, String associateGradebookAssignment, String gradebookUid) { boolean isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, associateGradebookAssignment); if (isExternalAssignmentDefined) { boolean found = false; // iterate through all assignments currently in the site, see if any is associated with this GB entry for (Assignment assignment : assignmentService.getAssignmentsForContext(context)) { String reference = AssignmentReferenceReckoner.reckoner().assignment(assignment).reckon().getReference(); + if (StringUtils.equals(assignment.getProperties().get(PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT), associateGradebookAssignment) && !StringUtils.equals(reference, assignmentReference)) { found = true; @@ -787,7 +850,7 @@ private void removeNonAssociatedExternalGradebookEntry(String context, String as } // so if none of the assignment in this site is associated with the entry, remove the entry if (!found) { - gradingService.removeExternalAssignment(gradebookUid, associateGradebookAssignment); + gradingService.removeExternalAssignment(gradebookUid, associateGradebookAssignment, assignmentService.getToolId()); } } } @@ -828,4 +891,46 @@ public boolean hasRubricHiddenToStudent(String assignmentId) { return false; } + public String fillSelectedGradebook(String siteId, Long assignmentId, String selectedGradebook) { + GradebookAssignment gradebookAssignment = gradingService.getGradebookAssigment(siteId, assignmentId); + + if (gradebookAssignment != null) { + if (selectedGradebook.isBlank()) { + selectedGradebook += gradebookAssignment.getId().toString(); + } else { + selectedGradebook += ("," + gradebookAssignment.getId().toString()); + } + } + + return selectedGradebook; + } + + public void buildGradebookPointsMap(String gbUid, String siteId, String assignmentRef, Map gradebookPointsMap, String newCategoryString) { + Long catRef = -1L; + + List categoryDefinitions = gradingService.getCategoryDefinitions(gbUid, siteId); + if (!newCategoryString.equals("-1") || assignmentRef.isEmpty()) { + // nothing to do + } else { + for (CategoryDefinition categorie : categoryDefinitions) { + if (categorie.isAssignmentInThisCategory(assignmentRef)) { + catRef = categorie.getId(); + } + } + } + + if (catRef != -1) { + for (CategoryDefinition thisCategoryDefinition : categoryDefinitions) { + if (Objects.equals(thisCategoryDefinition.getId(), catRef)) { + if (thisCategoryDefinition.getDropKeepEnabled() && !thisCategoryDefinition.getEqualWeight()) { + Double thisCategoryPoints = thisCategoryDefinition.getPointsForCategory(); + if (thisCategoryPoints != null) { + gradebookPointsMap.put(gbUid, thisCategoryPoints); + } + } + } + } + } + } + } diff --git a/assignment/tool/src/java/org/sakaiproject/assignment/tool/RangeAndGroupsDelegate.java b/assignment/tool/src/java/org/sakaiproject/assignment/tool/RangeAndGroupsDelegate.java index 3aff8d225e16..0076331f37ec 100644 --- a/assignment/tool/src/java/org/sakaiproject/assignment/tool/RangeAndGroupsDelegate.java +++ b/assignment/tool/src/java/org/sakaiproject/assignment/tool/RangeAndGroupsDelegate.java @@ -38,6 +38,7 @@ import org.sakaiproject.cheftool.VelocityPortletPaneledAction; import org.sakaiproject.event.api.SessionState; import org.sakaiproject.exception.IdUnusedException; +import org.sakaiproject.grading.api.GradingService; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; @@ -68,10 +69,11 @@ class RangeAndGroupsDelegate private final SiteService siteService; private final SecurityService securityService; private final FormattedText formattedText; + private final GradingService gradingService; void buildInstructorNewEditAssignmentContextGroupCheck(Context context, Assignment asn) { - if (!asn.getIsGroup()) + if (!asn.getIsGroup() && !gradingService.isGradebookGroupEnabled(asn.getContext())) { return; } @@ -135,6 +137,8 @@ boolean setNewOrEditedAssignmentParameters(RunData data, SessionState state, Str else if (VALUE_ASSIGN_TO_INDIVIDUALS_FROM_GROUPS.equals(assignTo)) { range = Assignment.Access.GROUP.toString(); + } else if (VALUE_ASSIGN_TO_INDIVIDUALS.equals(assignTo) && gradingService.isGradebookGroupEnabled(siteId)) { + VelocityPortletPaneledAction.addAlert(state, rb.getFormattedMessage("group.sitegradebook.nopermission")); } state.setAttribute(NEW_ASSIGNMENT_GROUP_SUBMIT, groupAssignment ? "1" : "0"); @@ -176,7 +180,7 @@ else if (VALUE_ASSIGN_TO_INDIVIDUALS_FROM_GROUPS.equals(assignTo)) } // check groups for duplicate members - if (groupAssignment) + if (groupAssignment || gradingService.isGradebookGroupEnabled(siteId)) { List groupIds = Arrays.asList(ArrayUtils.nullToEmpty(data.getParameters().getStrings("selectedGroups"))); List dupes = assignmentService.checkAssignmentForUsersInMultipleGroups(siteId, groupsFromIds(siteId, groupIds)); @@ -298,7 +302,7 @@ Collection checkSubmissionForUsersInMultipleGroups(Assignment void buildStudentViewSubmissionContext(SessionState state, Context context, String userId, Assignment asn, AssignmentAction asnAct) { - if (!asn.getIsGroup()) + if (!asn.getIsGroup() && !gradingService.isGradebookGroupEnabled(asn.getContext())) { return; } @@ -322,7 +326,7 @@ void buildStudentViewSubmissionContext(SessionState state, Context context, Stri void buildStudentViewAssignmentContext(SessionState state, String userId, Assignment asn) { - if (asn.getIsGroup() && !validateUserGroups(state, userId, asn)) + if ((asn.getIsGroup() || gradingService.isGradebookGroupEnabled(asn.getContext())) && !validateUserGroups(state, userId, asn)) { VelocityPortletPaneledAction.addAlert(state, rb.getString("group.error.message")); } @@ -363,19 +367,22 @@ boolean validateUserGroups(SessionState state, String userId, Assignment asn) void buildInstructorGradeSubmissionContextGroupCheck(Optional asnOpt, String groupId, SessionState state) { - if (!asnOpt.isPresent() || !asnOpt.get().getIsGroup()) + if (!asnOpt.isPresent() || (!asnOpt.get().getIsGroup() && !gradingService.isGradebookGroupEnabled(asnOpt.get().getContext()))) { return; } Assignment asn = asnOpt.get(); Collection groups = groupsFromIds(asn.getContext(), Collections.singletonList(groupId)); - if (groups.isEmpty()) + if (gradingService.isGradebookGroupEnabled(asnOpt.get().getContext())) { + checkAssignmentForUsersInMultipleGroups(asn, state); + } else if (groups.isEmpty()) { log.error("Invalid group id {}", groupId); + } else { + checkSubmissionForUsersInMultipleGroups(asn, groups.stream().findAny().get(), state, true); } - checkSubmissionForUsersInMultipleGroups(asn, groups.stream().findAny().get(), state, true); } private Site getSite(Assignment asn) diff --git a/assignment/tool/src/webapp/WEB-INF/applicationContext.xml b/assignment/tool/src/webapp/WEB-INF/applicationContext.xml index 24ae29c51bb5..20c813e5681f 100644 --- a/assignment/tool/src/webapp/WEB-INF/applicationContext.xml +++ b/assignment/tool/src/webapp/WEB-INF/applicationContext.xml @@ -5,6 +5,7 @@ + diff --git a/assignment/tool/src/webapp/vm/assignment/chef_assignments_instructor_new_edit_assignment.vm b/assignment/tool/src/webapp/vm/assignment/chef_assignments_instructor_new_edit_assignment.vm index db6ce03b555b..93c1a093015f 100644 --- a/assignment/tool/src/webapp/vm/assignment/chef_assignments_instructor_new_edit_assignment.vm +++ b/assignment/tool/src/webapp/vm/assignment/chef_assignments_instructor_new_edit_assignment.vm @@ -37,6 +37,9 @@ #if ($!tagsEnabled && $!allowAddTags) window.syncTagSelectorInput("tag-selector", "tag_selector"); #end + #if ($!isGradebookGroupEnabled) + window.syncGbSelectorInput("gb-selector", "gb_selector"); + #end }); + ## Anonymous Grading (SAK-17606) #if( $enableAnonGrading || $value_CheckAnonymousGrading.equals("true") )
@@ -84,45 +93,65 @@ This section contains the options for grading this assignment, including rubrics $tlang.getString("grading.add")
- #if ($!value_totalCategories > 1) - ## show the "Category list" choices or not + - #end #end ## if there are assignment entries in Gradebook - #if (!$!gradebookAssignmentsLabel.isEmpty()) + #if (($isGradebookGroupEnabled && $existAnyItemGradebook) || + (!$isGradebookGroupEnabled && !$!gradebookAssignmentsLabel.isEmpty()))
## Associate with Existing Gradebook Item
- + + #if ($isGradebookGroupEnabled) + + + #elseif (!$isGradebookGroupEnabled) + + #end
#end diff --git a/basiclti/basiclti-blis/src/java/org/sakaiproject/lti13/LTI13Servlet.java b/basiclti/basiclti-blis/src/java/org/sakaiproject/lti13/LTI13Servlet.java index 5c370db506e2..a7af51ad76ad 100644 --- a/basiclti/basiclti-blis/src/java/org/sakaiproject/lti13/LTI13Servlet.java +++ b/basiclti/basiclti-blis/src/java/org/sakaiproject/lti13/LTI13Servlet.java @@ -2408,7 +2408,7 @@ private void resultsForAssignment(String signed_placement, Site site, Assignment response.setContentType(Result.CONTENT_TYPE_CONTAINER); // Look up the assignment so we can find the max points - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); Session sess = SessionManager.getCurrentSession(); @@ -2465,7 +2465,7 @@ private void resultsForAssignment(String signed_placement, Site site, Assignment } try { - CommentDefinition commentDef = g.getAssignmentScoreComment(context_id, a.getId(), user.getId()); + CommentDefinition commentDef = gradingService.getAssignmentScoreComment(context_id, a.getId(), user.getId()); if (commentDef != null) { result.comment = commentDef.getCommentText(); } @@ -2477,7 +2477,7 @@ private void resultsForAssignment(String signed_placement, Site site, Assignment String actualGrade = null; result.resultScore = null; try { - actualGrade = g.getAssignmentScoreString(context_id, a.getId(), user.getId()); + actualGrade = gradingService.getAssignmentScoreString(context_id, context_id, a.getId(), user.getId()); } catch(AssessmentNotFoundException e) { log.error(e.getMessage(), e); // Unexpected break; diff --git a/basiclti/basiclti-common/src/java/org/sakaiproject/basiclti/util/SakaiBLTIUtil.java b/basiclti/basiclti-common/src/java/org/sakaiproject/basiclti/util/SakaiBLTIUtil.java index 6bc0011d080f..c3b23ebaa6ac 100644 --- a/basiclti/basiclti-common/src/java/org/sakaiproject/basiclti/util/SakaiBLTIUtil.java +++ b/basiclti/basiclti-common/src/java/org/sakaiproject/basiclti/util/SakaiBLTIUtil.java @@ -64,6 +64,7 @@ import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.event.cover.UsageSessionService; import org.sakaiproject.exception.IdUnusedException; +import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.linktool.LinkToolUtil; import org.sakaiproject.lti.api.LTIService; import org.sakaiproject.portal.util.CSSUtils; @@ -75,6 +76,7 @@ import org.sakaiproject.grading.api.CommentDefinition; import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.site.cover.SiteService; @@ -1163,8 +1165,14 @@ public static String[] postLaunchHTML(Map content, Map gradebookUids = Arrays.asList(context); + if (gradingService.isGradebookGroupEnabled(context)) { + gradebookUids = gradingService.getGradebookGroupInstancesIds(context); + } + for (String gradebookUid : gradebookUids) { + Gradebook gb = gradingService.getGradebook(gradebookUid, context); + } // See if there are the necessary items String secret = getSecret(tool, content); @@ -1563,8 +1571,14 @@ public static String[] postContentItemSelectionRequest(Long toolKey, Map gradebookUids = Arrays.asList(context); + if (gradingService.isGradebookGroupEnabled(context)) { + gradebookUids = gradingService.getGradebookGroupInstancesIds(context); + } + for (String gradebookUid : gradebookUids) { + Gradebook gb = gradingService.getGradebook(gradebookUid, context); + } User user = UserDirectoryService.getCurrentUser(); @@ -2501,7 +2515,7 @@ private static Object handleGradebook(String sourcedid, HttpServletRequest reque } // Look up the gradebook column so we can find the max points - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); // Make sure the user exists in the site @@ -2566,13 +2580,13 @@ private static Object handleGradebook(String sourcedid, HttpServletRequest reque sess.setUserId(gb_user_id); sess.setUserEid(gb_user_eid); if (isRead) { - String actualGrade = g.getAssignmentScoreString(siteId, gradebookColumn.getId(), user_id); + String actualGrade = gradingService.getAssignmentScoreString(gradebookColumn.getGradebookUid(), siteId, gradebookColumn.getId(), user_id); Double dGrade = null; if (StringUtils.isNotBlank(actualGrade)) { dGrade = new Double(actualGrade); dGrade = dGrade / gradebookColumn.getPoints(); } - CommentDefinition commentDef = g.getAssignmentScoreComment(siteId, gradebookColumn.getId(), user_id); + CommentDefinition commentDef = gradingService.getAssignmentScoreComment(gradebookColumn.getGradebookUid(), gradebookColumn.getId(), user_id); Map retMap = new TreeMap<>(); retMap.put("grade", dGrade); if (commentDef != null) { @@ -2580,21 +2594,21 @@ private static Object handleGradebook(String sourcedid, HttpServletRequest reque } retval = retMap; } else if (isDelete) { - g.setAssignmentScoreString(siteId,gradebookColumn.getId(), user_id, null, "External Outcome"); - g.deleteAssignmentScoreComment(siteId, gradebookColumn.getId(), user_id); - log.info("Delete Score site={} title={} user_id={}", siteId, title, user_id); + gradingService.setAssignmentScoreString(gradebookColumn.getGradebookUid(), siteId, gradebookColumn.getId(), user_id, null, "External Outcome"); + gradingService.deleteAssignmentScoreComment(gradebookColumn.getGradebookUid(), gradebookColumn.getId(), user_id); + log.info("Delete Score site={} gradebook={} title={} user_id={}", siteId, gradebookColumn.getGradebookUid(), title, user_id); retval = Boolean.TRUE; } else { String gradeI18n = getRoundedGrade(scoreGiven, gradebookColumn.getPoints()); gradeI18n = (",").equals((ComponentManager.get(FormattedText.class)).getDecimalSeparator()) ? gradeI18n.replace(".",",") : gradeI18n; - g.setAssignmentScoreString(siteId, gradebookColumn.getId(), user_id, gradeI18n, "External Outcome"); + gradingService.setAssignmentScoreString(gradebookColumn.getGradebookUid(), siteId, gradebookColumn.getId(), user_id, gradeI18n, "External Outcome"); if ( StringUtils.isBlank(comment) ) { - g.deleteAssignmentScoreComment(siteId, gradebookColumn.getId(), user_id); + gradingService.deleteAssignmentScoreComment(gradebookColumn.getGradebookUid(), gradebookColumn.getId(), user_id); } else { - g.setAssignmentScoreComment(siteId, gradebookColumn.getId(), user_id, comment); + gradingService.setAssignmentScoreComment(gradebookColumn.getGradebookUid(), gradebookColumn.getId(), user_id, comment); } - log.info("Stored Score={} title={} user_id={} score={}", siteId, title, user_id, scoreGiven); + log.info("Stored Score site={} gradebook={} title={} user_id={} score={}", siteId, gradebookColumn.getGradebookUid(), title, user_id, scoreGiven); retval = Boolean.TRUE; } @@ -2661,7 +2675,7 @@ public static Object handleGradebookLTI13(Site site, Long tool_id, Map userGradebooks = Arrays.asList(siteId); + if (gradingService.isGradebookGroupEnabled(siteId)) { + userGradebooks = gradingService.getGradebookInstancesForUser(siteId, userId); + returnGradebookUid = userGradebooks.get(0); + } + for (String gradebookUid : userGradebooks) { + List gradebookColumns = gradingService.getAssignments(gradebookUid, siteId, SortType.SORT_BY_NONE); + for (org.sakaiproject.grading.api.Assignment aColumn : gradebookColumns) { + if (title.trim().equalsIgnoreCase(aColumn.getName().trim())) { + returnColumn = aColumn; + returnGradebookUid = gradebookUid; + break; + } } } } finally { @@ -2907,8 +2927,9 @@ public static org.sakaiproject.grading.api.Assignment getGradebookColumn(Site si Boolean includeInComputation = lineItem.includeInComputation == null ? Boolean.TRUE : lineItem.includeInComputation; // Default true returnColumn.setReleased(releaseToStudent); // default true returnColumn.setUngraded(! includeInComputation); // default false - Long gradebookColumnId = g.addAssignment(siteId, returnColumn); + Long gradebookColumnId = gradingService.addAssignment(returnGradebookUid, siteId, returnColumn); returnColumn.setId(gradebookColumnId); + returnColumn.setGradebookUid(returnGradebookUid); log.info("Added gradebook column: {} with Id: {}", title, gradebookColumnId); } catch (ConflictingAssignmentNameException e) { log.warn("ConflictingAssignmentNameException while adding gradebook column {}", e.getMessage()); diff --git a/basiclti/basiclti-common/src/java/org/sakaiproject/lti13/LineItemUtil.java b/basiclti/basiclti-common/src/java/org/sakaiproject/lti13/LineItemUtil.java index 54ad948a7cad..1b1b1f9db2f8 100644 --- a/basiclti/basiclti-common/src/java/org/sakaiproject/lti13/LineItemUtil.java +++ b/basiclti/basiclti-common/src/java/org/sakaiproject/lti13/LineItemUtil.java @@ -48,6 +48,7 @@ import org.sakaiproject.grading.api.GradingService; import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.lti13.util.SakaiLineItem; import static org.tsugi.basiclti.BasicLTIUtil.getObject; @@ -145,7 +146,7 @@ public static Assignment createLineItem(Site site, Long tool_id, Map content, SakaiLineItem lineItem) { // Look up the assignment so we can find the max points - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); if (lineItem.scoreMaximum == null) { @@ -207,11 +208,11 @@ public static Assignment createLineItem(String context_id, Long tool_id, Map getColumnsForToolDAO(String context_id, Long tool_id) { List retval = new ArrayList(); - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); pushAdvisor(); try { - List gradebookColumns = g.getAssignments(context_id); + List gradebookColumns = gradingService.getAssignments(context_id, context_id, SortType.SORT_BY_NONE); for (Iterator i = gradebookColumns.iterator(); i.hasNext();) { Assignment gbColumn = (Assignment) i.next(); if ( ! isGradebookColumnLTI(gbColumn) ) continue; @@ -334,12 +335,12 @@ protected static List getColumnsForToolDAO(String context_id, Long t */ protected static List getColumnsForContextDAO(String context_id) { List retval = new ArrayList(); - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); pushAdvisor(); try { - List gradebookColumns = g.getAssignments(context_id); + List gradebookColumns = gradingService.getAssignments(context_id, context_id, SortType.SORT_BY_NONE); return gradebookColumns; } catch (Throwable e) { log.error("Unexpected Throwable", e.getMessage()); @@ -376,13 +377,13 @@ public static Assignment getColumnByKeyDAO(String context_id, Long tool_id, Long */ protected static Assignment getColumnByLabelDAO(String context_id, Long tool_id, String column_label) { - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); Assignment retval = null; pushAdvisor(); try { - List gradebookColumns = g.getAssignments(context_id); + List gradebookColumns = gradingService.getAssignments(context_id, context_id, SortType.SORT_BY_NONE); for (Iterator i = gradebookColumns.iterator(); i.hasNext();) { Assignment gbColumn = (Assignment) i.next(); if ( ! isGradebookColumnLTI(gbColumn) ) continue; @@ -413,13 +414,13 @@ protected static boolean deleteAssignmentByKeyDAO(String context_id, Long tool_i // Make sure it belongs to us Assignment a = getColumnByKeyDAO(context_id, tool_id, column_id); if ( a == null ) return false; - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); pushAdvisor(); try { // Provides us no return value - g.removeAssignment(column_id); + gradingService.removeAssignment(column_id); } finally { popAdvisor(); } @@ -450,14 +451,14 @@ public static List getLineItemsForTool(String signed_placement, S if ( tool_id == null ) { throw new RuntimeException("tool_id is required"); } - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); List retval = new ArrayList<>(); pushAdvisor(); try { - List gradebookColumns = g.getAssignments(context_id); + List gradebookColumns = gradingService.getAssignments(context_id, context_id, SortType.SORT_BY_NONE); for (Iterator i = gradebookColumns.iterator(); i.hasNext();) { Assignment gbColumn = (Assignment) i.next(); if ( ! isGradebookColumnLTI(gbColumn) ) continue; diff --git a/basiclti/basiclti-portlet/src/java/org/sakaiproject/portlets/IMSBLTIPortlet.java b/basiclti/basiclti-portlet/src/java/org/sakaiproject/portlets/IMSBLTIPortlet.java index 156d3d39e957..a53612e711ae 100644 --- a/basiclti/basiclti-portlet/src/java/org/sakaiproject/portlets/IMSBLTIPortlet.java +++ b/basiclti/basiclti-portlet/src/java/org/sakaiproject/portlets/IMSBLTIPortlet.java @@ -69,6 +69,7 @@ import org.sakaiproject.grading.api.Assignment; import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SitePage; import org.sakaiproject.site.api.ToolConfiguration; @@ -869,10 +870,9 @@ protected boolean addGradeBookItem(ActionRequest request, String assignmentName) { try { - GradingService g = (GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); + GradingService gradingService = (GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); - String gradebookUid = getContext(); - if ( ! ((g.currentUserHasEditPerm(gradebookUid) || g.currentUserHasGradingPerm(gradebookUid)) && g.currentUserHasGradeAllPerm(gradebookUid) ) ) return false; + if ( ! ((gradingService.currentUserHasEditPerm(getContext()) || gradingService.currentUserHasGradingPerm(getContext())) && gradingService.currentUserHasGradeAllPerm(getContext()) ) ) return false; // add assignment to gradebook Assignment asn = new Assignment(); @@ -881,7 +881,8 @@ protected boolean addGradeBookItem(ActionRequest request, String assignmentName) asn.setName(assignmentName); asn.setReleased(true); asn.setUngraded(false); - g.addAssignment(gradebookUid, asn); + String gradebookUid = getContext(); + gradingService.addAssignment(gradebookUid, getContext(), asn); return true; } catch (ConflictingAssignmentNameException e) @@ -901,12 +902,12 @@ protected boolean addGradeBookItem(ActionRequest request, String assignmentName) protected List getGradeBookAssignments() { List retval = new ArrayList(); - GradingService g = (GradingService) ComponentManager + GradingService gradingService = (GradingService) ComponentManager .get("org.sakaiproject.grading.api.GradingService"); + if ( ! ((gradingService.currentUserHasEditPerm(getContext()) || gradingService.currentUserHasGradingPerm(getContext())) && gradingService.currentUserHasGradeAllPerm(getContext()) ) ) return null; String gradebookUid = getContext(); - if ( ! ((g.currentUserHasEditPerm(gradebookUid) || g.currentUserHasGradingPerm(gradebookUid)) && g.currentUserHasGradeAllPerm(gradebookUid) ) ) return null; - List gradebookAssignments = g.getAssignments(gradebookUid); + List gradebookAssignments = gradingService.getAssignments(gradebookUid, getContext(), SortType.SORT_BY_NONE); // filtering out anything externally provided for (Iterator i=gradebookAssignments.iterator(); i.hasNext();) diff --git a/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties b/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties index 84b9ffb71bea..645ae0957be9 100644 --- a/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties +++ b/config/configuration/bundles/src/bundle/org/sakaiproject/config/bundle/default.sakai.properties @@ -1951,6 +1951,10 @@ # DEFAULT: false # gradebookng.allowColumnResizing=true +# S2U-26: Turn on multiple gradebook instances for groups +# DEFAULT: false +# gradebookng.multipleGroupInstances=true + # SAK-46075: max upload file size, defined in megabytes # DEFAULT: 2 # gradebook.import.maxSize=3 @@ -5615,20 +5619,6 @@ # START CLOUD STORAGE IMPLEMENTATIONS # ############################### -# ONEDRIVE INTEGRATION -# # -# Allows you to enable the OneDrive integration -# DEFAULT: onedrive.enabled=false -# onedrive.enabled=true -# # -# Related configuration for OneDrive integration: client id, secret and redirect url -# onedrive.client_id=--CLIENT_ID-- -# onedrive.client_secret=--SECRET-- -# onedrive.redirect_uri=${serverUrl}/sakai-onedrive-tool - -# If you set up the Microsoft app as single-tenant, you will need to specify your endpoint_uri with your Microsoft tenant ID -# onedrive.endpoint_uri=https://login.microsoftonline.com/{TenantID}/oauth2/v2.0/ - # GOOGLEDRIVE INTEGRATION # Allows you to enable the Google Drive integration diff --git a/content-review/impl/turnitin/src/main/java/org/sakaiproject/contentreview/turnitin/TurnitinReviewServiceImpl.java b/content-review/impl/turnitin/src/main/java/org/sakaiproject/contentreview/turnitin/TurnitinReviewServiceImpl.java index 6620dbfcf71b..61b5e337432d 100644 --- a/content-review/impl/turnitin/src/main/java/org/sakaiproject/contentreview/turnitin/TurnitinReviewServiceImpl.java +++ b/content-review/impl/turnitin/src/main/java/org/sakaiproject/contentreview/turnitin/TurnitinReviewServiceImpl.java @@ -69,6 +69,7 @@ import org.sakaiproject.exception.TypeException; import org.sakaiproject.grading.api.Assignment; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.tool.api.Session; @@ -570,11 +571,19 @@ public Assignment getAssociatedGbItem(Map data) { SecurityAdvisor advisor = pushAdvisor(); try { - List allGbItems = gradingService.getAssignments(siteId); + List gradebookUids = Arrays.asList(siteId); + if (gradingService.isGradebookGroupEnabled(siteId)) { + gradebookUids = gradingService.getGradebookGroupInstancesIds(siteId); + } + List allGbItems = new ArrayList<>(); + for (String gradebookUid : gradebookUids) { + allGbItems.addAll(gradingService.getAssignments(gradebookUid, siteId, SortType.SORT_BY_NONE)); + } for (Assignment assign : allGbItems) { // Match based on External ID / Assignment title if (taskId.equals(assign.getExternalId()) || assign.getName().equals(taskTitle)) { assignment = assign; + break; } } } finally { @@ -737,12 +746,19 @@ public boolean writeGrade(Assignment assignment, Map data, HashM try { if (grade != null) { try { + List gradebookUids = Arrays.asList(siteId); + if (gradingService.isGradebookGroupEnabled(siteId)) { + gradebookUids = gradingService.getGradebookGroupInstancesIds(siteId); + } if (data.containsKey("assignment1")) { - gradingService.updateExternalAssessmentScore(siteId, - assignment.getExternalId(), tiiExternalId, grade); + for (String gradebookUid : gradebookUids) { + gradingService.updateExternalAssessmentScore(gradebookUid, siteId, assignment.getExternalId(), tiiExternalId, grade); + } } else { - gradingService.setAssignmentScoreString(siteId, data.get("taskTitle").toString(), - tiiExternalId, grade, "SYNC"); + for (String gradebookUid : gradebookUids) { + Assignment a = gradingService.getAssignmentByNameOrId(gradebookUid, siteId, data.get("taskTitle").toString()); + gradingService.setAssignmentScoreString(gradebookUid, siteId, a.getId(), tiiExternalId, grade, "SYNC"); + } } log.info("UPDATED GRADE (" + grade + ") FOR USER (" + tiiExternalId + ") IN ASSIGNMENT (" + assignment.getName() + ")"); diff --git a/edu-services/sections-service/sections-impl/sakai/model/src/java/org/sakaiproject/component/section/sakai/facade/SakaiUtil.java b/edu-services/sections-service/sections-impl/sakai/model/src/java/org/sakaiproject/component/section/sakai/facade/SakaiUtil.java index 7321eced2943..b5390161bdc8 100644 --- a/edu-services/sections-service/sections-impl/sakai/model/src/java/org/sakaiproject/component/section/sakai/facade/SakaiUtil.java +++ b/edu-services/sections-service/sections-impl/sakai/model/src/java/org/sakaiproject/component/section/sakai/facade/SakaiUtil.java @@ -24,9 +24,6 @@ import org.sakaiproject.section.api.coursemanagement.User; import org.sakaiproject.component.section.sakai.UserImpl; -import org.sakaiproject.site.cover.SiteService; -import org.sakaiproject.tool.api.Placement; -import org.sakaiproject.tool.cover.ToolManager; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.user.cover.UserDirectoryService; @@ -62,13 +59,5 @@ public static final User convertUser(final org.sakaiproject.user.api.User sakaiU sakaiUser.getSortName(), sakaiUser.getId()); return user; } - - /** - * @return The current sakai authz reference - */ - public static final String getSiteReference() { - Placement placement = ToolManager.getCurrentPlacement(); - String context = placement.getContext(); - return SiteService.siteReference(context); - } + } diff --git a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/Assignment.java b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/Assignment.java index d0c752c5c75a..f75d86e7d140 100644 --- a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/Assignment.java +++ b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/Assignment.java @@ -140,6 +140,9 @@ public class Assignment implements Serializable, Comparable { @Getter @Setter private String gradebookId; + @Getter + @Setter + private String gradebookUid; @Override public int compareTo(final Assignment o) { diff --git a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingAuthz.java b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingAuthz.java index 513a00509c4c..28cf5cf77d43 100644 --- a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingAuthz.java +++ b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingAuthz.java @@ -34,50 +34,54 @@ public interface GradingAuthz { PERMISSION_VIEW_OWN_GRADES = "gradebook.viewOwnGrades", PERMISSION_VIEW_STUDENT_NUMBERS = "gradebook.viewStudentNumbers"; - public boolean isUserAbleToGrade(String gradebookUid); - public boolean isUserAbleToGrade(String gradebookUid, String userUid); - public boolean isUserAbleToGradeAll(String gradebookUid); - public boolean isUserAbleToGradeAll(String gradebookUid, String userUid); - public boolean isUserAbleToEditAssessments(String gradebookUid); - public boolean isUserAbleToViewOwnGrades(String gradebookUid); - public boolean isUserAbleToViewStudentNumbers(String gradebookUid); + public boolean isUserAbleToGrade(String siteId); + public boolean isUserAbleToGrade(String siteId, String userUid); + public boolean isUserAbleToGradeAll(String siteId); + public boolean isUserAbleToGradeAll(String siteId, String userUid); + public boolean isUserAbleToEditAssessments(String siteId); + public boolean isUserAbleToViewOwnGrades(String siteId); + public boolean isUserAbleToViewStudentNumbers(String siteId); /** * * @param gradebookUid + * @param siteId * @param itemId * @param studentUid * @return is user authorized to grade this gradebook item for this student? * first checks for special grader perms. if none, uses default perms */ - public boolean isUserAbleToGradeItemForStudent(String gradebookUid, Long itemId, String studentUid) throws IllegalArgumentException; + public boolean isUserAbleToGradeItemForStudent(String gradebookUid, String siteId, Long itemId, String studentUid) throws IllegalArgumentException; /** * * @param gradebookUid + * @param siteId * @param itemId * @param studentUid * @return is user authorized to view this gradebook item for this student? * first checks for special grader perms. if none, uses default perms */ - public boolean isUserAbleToViewItemForStudent(String gradebookUid, Long itemId, String studentUid) throws IllegalArgumentException; + public boolean isUserAbleToViewItemForStudent(String gradebookUid, String siteId, Long itemId, String studentUid) throws IllegalArgumentException; /** - * @param gradebookUid + * @param siteId * @return all of the CourseSections for this site */ - public List getAllSections(String gradebookUid); + public List getAllSections(String siteId); /** * * @param gradebookUid + * @param siteId * @return all CourseSections that the current user may view or grade */ - public List getViewableSections(String gradebookUid); + public List getViewableSections(String gradebookUid, String siteId); /** - * @param gradebookUid * @param userUid + * @param gradebookUid + * @param siteId * @param categoryId * The category id that the desired item is associated with * @param gbCategoryType @@ -90,11 +94,12 @@ public interface GradingAuthz { * @return a map of EnrollmentRecords to grade/view permission that the given user is authorized to * view or grade for the given gradebook item */ - public Map findMatchingEnrollmentsForItemForUser(String userUid, String gradebookUid, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid); + public Map findMatchingEnrollmentsForItemForUser(String userUid, String gradebookUid, String siteId, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid); /** * * @param gradebookUid + * @param siteId * @param categoryId * The category id that the desired item is associated with * @param gbCategoryType @@ -107,44 +112,16 @@ public interface GradingAuthz { * @return a map of EnrollmentRecords to grade/view permission that the current user is authorized to * view or grade for the given gradebook item */ - public Map findMatchingEnrollmentsForItem(String gradebookUid, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid); - - /** - * - * @param gradebookUid - * @param gbCategoryType - * The category type setting for this gradebook - * @param optionalSearchString - * @param optionalSectionUid - * @return Map of EnrollmentRecord --> function (grade/view) for all students that the current user has permission to - * view/grade every item in the gradebook. If he/she can grade everything, GRADE function is - * returned. Otherwise, function is VIEW. May only modify course grade if he/she can grade - * everything in the gradebook for that student. If he/she can grade only a subset of the items, the - * student is not returned. - */ - public Map findMatchingEnrollmentsForViewableCourseGrade(String gradebookUid, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid); - /** - * - * @param gradebookUid - * @param allGbItems - * List of all Assignments associated with this gradebook - * @param optionalSearchString - * a substring search for student name or display UID; the exact rules are - * up to the implementation - leave null to use all students - * @param optionalSectionUid - * null if the search should be made across all sections - * @return a map of EnrollmentRecords to a map of item id and function (grade/view) that the user is - * authorized to view/grade - */ - public Map> findMatchingEnrollmentsForViewableItems(String gradebookUid, List allGbItems, String optionalSearchString, String optionalSectionUid); + public Map findMatchingEnrollmentsForItem(String gradebookUid, String siteId, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid); /** * Check to see if current user may grade or view the given student for the given item in the given gradebook. * Returns string representation of function per GradingService vars (view/grade) or null if no permission * @param gradebookUid + * @param siteId * @param itemId * @param studentUid * @return GradingService.gradePermission, GradingService.viewPermission, or null if no permission */ - public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, Long itemId, String studentUid); + public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, String siteId, Long itemId, String studentUid); } diff --git a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingPersistenceManager.java b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingPersistenceManager.java index beda61d4b71d..b3395407c145 100644 --- a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingPersistenceManager.java +++ b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingPersistenceManager.java @@ -70,6 +70,7 @@ public interface GradingPersistenceManager { Long countAssignmentsByNameAndGradebookUid(String name, String gradebookUid); Long countDuplicateAssignments(GradebookAssignment assignment); Optional getExternalAssignment(String gradebookUid, String externalId); + List getGradebookUidByExternalId(String externalId); GradebookAssignment saveGradebookAssignment(GradebookAssignment assignment); Optional getInternalComment(String studentUid, String gradebookUid, Long assignmentId); diff --git a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingService.java b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingService.java index 467ad539b699..97725d9b2ea4 100644 --- a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingService.java +++ b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/GradingService.java @@ -32,12 +32,15 @@ import java.util.Set; import org.sakaiproject.grading.api.model.Category; +import org.sakaiproject.grading.api.model.CourseGrade; import org.sakaiproject.grading.api.model.Gradebook; +import org.sakaiproject.grading.api.model.GradebookAssignment; import org.sakaiproject.grading.api.model.GradingEvent; import org.sakaiproject.grading.api.model.GradingScale; import org.sakaiproject.section.api.coursemanagement.CourseSection; import org.apache.commons.lang3.StringUtils; +import org.hibernate.HibernateException; import org.sakaiproject.entity.api.EntityProducer; /** @@ -55,74 +58,11 @@ public interface GradingService extends EntityProducer { public static final MathContext MATH_CONTEXT = new MathContext(10, RoundingMode.HALF_DOWN); - /** - * An enum for defining valid/invalid information for a points possible/relative weight value for a gradebook item. See - * {@link GradingService#isPointsPossibleValid(String, Assignment, Double)} for usage - */ - public enum PointsPossibleValidation { - /** - * The points possible/relative weight is valid - */ - VALID, - /** - * The points possible/relative weight is invalid because it is null and a value is required. - */ - INVALID_NULL_VALUE, - /** - * The points possible/relative weight is invalid because it is a value <= 0 - */ - INVALID_NUMERIC_VALUE, - /** - * The points possible/relative weight is invalid because it contains more than 2 decimal places - */ - INVALID_DECIMAL - } - /** * Array of chars that are not allowed at the beginning of a gb item title */ public static final String[] INVALID_CHARS_AT_START_OF_GB_ITEM_NAME = { "#", "*", "[" }; - /** - * Comparator to ensure correct ordering of letter grades, catering for + and - in the grade This is duplicated in GradebookNG. If - * changing here, please change there as well. TODO combine them - */ - public static Comparator lettergradeComparator = new Comparator() { - @Override - public int compare(String o1, String o2) { - if (o1.toLowerCase().charAt(0) == o2.toLowerCase().charAt(0)) { - // only take the first 2 chars, to cater for GradePointsMapping as well - String s1 = StringUtils.trim(StringUtils.left(o1, 2)); - String s2 = StringUtils.trim(StringUtils.left(o2, 2)); - - if (s1.length() == 2 && s2.length() == 2) { - if (s1.charAt(1) == '+') { - return -1; // SAK-30094 - } else { - return 1; - } - } - if (s1.length() == 1 && s2.length() == 2) { - if (o2.charAt(1) == '+') { - return 1; // SAK-30094 - } else { - return -1; - } - } - if (s1.length() == 2 && s2.length() == 1) { - if (s1.charAt(1) == '+') { - return -1; // SAK-30094 - } else { - return 1; - } - } - return 0; - } else { - return o1.toLowerCase().compareTo(o2.toLowerCase()); - } - } - }; - /** * Check to see if the current user is allowed to view the list of gradebook assignments. * @@ -130,64 +70,40 @@ public int compare(String o1, String o2) { */ public boolean isUserAbleToViewAssignments(String gradebookUid); - /** - * Check to see if the current user is allowed to grade the given item for the given student in the given gradebook. This will give - * clients a chance to avoid a security exception. - * - * @param gradebookUid - * @param assignmentId - * @param studentUid - */ - public boolean isUserAbleToGradeItemForStudent(String gradebookUid, Long assignmentId, String studentUid); - - /** - * Check to see if the current user is allowed to view the given item for the given student in the given gradebook. This will give - * clients a chance to avoid a security exception. - * - * @param gradebookUid - * @param assignmentId - * @param studentUid - * @return - */ - public boolean isUserAbleToViewItemForStudent(String gradebookUid, Long assignmentId, String studentUid); - /** * Check to see if current user may grade or view the given student for the given item in the given gradebook. Returns string * representation of function per GradingService vars (view/grade) or null if no permission * * @param gradebookUid + * @param siteId * @param assignmentId * @param studentUid * @return GradingService.gradePermission, GradingService.viewPermission, or null if no permission */ - public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, Long assignmentId, String studentUid); - - - /** - * @return Returns a list of Assignment objects describing the assignments that are currently defined in the given gradebook. - */ - public List getAssignments(String gradebookUid); + public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, String siteId, Long assignmentId, String studentUid); /** * @return Returns a list of Assignment objects describing the assignments that are currently defined in the given gradebook, sorted by * the given sort type. */ - public List getAssignments(String gradebookUid, SortType sortBy); + public List getAssignments(String gradebookUid, String siteId, SortType sortBy); /** * Get an assignment based on its id * * @param gradebookUid + * @param siteId * @param assignmentId * @return the associated Assignment with the given assignmentId * @throws AssessmentNotFoundException */ - public Assignment getAssignment(String gradebookUid, Long assignmentId) throws AssessmentNotFoundException; + public Assignment getAssignment(String gradebookUid, String siteId, Long assignmentId) throws AssessmentNotFoundException; /** * Get an assignment based on its name. This is provided for backward compatibility only. * * @param gradebookUid + * @param siteId * @param assignmentName * @return the associated Assignment with the given name * @throws AssessmentNotFoundException @@ -195,10 +111,11 @@ public int compare(String o1, String o2) { * @deprecated Use {@link #getAssignment(String,Long)} instead. */ @Deprecated - public Assignment getAssignment(String gradebookUid, String assignmentName) + public Assignment getAssignment(String gradebookUid, String siteId, String assignmentName) throws AssessmentNotFoundException; public Assignment getExternalAssignment(String gradebookUid, String externalId); + public List getGradebookUidByExternalId(String externalId); /** * Get an assignment based on its name or id. This is intended as a migration path from the deprecated @@ -208,24 +125,26 @@ public Assignment getAssignment(String gradebookUid, String assignmentName) * {@link #getAssignment(String,Long)} if you always can use the Long instead. * * @param gradebookUid + * @param siteId * @param assignmentName * @return the associated Assignment with the given name * @throws AssessmentNotFoundException * */ - public Assignment getAssignmentByNameOrId(String gradebookUid, String assignmentName) + public Assignment getAssignmentByNameOrId(String gradebookUid, String siteId, String assignmentName) throws AssessmentNotFoundException; /** * * @param gradebookUid + * @param siteId * @param assignmentId * @param studentUid * @return Returns a GradeDefinition for the student, respecting the grade entry type for the gradebook (ie in %, letter grade, or * points format). Returns null if no grade * @throws AssessmentNotFoundException */ - public GradeDefinition getGradeDefinitionForStudentForItem(String gradebookUid, + public GradeDefinition getGradeDefinitionForStudentForItem(String gradebookUid, String siteId, Long assignmentId, String studentUid) throws AssessmentNotFoundException; @@ -282,7 +201,7 @@ public void deleteAssignmentScoreComment(String gradebookUid, Long assignmentId, * This is not deprecated as we currently need the ability to check for duplciate assignment names in the given gradebook * */ - public boolean isAssignmentDefined(String gradebookUid, String assignmentTitle); + public boolean isAssignmentDefined(String gradebookUid, String siteId, String assignmentTitle); /** * Transfer the gradebook information and assignments from one gradebook to another @@ -297,11 +216,12 @@ public Map transferGradebook(GradebookInformation gradebookInform /** * * @param gradebookUid + * @param siteId * @return a {@link GradebookInformation} object that contains information about this Gradebook that may be useful to consumers outside * the Gradebook tool * */ - public GradebookInformation getGradebookInformation(String gradebookUid); + public GradebookInformation getGradebookInformation(String gradebookUid, String siteId); /** * Removes an assignment from a gradebook. The assignment should not be deleted, but the assignment and all grade records associated @@ -332,7 +252,7 @@ public Map transferGradebook(GradebookInformation gradebookInform * a category object as it minimises the changes of accidental db updates with the live * Category entity. */ - public Optional getCategoryDefinition(Long categoryId); + public Optional getCategoryDefinition(Long categoryId, String siteId); /** * Updates the db category from the supplied definition object @@ -343,10 +263,11 @@ public Map transferGradebook(GradebookInformation gradebookInform * Get the categories for the given gradebook * * @param gradebookUid + * @param siteId * @return {@link CategoryDefinition}s for the categories defined for the given gradebook. Returns an empty list if the gradebook does * not have categories. */ - public List getCategoryDefinitions(String gradebookUid); + public List getCategoryDefinitions(String gradebookUid, String siteId); /** * remove category from gradebook @@ -360,10 +281,12 @@ public Map transferGradebook(GradebookInformation gradebookInform /** * Create a new Gradebook-managed assignment. * + * @param gradebookUid + * @param siteId * @param assignmentDefinition * @return the id of the newly created assignment */ - public Long addAssignment(String gradebookUid, Assignment assignmentDefinition); + public Long addAssignment(String gradebookUid, String siteId, Assignment assignmentDefinition); /** * Modify the definition of an existing Gradebook item. @@ -374,88 +297,41 @@ public Map transferGradebook(GradebookInformation gradebookInform * This method can be used to manage both internal and external gradebook items, however the title, due date and total points will not * be edited for external gradebook items. * + * @param gradebookUid + * @param siteId * @param assignmentId the id of the assignment that needs to be changed * @param assignmentDefinition the new properties of the assignment */ - public void updateAssignment(String gradebookUid, Long assignmentId, Assignment assignmentDefinition); - - /** - * - * @param gradebookUid - * @return list of gb items that the current user is authorized to view. If user has gradeAll permission, returns all gb items. If user - * has gradeSection perm with no grader permissions, returns all gb items. If user has gradeSection with grader perms, returns - * only the items that the current user is authorized to view or grade. If user does not have grading privileges but does have - * viewOwnGrades perm, will return all released gb items. - */ - public List getViewableAssignmentsForCurrentUser(String gradebookUid); + public void updateAssignment(String gradebookUid, String siteId, Long assignmentId, Assignment assignmentDefinition); /** * * @param gradebookUid + * @param siteId * @return list of gb items that the current user is authorized to view sorted by the provided SortType. If user has gradeAll * permission, returns all gb items. If user has gradeSection perm with no grader permissions, returns all gb items. If user has * gradeSection with grader perms, returns only the items that the current user is authorized to view or grade. If user does not * have grading privileges but does have viewOwnGrades perm, will return all released gb items. */ - public List getViewableAssignmentsForCurrentUser(String gradebookUid, SortType sortBy); - - /** - * - * @param gradebookUid - * @param assignmentId - * @return a map of studentId to view/grade function for the given gradebook and gradebook item. students who are not viewable or - * gradable will not be returned. if the current user does not have grading privileges, an empty map is returned - */ - public Map getViewableStudentsForItemForCurrentUser(String gradebookUid, Long assignmentId); + public List getViewableAssignmentsForCurrentUser(String gradebookUid, String siteId, SortType sortBy); /** * @param userUid * @param gradebookUid + * @param siteId * @param assignmentId * @return a map of studentId to view/grade function for the given gradebook and gradebook item that the given userUid is allowed to * view or grade. students who are not viewable or gradable will not be returned. if the given user does not have grading * privileges, an empty map is returned */ - public Map getViewableStudentsForItemForUser(String userUid, String gradebookUid, Long assignmentId); + public Map getViewableStudentsForItemForUser(String userUid, String gradebookUid, String siteId, Long assignmentId); /** * Get the Gradebook. Note that this returns Object to avoid circular dependency with sakai-gradebook-tool Consumers will need to cast * to {@link org.sakaiproject.tool.gradebook.Gradebook} * */ - public Gradebook getGradebook(String uid); - - /** - * Ensure that a gradebook exists for the given id - * - * @param gradebookUid The gradebook we want to initialise. - */ - public void initGradebook(String gradebookUid); - - /** - * Check if there are students that have not submitted - * - * @param gradebookUid - * @return - */ - public boolean checkStudentsNotSubmitted(String gradebookUid); - - /** - * Check if a gradeable object with the given id exists - * - * @param gradableObjectId - * @return true if a gradable object with the given id exists and was not removed - */ - public boolean isGradableObjectDefined(Long gradableObjectId); - - /** - * Using the grader permissions, return map of section uuid to section name that includes all sections that the current user may view or - * grade - * - * @param gradebookUid - * @return - */ - public Map getViewableSectionUuidToNameMap(String gradebookUid); + public Gradebook getGradebook(String uid, String siteId); /** * Check if the current user has the gradebook.gradeAll permission @@ -513,17 +389,19 @@ public Map transferGradebook(GradebookInformation gradebookInform * See {@link #getGradeDefinitionForStudentForItem} for the method call that can be made as a student. * * @param gradebookUid + * @param siteId * @param assignmentId * @param studentIds * @return a list of GradeDefinition with the grade information for the given students for the given gradableObjectId * @throws SecurityException if the current user is not authorized to view or grade a student in the passed list */ - public List getGradesForStudentsForItem(String gradebookUid, Long assignmentId, List studentIds); + public List getGradesForStudentsForItem(String gradebookUid, String siteId, Long assignmentId, List studentIds); /** * This method gets grades for multiple gradebook items with emphasis on performance. This is particularly useful for reporting tools * * @param gradebookUid + * @param siteId * @param gradableObjectIds * @param studentIds * @return a Map of GradableObjectIds to a List of GradeDefinitions containing the grade information for the given students for the @@ -533,8 +411,7 @@ public Map transferGradebook(GradebookInformation gradebookInform * @throws IllegalArgumentException if gradableObjectIds is null/empty, or if gradableObjectIds contains items that are not members of * the gradebook with uid = gradebookUid */ - public Map> getGradesWithoutCommentsForStudentsForItems(String gradebookUid, List gradableOjbectIds, - List studentIds); + public Map> getGradesWithoutCommentsForStudentsForItems(String gradebookUid, String siteId, List gradableOjbectIds, List studentIds); /** * @@ -567,6 +444,7 @@ public Map> getGradesWithoutCommentsForStudentsForIt * type. * * @param gradebookUid + * @param siteId * @param assignmentId * @param studentId * @param grade - must be in format according to gradebook's grade entry type @@ -575,7 +453,7 @@ public Map> getGradesWithoutCommentsForStudentsForIt * @throws AssessmentNotFoundException * @throws SecurityException if current user is not authorized to grade student */ - public void saveGradeAndCommentForStudent(String gradebookUid, Long assignmentId, String studentId, String grade, String comment) + public void saveGradeAndCommentForStudent(String gradebookUid, String siteId, Long assignmentId, String studentId, String grade, String comment) throws InvalidGradeException, AssessmentNotFoundException; /** @@ -583,6 +461,7 @@ public void saveGradeAndCommentForStudent(String gradebookUid, Long assignmentId * comments. Scores must be in a format according to the gradebook's grade entry type (ie points, %, letter). * * @param gradebookUid + * @param siteId * @param assignmentId * @param gradeDefList * @throws InvalidGradeException if any of the grades are not valid - none will be saved @@ -590,10 +469,10 @@ public void saveGradeAndCommentForStudent(String gradebookUid, Long assignmentId * student * @throws AssessmentNotFoundException */ - public void saveGradesAndComments(String gradebookUid, Long assignmentId, List gradeDefList) + public void saveGradesAndComments(String gradebookUid, String siteId, Long assignmentId, List gradeDefList) throws InvalidGradeException, AssessmentNotFoundException; - public void saveGradeAndExcuseForStudent(String gradebookUid, Long assignmentId, String studentId, String grade, boolean excuse) + public void saveGradeAndExcuseForStudent(String gradebookUid, String siteId, Long assignmentId, String studentId, String grade, boolean excuse) throws InvalidGradeException, AssessmentNotFoundException; /** @@ -603,135 +482,52 @@ public void saveGradeAndExcuseForStudent(String gradebookUid, Long assignmentId, */ public Integer getGradeEntryType(String gradebookUid); - /** - * Get a Map of overridden CourseGrade for students. - * - * @param gradebookUid - * @return Map of enrollment displayId as key, point as value string - * - */ - public Map getEnteredCourseGrade(String gradebookUid); - /** * Get student's assignment's score as string. * @param gradebookUid + * @param siteId * @param assignmentId * @param studentUid * @return String of score */ - public String getAssignmentScoreString(String gradebookUid, Long assignmentId, String studentUid) - throws AssessmentNotFoundException; - - /** - * Get student's assignment's score as string. This is provided for backward compatibility only. - * - * @param gradebookUid - * @param assignmentName - * @param studentUid - * @return String of score - * - * @deprecated See {@link #getAssignmentScoreString(String, Long, String)} - */ - @Deprecated - public String getAssignmentScoreString(String gradebookUid, String assignmentName, String studentUid) - throws AssessmentNotFoundException; - - /** - * Get student's assignment's score as string. - * - * This is intended as a migration path from the deprecated {@link #getAssignmentScoreString(String,String)} to the new - * {@link #getAssignmentScoreString(String,Long)} - * - * This method will attempt to lookup the name as provided then fallback to the ID as a Long (If it is a Long) You should use - * {@link #getAssignmentScoreString(String,Long)} if you always can use the Long instead. - * - * @param gradebookUid - * @param assignmentName - * @param studentUid - * @return String of score - */ - public String getAssignmentScoreStringByNameOrId(String gradebookUid, String assignmentName, String studentUid) + public String getAssignmentScoreString(String gradebookUid, String siteId, Long assignmentId, String studentUid) throws AssessmentNotFoundException; /** * Set student's score for assignment. * * @param gradebookUid + * @param siteId * @param assignmentId * @param studentUid * @param score * @param clientServiceDescription * */ - public void setAssignmentScoreString(String gradebookUid, Long assignmentId, String studentUid, String score, + public void setAssignmentScoreString(String gradebookUid, String siteId, Long assignmentId, String studentUid, String score, String clientServiceDescription) throws AssessmentNotFoundException; - /** - * Set student's score for assignment. This is provided for backward compatibility only. - * - * @param gradebookUid - * @param assignmentName - * @param studentUid - * @param score - * @param clientServiceDescription - * - * @deprecated See {@link #setAssignmentScoreString(String, Long, String, String, String)} - */ - @Deprecated - public void setAssignmentScoreString(String gradebookUid, String assignmentName, String studentUid, String score, - String clientServiceDescription) - throws AssessmentNotFoundException; - - - /** - * Finalize the gradebook's course grades by setting all still-unscored assignments to zero scores. - * - * @param gradebookUid - */ - public void finalizeGrades(String gradebookUid); - - /** - * - * @param gradebookUid - * @param assignmentId - * @return the lowest possible grade allowed for the given assignmentId. For example, in a points or %-based gradebook, the lowest - * possible grade for a gradebook item is 0. In a letter-grade gb, it may be 'F' depending on the letter grade mapping. Ungraded - * items have a lowest value of null. - * @throws SecurityException if user does not have permission to view assignments in the given gradebook - * @throws AssessmentNotFoundException if there is no gradebook item with the given gradebookItemId - */ - public String getLowestPossibleGradeForGbItem(String gradebookUid, Long assignmentId); - - /** - * - * @param gradebookUid (non-null) - * @param assignment (non-null) the Assignment object representing the gradebook item for which you are setting the points possible (aka - * relative weight). May be a new gradebook item without an id yet. - * @param pointsPossible the points possible/relative weight you would like to validate for the gradebookItem above. - * @return {@link PointsPossibleValidation} value indicating the validity of the given points possible/relative weight or a problem code - * defining why it is invalid - */ - public PointsPossibleValidation isPointsPossibleValid(String gradebookUid, Assignment assignment, Double pointsPossible); - /** * Computes the Average Course Grade as a letter. * * @param gradebookUid + * @param siteId * @return */ - public String getAverageCourseGrade(String gradebookUid); + public String getAverageCourseGrade(String gradebookUid, String siteId); public Long getCourseGradeId(final Long gradebookId); /** * Update the ordering of an assignment. This can be performed on internal and external assignments. * @param gradebookUid uid of the gradebook + * @param siteId * @param assignmentId id of the assignment in the gradebook * @param order the new order for this assignment. Note it is 0 based index ordering. * @return */ - public void updateAssignmentOrder(String gradebookUid, Long assignmentId, Integer order); + public void updateAssignmentOrder(String gradebookUid, String siteId, Long assignmentId, Integer order); /** * Gets the grading events for the given student and the given assignment @@ -777,46 +573,51 @@ Optional calculateCategoryScore(Object gradebook, String stud * Get the course grade for a student * * @param gradebookUid + * @param siteId * @param userUuid uuid of the user * @return The {@link CourseGradeTransferBean} for the student */ - CourseGradeTransferBean getCourseGradeForStudent(String gradebookUid, String userUuid); + CourseGradeTransferBean getCourseGradeForStudent(String gradebookUid, String siteId, String userUuid); /** * Get the course grade for a list of students * * @param gradebookUid + * @param siteId * @param userUuids uuids of the users * @return a Map of {@link CourseGradeTransferBean} for the students. Key is the student uuid. */ - Map getCourseGradeForStudents(String gradebookUid, List userUuids); + Map getCourseGradeForStudents(String gradebookUid, String siteId, List userUuids); /** * Get the course grade for a list of students using the given grading schema * * @param gradebookUid + * @param siteId * @param userUuids uuids of the users * @param schema the grading schema (bottom percents) to use in the calculation * @return a Map of {@link CourseGrade} for the students. Key is the student uuid. */ - Map getCourseGradeForStudents(String gradebookUid, List userUuids, Map schema); + Map getCourseGradeForStudents(String gradebookUid, String siteId, List userUuids, Map schema); /** * Get a list of CourseSections that the current user has access to in the given gradebook. This is a combination of sections and groups * and is permission filtered. * * @param gradebookUid + * @param siteId * @return list of CourseSection objects. */ - List getViewableSections(String gradebookUid); + List getViewableSections(String gradebookUid, String siteId); /** * Update the settings for this gradebook * * @param gradebookUid + * @param siteId * @param gbInfo GradebookInformation object */ - void updateGradebookSettings(String gradebookUid, GradebookInformation gbInfo); + void updateGradebookSettings(String gradebookUid, String siteId, GradebookInformation gbInfo); /** * Return the GradeMappings for the given gradebook. The normal getGradebook(siteId) doesn't return the GradeMapping. @@ -826,31 +627,26 @@ Optional calculateCategoryScore(Object gradebook, String stud */ Set getGradebookGradeMappings(Long gradebookId); - /** - * Return the GradeMappings for the given gradebook. - * @param gradebookUid - * @return Set of GradeMappings for the gradebook - */ - Set getGradebookGradeMappings(String gradebookUid); - /** * Allows an instructor to set a course grade override for the given student * * @param gradebookUid uuid of the gradebook + * @param siteId * @param studentUuid uuid of the student * @param grade the new course grade */ - void updateCourseGradeForStudent(String gradebookUid, String studentUuid, String grade, String gradeScale); + void updateCourseGradeForStudent(String gradebookUid, String siteId, String studentUuid, String grade, String gradeScale); /** * Updates the categorized order of an assignment * * @param gradebookUid uuid of the gradebook + * @param siteId * @param categoryId id of the category * @param assignmentId id of the assignment * @param order new position of the assignment */ - void updateAssignmentCategorizedOrder(String gradebookUid, Long categoryId, Long assignmentId, Integer order); + void updateAssignmentCategorizedOrder(String gradebookUid, String siteId, Long categoryId, Long assignmentId, Integer order); /** * Return the grade changes made since a given time @@ -862,71 +658,9 @@ Optional calculateCategoryScore(Object gradebook, String stud List getGradingEvents(List assignmentIds, Date since); /** - * @deprecated Replaced by - * {@link addExternalAssessment(String, String, String, String, Double, Date, String, Boolean)} - */ - @Deprecated - public void addExternalAssessment(String gradebookUid, String externalId, String externalUrl, - String title, double points, Date dueDate, String externalServiceDescription, String externalData) - throws ConflictingAssignmentNameException, ConflictingExternalIdException, AssignmentHasIllegalPointsException; - - /** - * Add an externally-managed assessment to a gradebook to be treated as a - * read-only assignment. The gradebook application will not modify the - * assessment properties or create any scores for the assessment. - * Since each assignment in a given gradebook must have a unique name, - * conflicts are possible. - * @param gradebookUid - * @param externalId some unique identifier which Samigo uses for the assessment. - * The externalId is globally namespaced within the gradebook, so - * if other apps decide to put assessments into the gradebook, - * they should prefix their externalIds with a well known (and - * unique within sakai) string. - * @param externalUrl a link to go to if the instructor or student wants to look at the assessment - * in Samigo; if null, no direct link will be provided in the - * gradebook, and the user will have to navigate to the assessment - * within the other application - * @param title - * @param points this is the total amount of points available and must be greater than zero. - * It could be null if it's an ungraded item. - * @param dueDate - * @param externalServiceDescription - * @param externalData if there is some data that the external service wishes to store. - * @param ungraded - * - * - */ - public void addExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, Double points, - Date dueDate, String externalServiceDescription, String externalData, Boolean ungraded) - throws ConflictingAssignmentNameException, ConflictingExternalIdException, AssignmentHasIllegalPointsException; - - /** - * This method is identical to {@link #addExternalAssessment(String, String, String, String, Double, Date, String, String, Boolean)} but - * allows you to also specify the associated Category for this assignment. If the gradebook is set up for categories and * categoryId is null, assignment category will be unassigned * @param gradebookUid - * @param externalId - * @param externalUrl - * @param title - * @param points - * @param dueDate - * @param externalServiceDescription - * @param externalData if there is some data that the external service wishes to store. - * @param ungraded - * @param categoryId - * @throws ConflictingAssignmentNameException - * @throws ConflictingExternalIdException - * @throws AssignmentHasIllegalPointsException - * @throws InvalidCategoryException - */ - public void addExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, Double points, - Date dueDate, String externalServiceDescription, String externalData, Boolean ungraded, Long categoryId) - throws ConflictingAssignmentNameException, ConflictingExternalIdException, AssignmentHasIllegalPointsException, InvalidCategoryException; - - /** - * This method is identical to {@link #addExternalAssessment(String, String, String, String, Double, Date, String, String, Boolean, Long)} but - * allows you to also specify the reference for the thing being graded via the gradableReference. - * @param gradebookUid + * @param siteId * @param externalId * @param externalUrl * @param title @@ -942,21 +676,10 @@ public void addExternalAssessment(String gradebookUid, String externalId, String * @throws AssignmentHasIllegalPointsException * @throws InvalidCategoryException */ - public void addExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, Double points, + public void addExternalAssessment(String gradebookUid, String siteId, String externalId, String externalUrl, String title, Double points, Date dueDate, String externalServiceDescription, String externalData, Boolean ungraded, Long categoryId, String gradableReference) throws ConflictingAssignmentNameException, ConflictingExternalIdException, AssignmentHasIllegalPointsException, InvalidCategoryException; - - - /** - * @deprecated Replaced by - * {@link updateExternalAssessment(String, String, String, String, Double, Date, Boolean)} - */ - @Deprecated - public void updateExternalAssessment(String gradebookUid, String externalId, String externalUrl, String externalData, - String title, double points, Date dueDate) - throws AssessmentNotFoundException, ConflictingAssignmentNameException, AssignmentHasIllegalPointsException; - /** * Update an external assessment * @param gradebookUid @@ -964,6 +687,7 @@ public void updateExternalAssessment(String gradebookUid, String externalId, Str * @param externalUrl * @param externalData * @param title + * @param categoryId * @param points * @param dueDate * @param ungraded @@ -971,24 +695,17 @@ public void updateExternalAssessment(String gradebookUid, String externalId, Str * @throws ConflictingAssignmentNameException * @throws AssignmentHasIllegalPointsException */ - public void updateExternalAssessment(String gradebookUid, String externalId, String externalUrl, String externalData, - String title, Double points, Date dueDate, Boolean ungraded) - throws AssessmentNotFoundException, ConflictingAssignmentNameException, AssignmentHasIllegalPointsException; - public void updateExternalAssessment(String gradebookUid, String externalId, String externalUrl, String externalData, String title, Long categoryId, Double points, Date dueDate, Boolean ungraded) throws AssessmentNotFoundException, ConflictingAssignmentNameException, AssignmentHasIllegalPointsException; /** - * Remove the assessment reference from the gradebook. Although Samigo - * doesn't currently delete assessments, an instructor can retract an - * assessment to keep it from students. Since such an assessment would - * presumably no longer be used to calculate final grades, Samigo should - * also remove that assessment from the gradebook. + * Remove the assessment reference from the gradebook. * + * @param gradebookUid * @param externalId - * the UID of the assessment + * @param externalApp */ - public void removeExternalAssignment(String gradebookUid, String externalId) + public void removeExternalAssignment(String gradebookUid, String externalId, String externalApp) throws AssessmentNotFoundException; /** @@ -996,6 +713,7 @@ public void removeExternalAssignment(String gradebookUid, String externalId) * * @param gradebookUid * The Uid of the gradebook + * @param siteId * @param externalId * The external ID of the assignment/assessment * @param studentUid @@ -1004,13 +722,14 @@ public void removeExternalAssignment(String gradebookUid, String externalId) * The number of points earned on this assessment, or null if a score * should be removed */ - public void updateExternalAssessmentScore(String gradebookUid, String externalId, + public void updateExternalAssessmentScore(String gradebookUid, String siteId, String externalId, String studentUid, String points) throws AssessmentNotFoundException; /** * * @param gradebookUid + * @param siteId * @param externalId * @param studentUidsToScores * @throws AssessmentNotFoundException @@ -1019,7 +738,7 @@ public void updateExternalAssessmentScore(String gradebookUid, String externalId * {@link updateExternalAssessmentScoresString(String, String, Map studentUidsToScores) throws AssessmentNotFoundException; @@ -1028,6 +747,7 @@ public void updateExternalAssessmentScores(String gradebookUid, * * @param gradebookUid * The Uid of the gradebook + * @param siteId * @param externalId * The external ID of the assignment/assessment * @param studentUidsToScores @@ -1035,7 +755,7 @@ public void updateExternalAssessmentScores(String gradebookUid, * String values are points earned on this assessment or null if the score * should be removed. */ - public void updateExternalAssessmentScoresString(String gradebookUid, + public void updateExternalAssessmentScoresString(String gradebookUid, String siteId, String externalId, Map studentUidsToScores) throws AssessmentNotFoundException; @@ -1044,6 +764,7 @@ public void updateExternalAssessmentScoresString(String gradebookUid, * * @param gradebookUid * The Uid of the gradebook + * @param siteId * @param externalId * The external ID of the assignment/assessment * @param studentUid @@ -1052,7 +773,7 @@ public void updateExternalAssessmentScoresString(String gradebookUid, * The comment to be added to this grade, or null if a comment * should be removed */ - public void updateExternalAssessmentComment(String gradebookUid, + public void updateExternalAssessmentComment(String gradebookUid, String siteId, String externalId, String studentUid, String comment ) throws AssessmentNotFoundException; /** @@ -1060,6 +781,7 @@ public void updateExternalAssessmentComment(String gradebookUid, * * @param gradebookUid * The Uid of the gradebook + * @param siteId * @param externalId * The external ID of the assignment/assessment * @param studentUidsToScores @@ -1067,7 +789,7 @@ public void updateExternalAssessmentComment(String gradebookUid, * String values are comments or null if the comments * should be removed. */ - public void updateExternalAssessmentComments(String gradebookUid, + public void updateExternalAssessmentComments(String gradebookUid, String siteId, String externalId, Map studentUidsToComments) throws AssessmentNotFoundException; @@ -1104,26 +826,6 @@ public void updateExternalAssessmentComments(String gradebookUid, */ public boolean isExternalAssignmentVisible(String gradebookUid, String externalId, String userId); - /** - * Retrieve all assignments for a gradebook that are marked as externally - * maintained and are visible to the current user. Assignments may be included - * with a null providerAppKey, indicating that the gradebook references the - * assignment, but no provider claims responsibility for it. - * - * @param gradebookUid The gradebook's unique identifier - * @return A map from the externalId of each activity to the providerAppKey - */ - public Map getExternalAssignmentsForCurrentUser(String gradebookUid); - - /** - * Retrieve a list of all visible, external assignments for a set of users. - * - * @param gradebookUid The gradebook's unique identifier - * @param studentIds The collection of student IDs for which to retrieve assignments - * @return A map from the student ID to all visible, external activity IDs - */ - public Map> getVisibleExternalAssignments(String gradebookUid, Collection studentIds); - /** * Register a new ExternalAssignmentProvider for handling the integration of external * assessment sources with the sakai gradebook @@ -1141,15 +843,6 @@ public void updateExternalAssessmentComments(String gradebookUid, */ public void unregisterExternalAssignmentProvider(String providerAppKey); - /** - * Break the connection between an external assessment engine and an assessment which - * it created, giving it up to the Gradebook application to control from now on. - * - * @param gradebookUid - * @param externalId - */ - public void setExternalAssessmentToGradebookAssignment(String gradebookUid, String externalId); - /** * Get the category of a gradebook with the externalId given * @@ -1175,8 +868,9 @@ public void updateExternalAssessmentComments(String gradebookUid, * The UID used to specify a gradebook and its associated data. * It is the caller's responsibility to ensure that this is * unique within gradebook storage. + * @param name */ - public Gradebook addGradebook(String uid); + public Gradebook addGradebook(String uid, String name); /** * Deletes the gradebook with the given UID, along with all its associated @@ -1228,5 +922,16 @@ public void updateExternalAssessmentComments(String gradebookUid, */ public void updateGradeMapping(Long gradeMappingId, Map gradeMap); - public String getUrlForAssignment(Assignment assignment); + public boolean isGradebookGroupEnabled(String siteId); + public List getGradebookGroupInstances(String siteId); + public List getGradebookGroupInstancesIds(String siteId); + public Assignment getAssignmentById(String siteId, Long assignmentId); + public GradebookAssignment getGradebookAssigment(String siteId, Long assignmentId); + public String getGradebookUidByAssignmentById(String siteId, Long assignmentId); + public void buildGradebookPointsMap(String gbUid, String siteId, String assignmentRef, Map gradebookPointsMap, String newCategoryString); + public boolean checkMultiSelectorList(String siteId, List groupList, List multiSelectorList, boolean isCategory); + public Map buildCategoryGradebookMap(List selectedGradebookUids, String categoriesString, String siteId); + public Long getMatchingUserGradebookItemId(String siteId, String userId, String gradebookItemIdString); + public List getGradebookInstancesForUser(String siteId, String userId); + } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/MessageHelper.java b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/MessageHelper.java similarity index 71% rename from gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/MessageHelper.java rename to gradebookng/api/src/main/java/org/sakaiproject/grading/api/MessageHelper.java index 41b5f1e84aa1..16194fe7d4f9 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/MessageHelper.java +++ b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/MessageHelper.java @@ -13,14 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sakaiproject.gradebookng.business.util; +package org.sakaiproject.grading.api; import java.text.MessageFormat; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; -import org.sakaiproject.util.ResourceLoader; /** * Handles the retrieval of localised messages and parameter substitution outside of the Wicket context. @@ -38,9 +37,9 @@ public class MessageHelper { * @param key * @return */ - public static String getString(final String key) { + public static String getString(final String key, final Locale userPreferredLocale) { try { - return ResourceBundle.getBundle("gradebookng", getUserPreferredLocale()).getString(key); + return ResourceBundle.getBundle("gradebookng", userPreferredLocale).getString(key); } catch (final MissingResourceException e) { return '!' + key + '!'; } @@ -52,13 +51,8 @@ public static String getString(final String key) { * @param key * @return */ - public static String getString(final String key, final Object... arguments) { - return MessageFormat.format(getString(key), arguments); + public static String getString(final String key, final Locale userPreferredLocale, final Object... arguments) { + return MessageFormat.format(getString(key, userPreferredLocale), arguments); } - // helper to get the Locale from Sakai - private static Locale getUserPreferredLocale() { - final ResourceLoader rl = new ResourceLoader(); - return rl.getLocale(); - } } diff --git a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/model/Gradebook.java b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/model/Gradebook.java index 4d2793b1a34b..780cdb127c59 100644 --- a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/model/Gradebook.java +++ b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/model/Gradebook.java @@ -41,10 +41,7 @@ // TODO: Check this against SAK-46484. I cut this code before that patch. /** - * A Gradebook is the top-level object in the Sakai Gradebook tool. Only one - * Gradebook should be associated with any particular course (or site, as they - * exist in Sakai 1.5) for any given academic term. How courses and terms are - * determined will likely depend on the particular Sakai installation. + * A Gradebook is the top-level object in the Sakai Gradebook tool. */ @Entity @Table(name = "GB_GRADEBOOK_T") diff --git a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/repository/GradebookAssignmentRepository.java b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/repository/GradebookAssignmentRepository.java index de67c8c81288..298635b7817f 100644 --- a/gradebookng/api/src/main/java/org/sakaiproject/grading/api/repository/GradebookAssignmentRepository.java +++ b/gradebookng/api/src/main/java/org/sakaiproject/grading/api/repository/GradebookAssignmentRepository.java @@ -32,6 +32,7 @@ public interface GradebookAssignmentRepository extends SpringCrudRepository findByGradebook_IdAndRemovedAndNotCounted(Long gradebookId, Boolean removed, Boolean notCounted); List findByGradebook_IdAndRemovedAndNotCountedAndUngraded(Long gradebookId, Boolean removed, Boolean notCounted, Boolean ungraded); Optional findByGradebook_UidAndExternalId(String gradebookUid, String externalId); + List findByExternalId(String externalId); Long countByGradebook_UidAndExternalId(String gradebookUid, String externalId); Long countByNameAndGradebook_UidAndRemoved(String name, String gradebookUid, Boolean removed); Long countByNameAndGradebookAndNotIdAndRemoved(String name, Gradebook gradebook, Long id, Boolean removed); diff --git a/gradebookng/bundle/src/main/bundle/gradebookng.properties b/gradebookng/bundle/src/main/bundle/gradebookng.properties index ccbe40d53c11..b98d07d9a171 100644 --- a/gradebookng/bundle/src/main/bundle/gradebookng.properties +++ b/gradebookng/bundle/src/main/bundle/gradebookng.properties @@ -736,3 +736,6 @@ bulkedit.confirmation.cancel=Cancel sections.label.none = None label.submission-messager.title=Message Students + +# S2U-26 +group.gradebook = Group diff --git a/gradebookng/bundle/src/main/bundle/gradebookng_ca.properties b/gradebookng/bundle/src/main/bundle/gradebookng_ca.properties index b7447847f09e..b9a946280518 100644 --- a/gradebookng/bundle/src/main/bundle/gradebookng_ca.properties +++ b/gradebookng/bundle/src/main/bundle/gradebookng_ca.properties @@ -728,3 +728,6 @@ bulkedit.confirmation.cancel=Cancel\u00b7la sections.label.none=Cap label.submission-messager.title=Missatge per als estudiants + +# S2U-26 +group.gradebook = Grup diff --git a/gradebookng/bundle/src/main/bundle/gradebookng_es.properties b/gradebookng/bundle/src/main/bundle/gradebookng_es.properties index a8c875d0f9a6..20a296a0cc16 100644 --- a/gradebookng/bundle/src/main/bundle/gradebookng_es.properties +++ b/gradebookng/bundle/src/main/bundle/gradebookng_es.properties @@ -736,3 +736,6 @@ bulkedit.confirmation.cancel=Cancelar sections.label.none=Ninguno label.submission-messager.title=Mensajes + +# S2U-26 +group.gradebook = Grupo diff --git a/gradebookng/bundle/src/main/bundle/gradebookng_eu.properties b/gradebookng/bundle/src/main/bundle/gradebookng_eu.properties index c46a00c2c4b9..ce7f3a240bb2 100644 --- a/gradebookng/bundle/src/main/bundle/gradebookng_eu.properties +++ b/gradebookng/bundle/src/main/bundle/gradebookng_eu.properties @@ -728,3 +728,6 @@ bulkedit.confirmation.cancel=Utzi sections.label.none=Ezein ez label.submission-messager.title=Emaila ikasleei + +# S2U-26 +group.gradebook = Group diff --git a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradebookDefinition.java b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradebookDefinition.java deleted file mode 100644 index 8f8693dd3fb4..000000000000 --- a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradebookDefinition.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2003-2012 The Apereo Foundation - * - * Licensed under the Educational Community License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://opensource.org/licenses/ecl2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sakaiproject.grading.impl; - -import java.io.Externalizable; -import java.util.Collection; -import java.util.Map; -import java.util.List; - -import org.sakaiproject.grading.api.Assignment; - -import lombok.Getter; -import lombok.Setter; - -@Getter @Setter -public class GradebookDefinition extends VersionedExternalizable implements Externalizable { - - private static final long serialVersionUID = 1L; - public static final String EXTERNALIZABLE_VERSION = "1"; - - private String selectedGradingScaleUid; - private Map selectedGradingScaleBottomPercents; - private Collection assignments; - private int gradeType; - private int categoryType; - private List category; - - public String getExternalizableVersion() { - return EXTERNALIZABLE_VERSION; - } -} diff --git a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingAuthzImpl.java b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingAuthzImpl.java index 20780f6ab96a..df15ddd4c0be 100644 --- a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingAuthzImpl.java +++ b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingAuthzImpl.java @@ -90,16 +90,16 @@ public void init() { } } - public boolean isUserAbleToGrade(String gradebookUid) { + public boolean isUserAbleToGrade(String siteId) { - return (hasPermission(gradebookUid, PERMISSION_GRADE_ALL) || hasPermission(gradebookUid, PERMISSION_GRADE_SECTION)); + return (hasPermission(siteId, PERMISSION_GRADE_ALL) || hasPermission(siteId, PERMISSION_GRADE_SECTION)); } - public boolean isUserAbleToGrade(String gradebookUid, String userUid) { + public boolean isUserAbleToGrade(String siteId, String userUid) { try { User user = userDirectoryService.getUser(userUid); - return (hasPermission(user, gradebookUid, PERMISSION_GRADE_ALL) || hasPermission(user, gradebookUid, PERMISSION_GRADE_SECTION)); + return (hasPermission(user, siteId, PERMISSION_GRADE_ALL) || hasPermission(user, siteId, PERMISSION_GRADE_SECTION)); } catch (UserNotDefinedException unde) { log.warn("User not found for userUid: " + userUid); return false; @@ -107,56 +107,45 @@ public boolean isUserAbleToGrade(String gradebookUid, String userUid) { } - public boolean isUserAbleToGradeAll(String gradebookUid) { + public boolean isUserAbleToGradeAll(String siteId) { - return hasPermission(gradebookUid, PERMISSION_GRADE_ALL); + return hasPermission(siteId, PERMISSION_GRADE_ALL); } - public boolean isUserAbleToGradeAll(String gradebookUid, String userUid) { + public boolean isUserAbleToGradeAll(String siteId, String userUid) { try { User user = userDirectoryService.getUser(userUid); - return hasPermission(user, gradebookUid, PERMISSION_GRADE_ALL); + return hasPermission(user, siteId, PERMISSION_GRADE_ALL); } catch (UserNotDefinedException unde) { log.warn("User not found for userUid: " + userUid); return false; } } - /** - * When group-scoped permissions are available, this is where - * they will go. My current assumption is that the call will look like: - * - * return hasPermission(sectionUid, PERMISSION_GRADE_ALL); - */ - public boolean isUserAbleToGradeSection(String sectionUid) { + public boolean isUserAbleToEditAssessments(String siteId) { - return sectionAwareness.isSectionMemberInRole(sectionUid, sessionManager.getCurrentSessionUserId(), Role.TA); + return hasPermission(siteId, PERMISSION_EDIT_ASSIGNMENTS); } - public boolean isUserAbleToEditAssessments(String gradebookUid) { + public boolean isUserAbleToViewOwnGrades(String siteId) { - return hasPermission(gradebookUid, PERMISSION_EDIT_ASSIGNMENTS); + return hasPermission(siteId, PERMISSION_VIEW_OWN_GRADES); } - public boolean isUserAbleToViewOwnGrades(String gradebookUid) { + public boolean isUserAbleToViewStudentNumbers(String siteId) { - return hasPermission(gradebookUid, PERMISSION_VIEW_OWN_GRADES); + return hasPermission(siteId, PERMISSION_VIEW_STUDENT_NUMBERS); } - public boolean isUserAbleToViewStudentNumbers(String gradebookUid) { + private boolean hasPermission(String siteId, String permission) { - return hasPermission(gradebookUid, PERMISSION_VIEW_STUDENT_NUMBERS); + return securityService.unlock(permission, siteService.siteReference(siteId)); } - private boolean hasPermission(String gradebookUid, String permission) { + private boolean hasPermission(User user, String siteId, String permission) { - return securityService.unlock(permission, siteService.siteReference(gradebookUid)); - } - - private boolean hasPermission(User user, String gradebookUid, String permission) { - - return securityService.unlock(user, permission, siteService.siteReference(gradebookUid)); + return securityService.unlock(user, permission, siteService.siteReference(siteId)); } /** @@ -175,19 +164,19 @@ private boolean isUserTAinSection(String sectionUid, String userUid) { return sectionAwareness.isSectionMemberInRole(sectionUid, userUid, Role.TA); } - public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, Long itemId, String studentUid) { + public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, String siteId, Long itemId, String studentUid) { if (itemId == null || studentUid == null || gradebookUid == null) { - throw new IllegalArgumentException("Null parameter(s) in AuthzSectionsServiceImpl.isUserAbleToGradeItemForStudent"); + throw new IllegalArgumentException("Null parameter(s) in AuthzSectionsServiceImpl.getGradeViewFunctionForUserForStudentForItem"); } - if (isUserAbleToGradeAll(gradebookUid)) { + if (isUserAbleToGradeAll(siteId)) { return GradingConstants.gradePermission; } String userUid = sessionManager.getCurrentSessionUserId(); - List viewableSections = getViewableSections(gradebookUid); + List viewableSections = getViewableSections(gradebookUid, siteId); if (gradingPermissionService.currentUserHasGraderPermissions(gradebookUid)) { @@ -229,19 +218,19 @@ public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, } } - private boolean isUserAbleToGradeOrViewItemForStudent(String gradebookUid, Long itemId, String studentUid, String function) throws IllegalArgumentException { + private boolean isUserAbleToGradeOrViewItemForStudent(String gradebookUid, String siteId, Long itemId, String studentUid, String function) throws IllegalArgumentException { if (itemId == null || studentUid == null || function == null) { - throw new IllegalArgumentException("Null parameter(s) in AuthzSectionsServiceImpl.isUserAbleToGradeItemForStudent"); + throw new IllegalArgumentException("Null parameter(s) in AuthzSectionsServiceImpl.isUserAbleToGradeOrViewItemForStudent"); } - if (isUserAbleToGradeAll(gradebookUid)) { + if (isUserAbleToGradeAll(siteId)) { return true; } String userUid = sessionManager.getCurrentSessionUserId(); - List viewableSections = getViewableSections(gradebookUid); + List viewableSections = getViewableSections(gradebookUid, siteId); List sectionIds = new ArrayList<>(); if (!viewableSections.isEmpty()) { viewableSections.forEach(cs -> sectionIds.add(cs.getUuid())); @@ -282,26 +271,26 @@ private boolean isUserAbleToGradeOrViewItemForStudent(String gradebookUid, Long } } - public boolean isUserAbleToGradeItemForStudent(String gradebookUid, Long itemId, String studentUid) throws IllegalArgumentException { + public boolean isUserAbleToGradeItemForStudent(String gradebookUid, String siteId, Long itemId, String studentUid) throws IllegalArgumentException { - return isUserAbleToGradeOrViewItemForStudent(gradebookUid, itemId, studentUid, GradingConstants.gradePermission); + return isUserAbleToGradeOrViewItemForStudent(gradebookUid, siteId, itemId, studentUid, GradingConstants.gradePermission); } - public boolean isUserAbleToViewItemForStudent(String gradebookUid, Long itemId, String studentUid) throws IllegalArgumentException { + public boolean isUserAbleToViewItemForStudent(String gradebookUid, String siteId, Long itemId, String studentUid) throws IllegalArgumentException { - return isUserAbleToGradeOrViewItemForStudent(gradebookUid, itemId, studentUid, GradingConstants.viewPermission); + return isUserAbleToGradeOrViewItemForStudent(gradebookUid, siteId, itemId, studentUid, GradingConstants.viewPermission); } - public List getViewableSections(String gradebookUid) { + public List getViewableSections(String gradebookUid, String siteId) { List viewableSections = new ArrayList<>(); - List allSections = getAllSections(gradebookUid); + List allSections = getAllSections(siteId); if (allSections.isEmpty()) { return viewableSections; } - if (isUserAbleToGradeAll(gradebookUid)) { + if (isUserAbleToGradeAll(siteId)) { return allSections; } @@ -339,9 +328,9 @@ public List getViewableSections(String gradebookUid) { return viewableSections; } - public List getAllSections(String gradebookUid) { + public List getAllSections(String siteId) { - return sectionAwareness.getSections(gradebookUid); + return sectionAwareness.getSections(siteId); } private List getSectionEnrollmentsTrusted(String sectionUid) { @@ -349,192 +338,37 @@ private List getSectionEnrollmentsTrusted(String sectionUid) { return sectionAwareness.getSectionMembersInRole(sectionUid, Role.STUDENT); } - public Map findMatchingEnrollmentsForItem(String gradebookUid, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid) { - - String userUid = sessionManager.getCurrentSessionUserId(); - return findMatchingEnrollmentsForItemOrCourseGrade(userUid, gradebookUid, categoryId, gbCategoryType, optionalSearchString, optionalSectionUid, false); - } - - public Map findMatchingEnrollmentsForItemForUser(String userUid, String gradebookUid, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid) { - - return findMatchingEnrollmentsForItemOrCourseGrade(userUid, gradebookUid, categoryId, gbCategoryType, optionalSearchString, optionalSectionUid, false); - } - - public Map findMatchingEnrollmentsForViewableCourseGrade(String gradebookUid, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid) { + public Map findMatchingEnrollmentsForItem(String gradebookUid, String siteId, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid) { String userUid = sessionManager.getCurrentSessionUserId(); - return findMatchingEnrollmentsForItemOrCourseGrade(userUid, gradebookUid, null, gbCategoryType, optionalSearchString, optionalSectionUid, true); + return findMatchingEnrollmentsForItemOrCourseGrade(userUid, gradebookUid, siteId, categoryId, gbCategoryType, optionalSearchString, optionalSectionUid, false); } - public Map> findMatchingEnrollmentsForViewableItems(String gradebookUid, List allGbItems, String optionalSearchString, String optionalSectionUid) { - - Map> enrollmentMap = new HashMap<>(); - List filteredEnrollments = null; - if (optionalSearchString != null) { - filteredEnrollments = sectionAwareness.findSiteMembersInRole(gradebookUid, Role.STUDENT, optionalSearchString); - } else { - filteredEnrollments = sectionAwareness.getSiteMembersInRole(gradebookUid, Role.STUDENT); - } - - if (filteredEnrollments == null || filteredEnrollments.isEmpty()) { - return enrollmentMap; - } - - // get all the students in the filtered section, if appropriate - Map studentsInSectionMap = new HashMap<>(); - if (optionalSectionUid != null) { - List sectionMembers = getSectionEnrollmentsTrusted(optionalSectionUid); - if (!sectionMembers.isEmpty()) { - sectionMembers.forEach(m -> studentsInSectionMap.put(m.getUser().getUserUid(), m)); - } - } - - Map studentIdEnrRecMap = new HashMap<>(); - for (EnrollmentRecord enr : filteredEnrollments) { - String studentId = enr.getUser().getUserUid(); - if (optionalSectionUid != null) { - if (studentsInSectionMap.containsKey(studentId)) { - studentIdEnrRecMap.put(studentId, enr); - } - } else { - studentIdEnrRecMap.put(studentId, enr); - } - } - - if (isUserAbleToGradeAll(gradebookUid)) { - List enrollments = new ArrayList<>(studentIdEnrRecMap.values()); - - HashMap assignFunctionMap = new HashMap<>(); - if (allGbItems != null && !allGbItems.isEmpty()) { - for (Object assign : allGbItems) { - Long assignId = null; - if (assign instanceof Assignment) { - assignId = ((Assignment) assign).getId(); - } else if (assign instanceof GradebookAssignment) { - assignId = ((GradebookAssignment)assign).getId(); - } - - if (assignId != null) { - assignFunctionMap.put(assignId, GradingConstants.gradePermission); - } - } - } - - enrollments.forEach(e -> enrollmentMap.put(e, assignFunctionMap)); - } else { - String userId = sessionManager.getCurrentSessionUserId(); - - Map sectionIdCourseSectionMap = getViewableSections(gradebookUid) - .stream().collect(Collectors.toMap(s -> s.getUuid(), s -> s)); - - if (gradingPermissionService.currentUserHasGraderPermissions(gradebookUid)) { - // user has special grader permissions that override default perms - - List myStudentIds = new ArrayList<>(studentIdEnrRecMap.keySet()); - - List selSections = new ArrayList<>(); - if (optionalSectionUid == null) { - // pass all sections - selSections = new ArrayList<>(sectionIdCourseSectionMap.values()); - } else { - // only pass the selected section - CourseSection section = sectionIdCourseSectionMap.get(optionalSectionUid); - if (section != null) - selSections.add(section); - } - - // we need to get the viewable students, so first create section id --> student ids map - myStudentIds = gradingPermissionService.getViewableStudentsForUser(gradebookUid, userId, myStudentIds, selSections); - Map> viewableStudentIdItemsMap = new HashMap<>(); - if (allGbItems == null || allGbItems.isEmpty()) { - if (myStudentIds != null) { - for (String studentId : myStudentIds) { - if (studentId != null) { - viewableStudentIdItemsMap.put(studentId, null); - } - } - } - } else { - viewableStudentIdItemsMap = gradingPermissionService.getAvailableItemsForStudents(gradebookUid, userId, myStudentIds, selSections); - } - - if (!viewableStudentIdItemsMap.isEmpty()) { - for (Map.Entry> entry : viewableStudentIdItemsMap.entrySet()) { - String studentId = entry.getKey(); - EnrollmentRecord enrRec = studentIdEnrRecMap.get(studentId); - if (enrRec != null) { - enrollmentMap.put(enrRec, entry.getValue()); - } - } - } - - } else { - // use default section-based permissions - - // Determine the current user's section memberships - List availableSections = new ArrayList<>(); - if (optionalSectionUid != null && isUserTAinSection(optionalSectionUid)) { - if (sectionIdCourseSectionMap.containsKey(optionalSectionUid)) - availableSections.add(optionalSectionUid); - } else { - for (String sectionUuid : sectionIdCourseSectionMap.keySet()) { - if (isUserTAinSection(sectionUuid)) { - availableSections.add(sectionUuid); - } - } - } - - // Determine which enrollees are in these sections - Map uniqueEnrollees = new HashMap<>(); - for (String sectionUuid : availableSections) { - List sectionEnrollments = getSectionEnrollmentsTrusted(sectionUuid); - sectionEnrollments.forEach(e -> uniqueEnrollees.put(e.getUser().getUserUid(), e)); - } - - // Filter out based upon the original filtered students - for (String enrId : studentIdEnrRecMap.keySet()) { - if (uniqueEnrollees.containsKey(enrId)) { - // iterate through the assignments - Map itemFunctionMap = new HashMap<>(); - if (allGbItems != null && !allGbItems.isEmpty()) { - for (Object assign : allGbItems) { - Long assignId = null; - if (assign instanceof org.sakaiproject.grading.api.Assignment) { - assignId = ((org.sakaiproject.grading.api.Assignment)assign).getId(); - } else if (assign instanceof GradebookAssignment) { - assignId = ((GradebookAssignment)assign).getId(); - } - - if (assignId != null) { - itemFunctionMap.put(assignId, GradingConstants.gradePermission); - } - } - } - enrollmentMap.put(studentIdEnrRecMap.get(enrId), itemFunctionMap); - } - } - } - } + public Map findMatchingEnrollmentsForItemForUser(String userUid, String gradebookUid, String siteId, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid) { - return enrollmentMap; + return findMatchingEnrollmentsForItemOrCourseGrade(userUid, gradebookUid, siteId, categoryId, gbCategoryType, optionalSearchString, optionalSectionUid, false); } /** * @param userUid * @param gradebookUid + * @param siteId * @param categoryId + * @param gbCategoryType * @param optionalSearchString * @param optionalSectionUid * @param itemIsCourseGrade * @return Map of EnrollmentRecord --> View or Grade */ - private Map findMatchingEnrollmentsForItemOrCourseGrade(String userUid, String gradebookUid, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid, boolean itemIsCourseGrade) { + private Map findMatchingEnrollmentsForItemOrCourseGrade(String userUid, String gradebookUid, String siteId, Long categoryId, Integer gbCategoryType, String optionalSearchString, String optionalSectionUid, boolean itemIsCourseGrade) { Map enrollmentMap = new HashMap<>(); List filteredEnrollments = new ArrayList<>(); if (optionalSearchString != null) { filteredEnrollments = sectionAwareness.findSiteMembersInRole(gradebookUid, Role.STUDENT, optionalSearchString); + } else if (optionalSectionUid != null && gradebookUid.equals(optionalSectionUid)) {// this could be more efficient if we add optionalSearchString and skip the following getSectionMembersInRole, but it feels cleaner like this + filteredEnrollments = sectionAwareness.getSectionMembersInRole(gradebookUid, Role.STUDENT); } else { filteredEnrollments = sectionAwareness.getSiteMembersInRole(gradebookUid, Role.STUDENT); } @@ -564,11 +398,11 @@ private Map findMatchingEnrollmentsForItemOrCourseGrad } } - if (isUserAbleToGradeAll(gradebookUid, userUid)) { + if (isUserAbleToGradeAll(siteId, userUid)) { studentIdEnrRecMap.values().forEach(e -> enrollmentMap.put(e, GradingConstants.gradePermission)); } else { Map sectionIdCourseSectionMap = new HashMap<>(); - getAllSections(gradebookUid).forEach(cs -> sectionIdCourseSectionMap.put(cs.getUuid(), cs)); + getAllSections(siteId).forEach(cs -> sectionIdCourseSectionMap.put(cs.getUuid(), cs));// this could be more efficient for group filtering, but leaving as it is for the moment if (gradingPermissionService.userHasGraderPermissions(gradebookUid, userUid)) { // user has special grader permissions that override default perms @@ -655,28 +489,4 @@ private Map getEnrollmentMapUsingDefaultPermissions(St return enrollmentMap; } - /* - public List findStudentSectionMemberships(String gradebookUid, String studentUid) { - - List sectionMemberships = new ArrayList<>(); - try { - sectionMemberships = siteService.getSite(gradebookUid).getGroupsWithMember(studentUid); - } catch (IdUnusedException e) { - log.error("No site with id = " + gradebookUid); - } - - return sectionMemberships; - } - - public List getStudentSectionMembershipNames(String gradebookUid, String studentUid) { - - List sectionNames = new ArrayList<>(); - List sections = findStudentSectionMemberships(gradebookUid, studentUid); - if (sections != null && !sections.isEmpty()) { - sections.forEach(g -> sectionNames.add(myGroup.getTitle())); - } - - return sectionNames; - } - */ } diff --git a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingPersistenceManagerImpl.java b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingPersistenceManagerImpl.java index b41bed8d8905..ece8fe85e5a2 100644 --- a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingPersistenceManagerImpl.java +++ b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingPersistenceManagerImpl.java @@ -205,6 +205,10 @@ public Optional getExternalAssignment(String gradebookUid, return gradebookAssignmentRepository.findByGradebook_UidAndExternalId(gradebookUid, externalId); } + public List getGradebookUidByExternalId(String externalId) { + return gradebookAssignmentRepository.findByExternalId(externalId); + } + public GradebookAssignment saveGradebookAssignment(GradebookAssignment assignment) { return gradebookAssignmentRepository.save(assignment); } diff --git a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingServiceImpl.java b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingServiceImpl.java index 5f255bad6e7d..539098643511 100644 --- a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingServiceImpl.java +++ b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/GradingServiceImpl.java @@ -23,6 +23,7 @@ import java.text.NumberFormat; import java.text.ParseException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -36,6 +37,7 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; +import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; @@ -79,6 +81,7 @@ import org.sakaiproject.grading.api.GradingEventStatus; import org.sakaiproject.grading.api.InvalidCategoryException; import org.sakaiproject.grading.api.InvalidGradeException; +import org.sakaiproject.grading.api.MessageHelper; import org.sakaiproject.grading.api.SortType; import org.sakaiproject.grading.api.StaleObjectModificationException; import org.sakaiproject.grading.api.UnmappableCourseGradeOverrideException; @@ -100,6 +103,8 @@ import org.sakaiproject.grading.api.model.LetterGradePercentMapping; import org.sakaiproject.grading.api.model.LetterGradePlusMinusMapping; import org.sakaiproject.grading.api.model.PassNotPassMapping; +import org.sakaiproject.memory.api.Cache; +import org.sakaiproject.memory.api.MemoryService; import org.sakaiproject.section.api.SectionAwareness; import org.sakaiproject.section.api.coursemanagement.CourseSection; import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord; @@ -110,11 +115,10 @@ import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.tool.api.SessionManager; -import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.plus.api.PlusService; import org.sakaiproject.grading.api.GradingAuthz; import org.sakaiproject.util.ResourceLoader; - +import org.sakaiproject.util.StringUtil; import org.springframework.lang.Nullable; import org.springframework.orm.hibernate5.HibernateOptimisticLockingFailureException; @@ -133,6 +137,12 @@ @Setter public class GradingServiceImpl implements GradingService { + private String gradebookGroupEnabledCache = "org.sakaiproject.tool.gradebook.group.enabled"; + private String gradebookGroupInstancesCache = "org.sakaiproject.tool.gradebook.group.instances"; + private String matchingUserGradebookItemCache = "org.sakaiproject.tool.gradebook.group.user_gradebookItem"; + + private MemoryService memoryService; + public static final String UID_OF_DEFAULT_GRADING_SCALE_PROPERTY = "uidOfDefaultGradingScale"; public static final String PROP_COURSE_POINTS_DISPLAYED = "gradebook.coursepoints.displayed"; @@ -153,15 +163,28 @@ public class GradingServiceImpl implements GradingService { @Autowired private SecurityService securityService; @Autowired private SessionManager sessionManager; @Autowired private ServerConfigurationService serverConfigurationService; - @Autowired private ToolManager toolManager; + + // Local cache of static-between-deployment properties. private Map propertiesMap = new HashMap<>(); + public void init() { + log.debug("INIT"); + + log.debug(buildCacheLogDebug("creatingCache", gradebookGroupEnabledCache)); + log.debug(buildCacheLogDebug("creatingCache", gradebookGroupInstancesCache)); + log.debug(buildCacheLogDebug("creatingCache", matchingUserGradebookItemCache)); + + memoryService.newCache(gradebookGroupEnabledCache); + memoryService.newCache(gradebookGroupInstancesCache); + memoryService.newCache(matchingUserGradebookItemCache); + } + @Override - public boolean isAssignmentDefined(String gradebookUid, String assignmentName) { + public boolean isAssignmentDefined(String gradebookUid, String siteId, String assignmentName) { - if (!isUserAbleToViewAssignments(gradebookUid)) { + if (!isUserAbleToViewAssignments(siteId)) { log.warn("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to check for assignment {}", getUserUid(), gradebookUid, assignmentName); throw new GradingSecurityException(); @@ -170,42 +193,32 @@ public boolean isAssignmentDefined(String gradebookUid, String assignmentName) { } @Override - public boolean isUserAbleToViewAssignments(String gradebookUid) { - - return (gradingAuthz.isUserAbleToEditAssessments(gradebookUid) || gradingAuthz.isUserAbleToGrade(gradebookUid)); - } - - @Override - public boolean isUserAbleToGradeItemForStudent(String gradebookUid, Long itemId, String studentUid) { + public boolean isUserAbleToViewAssignments(String siteId) { - return gradingAuthz.isUserAbleToGradeItemForStudent(gradebookUid, itemId, studentUid); + return (gradingAuthz.isUserAbleToEditAssessments(siteId) || gradingAuthz.isUserAbleToGrade(siteId)); } - @Override - public boolean isUserAbleToViewItemForStudent(String gradebookUid, Long itemId, String studentUid) { + private boolean isUserAbleToGradeItemForStudent(String gradebookUid, String siteId, Long itemId, String studentUid) { - return gradingAuthz.isUserAbleToViewItemForStudent(gradebookUid, itemId, studentUid); + return gradingAuthz.isUserAbleToGradeItemForStudent(gradebookUid, siteId, itemId, studentUid); } - @Override - public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, Long itemId, String studentUid) { + private boolean isUserAbleToViewItemForStudent(String gradebookUid, String siteId, Long itemId, String studentUid) { - return gradingAuthz.getGradeViewFunctionForUserForStudentForItem(gradebookUid, itemId, studentUid); + return gradingAuthz.isUserAbleToViewItemForStudent(gradebookUid, siteId, itemId, studentUid); } @Override - @Transactional - public List getAssignments(String gradebookUid) { + public String getGradeViewFunctionForUserForStudentForItem(String gradebookUid, String siteId, Long itemId, String studentUid) { - initGradebook(gradebookUid); - return getAssignments(gradebookUid, SortType.SORT_BY_NONE); + return gradingAuthz.getGradeViewFunctionForUserForStudentForItem(gradebookUid, siteId, itemId, studentUid); } @Override @Transactional - public List getAssignments(String gradebookUid, SortType sortBy) { + public List getAssignments(String gradebookUid, String siteId, SortType sortBy) { - if (!isUserAbleToViewAssignments(gradebookUid)) { + if (!isUserAbleToViewAssignments(siteId)) { log.warn("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to get assignments list", getUserUid(), gradebookUid); throw new GradingSecurityException(); } @@ -223,13 +236,13 @@ public List getAssignments(String gradebookUid, SortType sortBy) { } @Override - public Assignment getAssignment(String gradebookUid, Long assignmentId) throws AssessmentNotFoundException { + public Assignment getAssignment(String gradebookUid, String siteId, Long assignmentId) throws AssessmentNotFoundException { if (assignmentId == null || gradebookUid == null) { throw new IllegalArgumentException("null parameter passed to getAssignment. Values are assignmentId:" + assignmentId + " gradebookUid:" + gradebookUid); } - if (!isUserAbleToViewAssignments(gradebookUid) && !currentUserHasViewOwnGradesPerm(gradebookUid)) { + if (!isUserAbleToViewAssignments(siteId) && !currentUserHasViewOwnGradesPerm(siteId)) { log.warn("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to get assignment with id {}", getUserUid(), gradebookUid, assignmentId); throw new GradingSecurityException(); @@ -245,14 +258,14 @@ public Assignment getAssignment(String gradebookUid, Long assignmentId) throws A } @Override - @Deprecated - public Assignment getAssignment(String gradebookUid, String assignmentName) throws AssessmentNotFoundException { + @Deprecated // used on external tools, it will always be a site=id situation until SAK-49493 is completed + public Assignment getAssignment(String gradebookUid, String siteId, String assignmentName) throws AssessmentNotFoundException { if (assignmentName == null || gradebookUid == null) { throw new IllegalArgumentException("null parameter passed to getAssignment. Values are assignmentName:" + assignmentName + " gradebookUid:" + gradebookUid); } - if (!isUserAbleToViewAssignments(gradebookUid) && !currentUserHasViewOwnGradesPerm(gradebookUid)) { + if (!isUserAbleToViewAssignments(siteId) && !currentUserHasViewOwnGradesPerm(siteId)) { log.warn("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to get assignment {}", getUserUid(), gradebookUid, assignmentName); throw new GradingSecurityException(); @@ -267,15 +280,26 @@ public Assignment getExternalAssignment(String gradebookUid, String externalId) return getDbExternalAssignment(gradebookUid, externalId).map(this::getAssignmentDefinition) .orElseThrow(() -> new IllegalArgumentException("Invalid gradebookUid or externalId")); - //return getAssignmentDefinition(getDbExternalAssignment(gradebookUid, externalId).get()); + } + + public List getGradebookUidByExternalId(String externalId) { + + List optAsn = gradingPersistenceManager.getGradebookUidByExternalId(externalId); + if (optAsn.isEmpty()) { + return new ArrayList<>(); + } + + return optAsn.stream() + .map(a -> a.getGradebook().getUid()) + .collect(Collectors.toList()); } @Override - public Assignment getAssignmentByNameOrId(String gradebookUid, String assignmentName) throws AssessmentNotFoundException { + public Assignment getAssignmentByNameOrId(String gradebookUid, String siteId, String assignmentName) throws AssessmentNotFoundException { Assignment assignment = null; try { - assignment = getAssignment(gradebookUid, assignmentName); + assignment = getAssignment(gradebookUid, siteId, assignmentName); } catch (AssessmentNotFoundException e) { // Don't fail on this exception log.debug("Assessment not found by name", e); @@ -285,7 +309,7 @@ public Assignment getAssignmentByNameOrId(String gradebookUid, String assignment // Try to get the assignment by id if (NumberUtils.isCreatable(assignmentName)) { final Long assignmentId = NumberUtils.toLong(assignmentName, -1L); - return getAssignment(gradebookUid, assignmentId); + return getAssignment(gradebookUid, siteId, assignmentId); } } return assignment; @@ -328,17 +352,6 @@ private Assignment getAssignmentDefinition(GradebookAssignment internalAssignmen return assignmentDefinition; } - // Legacy method - Removed 2022-08-21 - Chuck S. - /* - private Long createAssignment(Long gradebookId, String name, Double points, Date dueDate, Boolean isNotCounted, - Boolean isReleased, Boolean isExtraCredit, Integer sortOrder) - throws ConflictingAssignmentNameException, StaleObjectModificationException { - - Assignment assignmentDefinition = null; - return createNewAssignment(gradebookId, null, name, points, dueDate, isNotCounted, isReleased, isExtraCredit, sortOrder, null, assignmentDefinition); - } - */ - private Long createAssignment(Long gradebookId, String name, Double points, Date dueDate, Boolean isNotCounted, Boolean isReleased, Boolean isExtraCredit, Integer sortOrder, Assignment assignmentDefinition) @@ -347,21 +360,6 @@ private Long createAssignment(Long gradebookId, String name, Double points, Date return createNewAssignment(gradebookId, null, name, points, dueDate, isNotCounted, isReleased, isExtraCredit, sortOrder, null, assignmentDefinition); } - // Legacy method - Removed 2022-08-21 - Chuck S. - /* - private Long createAssignmentForCategory(Long gradebookId, Long categoryId, String name, Double points, Date dueDate, Boolean isNotCounted, - Boolean isReleased, Boolean isExtraCredit, Integer categorizedSortOrder) - throws ConflictingAssignmentNameException, StaleObjectModificationException, IllegalArgumentException { - - if (gradebookId == null || categoryId == null) { - throw new IllegalArgumentException("gradebookId or categoryId is null in BaseHibernateManager.createAssignmentForCategory"); - } - - Assignment assignmentDefinition = null; - return createNewAssignment(gradebookId, categoryId, name, points, dueDate, isNotCounted, isReleased, isExtraCredit, null, categorizedSortOrder, assignmentDefinition); - } - */ - private Long createAssignmentForCategory(Long gradebookId, Long categoryId, String name, Double points, Date dueDate, Boolean isNotCounted, Boolean isReleased, Boolean isExtraCredit, Integer categorizedSortOrder, Assignment assignmentDefinition) throws ConflictingAssignmentNameException, StaleObjectModificationException, IllegalArgumentException { @@ -430,7 +428,7 @@ private Long saveNewAssignment(Long gradebookId, Long categoryId, GradebookAssig - public void updateGradebook(final Gradebook gradebook) throws StaleObjectModificationException { + public void updateGradebook(final Gradebook gradebook, final String siteId) throws StaleObjectModificationException { // Get the gradebook and selected mapping from persistence //final Gradebook gradebookFromPersistence = (Gradebook)session.load(gradebook.getClass(), gradebook.getId()); @@ -440,7 +438,7 @@ public void updateGradebook(final Gradebook gradebook) throws StaleObjectModific // If the mapping has changed, and there are explicitly entered // course grade records, disallow this update. if (!mappingFromPersistence.getId().equals(gradebook.getSelectedGradeMapping().getId())) { - if (hasExplicitlyEnteredCourseGradeRecords(gradebook.getId())) { + if (hasExplicitlyEnteredCourseGradeRecords(gradebook.getId(), siteId)) { throw new IllegalStateException("Selected grade mapping can not be changed, since explicit course grades exist."); } } @@ -460,9 +458,9 @@ public void updateGradebook(final Gradebook gradebook) throws StaleObjectModific } } - public boolean hasExplicitlyEnteredCourseGradeRecords(final Long gradebookId) { + private boolean hasExplicitlyEnteredCourseGradeRecords(final Long gradebookId, final String siteId) { - final Set studentIds = getAllStudentUids(getGradebookUid(gradebookId)); + final Set studentIds = getAllStudentUids(siteId); if (studentIds.isEmpty()) { return false; @@ -473,7 +471,7 @@ public boolean hasExplicitlyEnteredCourseGradeRecords(final Long gradebookId) { @Override - public GradeDefinition getGradeDefinitionForStudentForItem(final String gradebookUid, final Long assignmentId, final String studentUid) { + public GradeDefinition getGradeDefinitionForStudentForItem(final String gradebookUid, final String siteId, final Long assignmentId, final String studentUid) { if (gradebookUid == null || assignmentId == null || studentUid == null) { throw new IllegalArgumentException("Null paraemter passed to getGradeDefinitionForStudentForItem"); @@ -481,16 +479,16 @@ public GradeDefinition getGradeDefinitionForStudentForItem(final String gradeboo // studentId can be a groupId (from Assignments) final boolean studentRequestingOwnScore = sessionManager.getCurrentSessionUserId().equals(studentUid) - || isCurrentUserFromGroup(gradebookUid, studentUid); + || isCurrentUserFromGroup(siteId, studentUid); - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); if (assignment == null) { throw new AssessmentNotFoundException( "There is no assignment with the assignmentId " + assignmentId + " in gradebook " + gradebookUid); } - if (!studentRequestingOwnScore && !isUserAbleToViewItemForStudent(gradebookUid, assignment.getId(), studentUid)) { + if (!studentRequestingOwnScore && !isUserAbleToViewItemForStudent(gradebookUid, siteId, assignment.getId(), studentUid)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to retrieve grade for student {} for assignment {}", getUserUid(), gradebookUid, studentUid, assignmentId); throw new GradingSecurityException(); @@ -559,13 +557,13 @@ public GradeDefinition getGradeDefinitionForStudentForItem(final String gradeboo } @Override - public GradebookInformation getGradebookInformation(final String gradebookUid) { + public GradebookInformation getGradebookInformation(final String gradebookUid, final String siteId) { if (gradebookUid == null) { throw new IllegalArgumentException("null gradebookUid " + gradebookUid); } - if (!currentUserHasEditPerm(gradebookUid) && !currentUserHasGradingPerm(gradebookUid)) { + if (!currentUserHasEditPerm(siteId) && !currentUserHasGradingPerm(siteId)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to access gb information", getUserUid(), gradebookUid); throw new GradingSecurityException(); } @@ -599,7 +597,7 @@ public GradebookInformation getGradebookInformation(final String gradebookUid) { rval.setDisplayReleasedGradeItemsToStudents(gradebook.getAssignmentsDisplayed()); // add in the category definitions - rval.setCategories(getCategoryDefinitions(gradebookUid)); + rval.setCategories(getCategoryDefinitions(gradebookUid, siteId)); // add in the course grade display settings rval.setCourseGradeDisplayed(gradebook.getCourseGradeDisplayed()); @@ -624,7 +622,7 @@ public GradebookInformation getGradebookInformation(final String gradebookUid) { @Override public Map transferGradebook(final GradebookInformation gradebookInformation, - final List assignments, final String toGradebookUid, final String fromContext) { + final List assignments, final String toGradebookUid, final String fromContext) { final Map transversalMap = new HashMap<>(); @@ -646,7 +644,7 @@ public Map transferGradebook(final GradebookInformation gradebook gradebook.setCoursePointsDisplayed(gradebookInformation.getCoursePointsDisplayed()); gradebook.setCourseAverageDisplayed(gradebookInformation.getCourseAverageDisplayed()); - updateGradebook(gradebook); + updateGradebook(gradebook, toGradebookUid); // all categories that we need to end up with final List categories = gradebookInformation.getCategories(); @@ -666,11 +664,13 @@ public Map transferGradebook(final GradebookInformation gradebook categories.forEach(c -> { assignments.forEach(a -> { + String taskName = isGradebookGroupEnabled(fromContext) + ? a.getName().substring(a.getName().indexOf('-') + 1) + : a.getName(); if (StringUtils.equals(c.getName(), a.getCategoryName())) { if (!categoriesCreated.containsKey(c.getName())) { - // create category Long categoryId = null; try { @@ -683,7 +683,7 @@ public Map transferGradebook(final GradebookInformation gradebook if (categoryId == null) { // couldn't create so look up the id in the target site - final List existingCategories = getCategoryDefinitions(gradebook.getUid()); + final List existingCategories = getCategoryDefinitions(gradebook.getUid(), gradebook.getUid()); categoryId = existingCategories.stream().filter(e -> StringUtils.equals(e.getName(), c.getName())) .findFirst().get().getId(); } @@ -694,18 +694,18 @@ public Map transferGradebook(final GradebookInformation gradebook // create the assignment for the current category try { - Long newId = createAssignmentForCategory(gradebook.getId(), categoriesCreated.get(c.getName()), a.getName(), a.getPoints(), + Long newId = createAssignmentForCategory(gradebook.getId(), categoriesCreated.get(c.getName()), taskName, a.getPoints(), a.getDueDate(), !a.getCounted(), a.getReleased(), a.getExtraCredit(), a.getCategorizedSortOrder(), null); transversalMap.put("gb/"+a.getId(),"gb/"+newId); } catch (final ConflictingAssignmentNameException e) { // assignment already exists. Could be from a merge. - log.info("GradebookAssignment: {} already exists in target site. Skipping creation.", a.getName()); + log.info("GradebookAssignment: {} already exists in target site. Skipping creation.", taskName); } catch (final Exception ex) { - log.warn("GradebookAssignment: exception {} trying to create {} in target site. Skipping creation.", ex.getMessage(), a.getName()); + log.warn("GradebookAssignment: exception {} trying to create {} in target site. Skipping creation.", ex.getMessage(), taskName); } // record that we have created this assignment - assignmentsCreated.add(a.getName()); + assignmentsCreated.add(taskName); } }); }); @@ -724,17 +724,26 @@ public Map transferGradebook(final GradebookInformation gradebook } // create any remaining assignments that have no categories - assignments.removeIf(a -> assignmentsCreated.contains(a.getName())); + assignments.removeIf(a -> { + String taskName = isGradebookGroupEnabled(fromContext) + ? (a.getName().contains("-") ? a.getName().substring(a.getName().indexOf('-') + 1) : a.getName()) + : a.getName(); + + return assignmentsCreated.contains(taskName); + }); assignments.forEach(a -> { + String taskName = isGradebookGroupEnabled(fromContext) + ? a.getName().substring(a.getName().indexOf('-') + 1) + : a.getName(); try { - Long newId = createAssignment(gradebook.getId(), a.getName(), a.getPoints(), a.getDueDate(), !a.getCounted(), a.getReleased(), a.getExtraCredit(), a.getSortOrder(), null); + Long newId = createAssignment(gradebook.getId(), taskName, a.getPoints(), a.getDueDate(), !a.getCounted(), a.getReleased(), a.getExtraCredit(), a.getSortOrder(), null); transversalMap.put("gb/"+a.getId(),"gb/"+newId); } catch (final ConflictingAssignmentNameException e) { // assignment already exists. Could be from a merge. - log.info("GradebookAssignment: {} already exists in target site. Skipping creation.", a.getName()); + log.info("GradebookAssignment: {} already exists in target site. Skipping creation.", taskName); } catch (final Exception ex) { - log.warn("GradebookAssignment: exception {} trying to create {} in target site. Skipping creation.", ex.getMessage(), a.getName()); + log.warn("GradebookAssignment: exception {} trying to create {} in target site. Skipping creation.", ex.getMessage(), taskName); } }); @@ -758,7 +767,7 @@ public Map transferGradebook(final GradebookInformation gradebook gradeMapping.getGradeMap().put(gradeCode, inputGradePercents.get(gradeCode)); } gradebook.setSelectedGradeMapping(gradeMapping); - updateGradebook(gradebook); + updateGradebook(gradebook, toGradebookUid); log.info("Merge to gradebook {} updated grade mapping", toGradebookUid); break MERGE_GRADE_MAPPING; @@ -787,9 +796,9 @@ public void removeAssignment(Long assignmentId) throws StaleObjectModificationEx } @Override - public Long addAssignment(final String gradebookUid, Assignment assignmentDefinition) { + public Long addAssignment(final String gradebookUid, final String siteId, Assignment assignmentDefinition) { - if (!gradingAuthz.isUserAbleToEditAssessments(gradebookUid)) { + if (!gradingAuthz.isUserAbleToEditAssessments(siteId)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to add an assignment", getUserUid(), gradebookUid); throw new GradingSecurityException(); } @@ -813,7 +822,7 @@ public Long addAssignment(final String gradebookUid, Assignment assignmentDefini // Check if this ia a plus course - if ( plusService.enabled() ) { + if ( plusService.enabled() && isCurrentGbSite(gradebookUid)) { try { final Site site = this.siteService.getSite(gradebookUid); if ( plusService.enabled(site) ) { @@ -822,7 +831,7 @@ public Long addAssignment(final String gradebookUid, Assignment assignmentDefini log.debug("Lineitem={} created assignment={} gradebook={}", lineItem, assignmentId, gradebookUid); // Update the assignment with the new lineItem - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); if (assignment == null) { throw new AssessmentNotFoundException( "There is no assignment with id " + assignmentId + " in gradebook " + gradebookUid); @@ -841,9 +850,9 @@ public Long addAssignment(final String gradebookUid, Assignment assignmentDefini @SuppressWarnings({ "unchecked", "rawtypes" }) @Override - public void updateAssignment(final String gradebookUid, final Long assignmentId, final Assignment assignmentDefinition) { + public void updateAssignment(final String gradebookUid, final String siteId, final Long assignmentId, final Assignment assignmentDefinition) { - if (!gradingAuthz.isUserAbleToEditAssessments(gradebookUid)) { + if (!gradingAuthz.isUserAbleToEditAssessments(siteId)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to change the definition of assignment {}", getUserUid(), gradebookUid, assignmentId); throw new GradingSecurityException(); @@ -853,7 +862,7 @@ public void updateAssignment(final String gradebookUid, final Long assignmentId, final Gradebook gradebook = this.getGradebook(gradebookUid); - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); if (assignment == null) { throw new AssessmentNotFoundException( "There is no assignment with id " + assignmentId + " in gradebook " + gradebookUid); @@ -904,7 +913,7 @@ public void updateAssignment(final String gradebookUid, final Long assignmentId, } // Check if this is a plus course - if ( plusService.enabled() ) { + if ( plusService.enabled() && isCurrentGbSite(gradebookUid)) { try { final Site site = this.siteService.getSite(gradebookUid); if ( plusService.enabled(site) ) { @@ -1219,9 +1228,8 @@ private List getTotalPointsEarnedInternal(final String studentId, final * @param id * @return * - * NOTE: When the UI changes, this is to be turned private again */ - public Gradebook getGradebook(Long id) { + private Gradebook getGradebook(Long id) { return gradingPersistenceManager.getGradebook(id).orElse(null); } @@ -1231,56 +1239,6 @@ private List getAssignmentsCounted(Long gradebookId) { return gradingPersistenceManager.getCountedAssignmentsForGradebook(gradebookId); } - @Override - public boolean checkStudentsNotSubmitted(String gradebookUid) { - - final Gradebook gradebook = getGradebook(gradebookUid); - final Set studentUids = getAllStudentUids(getGradebookUid(gradebook.getId())); - if (Objects.equals(gradebook.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY) - || Objects.equals(gradebook.getCategoryType(), GradingConstants.CATEGORY_TYPE_ONLY_CATEGORY)) { - - List filteredAssigns = getAssignments(gradebook.getId(), SortType.SORT_BY_SORTING, true) - .stream().filter(a -> a.getCounted() && !a.getUngraded()).collect(Collectors.toList()); - - final List records = getAllAssignmentGradeRecords(gradebook.getId(), studentUids); - final List filteredRecords = new ArrayList<>(); - for (AssignmentGradeRecord agr : records) { - if (!agr.isCourseGradeRecord() && agr.getAssignment().getCounted() && !agr.getAssignment().getUngraded()) { - if (agr.getPointsEarned() == null) { - return true; - } - filteredRecords.add(agr); - } - } - - return filteredRecords.size() < (filteredAssigns.size() * studentUids.size()); - } else { - final List assigns = getAssignments(gradebook.getId(), SortType.SORT_BY_SORTING, true); - final List records = getAllAssignmentGradeRecords(gradebook.getId(), studentUids); - - final Set filteredAssigns = new HashSet<>(); - for (GradebookAssignment assign : assigns) { - if (assign != null && assign.getCounted() && !assign.getUngraded()) { - if (assign.getCategory() != null && !assign.getCategory().getRemoved()) { - filteredAssigns.add(assign.getId()); - } - } - } - - final List filteredRecords = new ArrayList<>(); - for (AssignmentGradeRecord agr : records) { - if (filteredAssigns.contains(agr.getAssignment().getId()) && !agr.isCourseGradeRecord()) { - if (agr.getPointsEarned() == null) { - return true; - } - filteredRecords.add(agr); - } - } - - return filteredRecords.size() < filteredAssigns.size() * studentUids.size(); - } - } - /** * Get all assignment grade records for the given students * @@ -1288,9 +1246,8 @@ public boolean checkStudentsNotSubmitted(String gradebookUid) { * @param studentUids * @return * - * NOTE When the UI changes, this needs to be made private again */ - public List getAllAssignmentGradeRecords(Long gradebookId, Collection studentUids) { + private List getAllAssignmentGradeRecords(Long gradebookId, Collection studentUids) { if (studentUids.isEmpty()) { // If there are no enrollments, no need to execute the query. @@ -1306,7 +1263,7 @@ private List getAllAssignmentGradeRecordsForGbItem(Long g if (studentUids.isEmpty()) { // If there are no enrollments, no need to execute the query. - log.debug("No enrollments were specified. Returning an empty List of grade records"); + log.debug("getAllAssignmentGradeRecordsForGbItem: No enrollments were specified. Returning an empty List of grade records"); return Collections.emptyList(); } else { List unfilteredRecords = gradingPersistenceManager.getAllAssignmentGradeRecordsForAssignment(gradableObjectId); @@ -1322,7 +1279,7 @@ private List getAllAssignmentGradeRecordsForGbItems(final final List gradeRecords = new ArrayList<>(); if (studentUids.isEmpty()) { // If there are no enrollments, no need to execute the query. - log.debug("No enrollments were specified. Returning an empty List of grade records"); + log.debug("getAllAssignmentGradeRecordsForGbItems: No enrollments were specified. Returning an empty List of grade records"); return gradeRecords; } /* @@ -1362,9 +1319,8 @@ private List getAllAssignmentGradeRecordsForGbItems(final * @param ascending * @return * - * NOTE: When the UI changes, this needs to go back to private */ - private List getAssignments(Long gradebookId, SortType sortBy, boolean ascending) { + private List getSortedAssignments(Long gradebookId, SortType sortBy, boolean ascending) { return sortAssignments(getAssignments(gradebookId), sortBy, ascending); } @@ -1378,7 +1334,6 @@ private List getAssignments(Long gradebookId, SortType sort */ private List sortAssignments(final List assignments, SortType sortBy, final boolean ascending) { - // note, this is duplicated in the tool GradebookManagerHibernateImpl class Comparator comp; if (sortBy == null) { @@ -1428,30 +1383,13 @@ private List sortAssignments(final List getViewableAssignmentsForCurrentUser(String gradebookUid) { - - return getViewableAssignmentsForCurrentUser(gradebookUid, SortType.SORT_BY_SORTING); - } - - /* - * (non-Javadoc) - * - * @see org.sakaiproject.grading.api.GradingService#getViewableAssignmentsForCurrentUser(java.lang.String, java.) - */ @Override @SuppressWarnings({ "rawtypes", "unchecked" }) - public List getViewableAssignmentsForCurrentUser(final String gradebookUid, final SortType sortBy) { + public List getViewableAssignmentsForCurrentUser(final String gradebookUid, final String siteId, final SortType sortBy) { - if (!gradingAuthz.isUserAbleToGradeAll(gradebookUid) - && !gradingAuthz.isUserAbleToGrade(gradebookUid) - && !gradingAuthz.isUserAbleToViewOwnGrades(gradebookUid)) { + if (!gradingAuthz.isUserAbleToGradeAll(siteId) + && !gradingAuthz.isUserAbleToGrade(siteId) + && !gradingAuthz.isUserAbleToViewOwnGrades(siteId)) { return Collections.emptyList(); } @@ -1461,24 +1399,24 @@ public List getViewableAssignmentsForCurrentUser(final String gradeb final Gradebook gradebook = getGradebook(gradebookUid); // will send back all assignments if user can grade all - if (gradingAuthz.isUserAbleToGradeAll(gradebookUid)) { - viewableAssignments = getAssignments(gradebook.getId(), sortBy, true); - } else if (gradingAuthz.isUserAbleToGrade(gradebookUid)) { + if (gradingAuthz.isUserAbleToGradeAll(siteId)) { + viewableAssignments = getSortedAssignments(gradebook.getId(), sortBy, true); + } else if (gradingAuthz.isUserAbleToGrade(siteId)) { // if user can grade and doesn't have grader perm restrictions, they // may view all assigns if (!gradingPermissionService.currentUserHasGraderPermissions(gradebookUid)) { - viewableAssignments = getAssignments(gradebook.getId(), sortBy, true); + viewableAssignments = getSortedAssignments(gradebook.getId(), sortBy, true); } else { // this user has grader perms, so we need to filter the items returned // if this gradebook has categories enabled, we need to check for category-specific restrictions if (Objects.equals(gradebook.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY)) { - assignmentsToReturn.addAll(getAssignments(gradebookUid, sortBy)); + assignmentsToReturn.addAll(getAssignments(gradebookUid, siteId, sortBy)); } else { final String userUid = getUserUid(); if (gradingPermissionService.getPermissionForUserForAllAssignment(gradebook.getId(), userUid)) { - assignmentsToReturn.addAll(getAssignments(gradebookUid, sortBy)); + assignmentsToReturn.addAll(getAssignments(gradebookUid, siteId, sortBy)); } else { - final List assignments = getAssignments(gradebookUid, sortBy); + final List assignments = getAssignments(gradebookUid, siteId, sortBy); final List categoryIds = ((List) getCategories(gradebook.getId())).stream().map(Category::getId) .collect(Collectors.toList()); // categories are enabled, so we need to check the category restrictions @@ -1494,9 +1432,9 @@ public List getViewableAssignmentsForCurrentUser(final String gradeb } } } - } else if (gradingAuthz.isUserAbleToViewOwnGrades(gradebookUid)) { + } else if (gradingAuthz.isUserAbleToViewOwnGrades(siteId)) { // if user is just a student, we need to filter out unreleased items - final List allAssigns = getAssignments(gradebook.getId(), sortBy, true); + final List allAssigns = getSortedAssignments(gradebook.getId(), sortBy, true); if (allAssigns != null) { for (final Iterator aIter = allAssigns.iterator(); aIter.hasNext();) { final GradebookAssignment assign = (GradebookAssignment) aIter.next(); @@ -1519,16 +1457,9 @@ public List getViewableAssignmentsForCurrentUser(final String gradeb return new ArrayList<>(assignmentsToReturn); } - @Override - public Map getViewableStudentsForItemForCurrentUser(String gradebookUid, Long gradableObjectId) { - - String userUid = sessionManager.getCurrentSessionUserId(); - return getViewableStudentsForItemForUser(userUid, gradebookUid, gradableObjectId); - } - @Override @SuppressWarnings({ "rawtypes", "unchecked" }) - public Map getViewableStudentsForItemForUser(String userUid, String gradebookUid, Long gradableObjectId) { + public Map getViewableStudentsForItemForUser(String userUid, String gradebookUid, String siteId, Long gradableObjectId) { if (gradebookUid == null || gradableObjectId == null || userUid == null) { throw new IllegalArgumentException("null gradebookUid or gradableObjectId or " + @@ -1537,7 +1468,7 @@ public Map getViewableStudentsForItemForUser(String userUid, Str gradableObjectId + " userId: " + userUid); } - if (!this.gradingAuthz.isUserAbleToGrade(gradebookUid, userUid)) { + if (!this.gradingAuthz.isUserAbleToGrade(siteId, userUid)) { return new HashMap<>(); } @@ -1550,8 +1481,8 @@ public Map getViewableStudentsForItemForUser(String userUid, Str final Long categoryId = gradebookItem.getCategory() == null ? null : gradebookItem.getCategory().getId(); - final Map enrRecFunctionMap = this.gradingAuthz.findMatchingEnrollmentsForItemForUser(userUid, gradebookUid, - categoryId, getGradebook(gradebookUid).getCategoryType(), null, null); + final Map enrRecFunctionMap = this.gradingAuthz.findMatchingEnrollmentsForItemForUser(userUid, gradebookUid, siteId, + categoryId, getGradebook(gradebookUid).getCategoryType(), null, isCurrentGbSite(gradebookUid) ? null : gradebookUid); if (enrRecFunctionMap == null) { return new HashMap(); } @@ -1567,70 +1498,49 @@ public Map getViewableStudentsForItemForUser(String userUid, Str } @Override - public boolean isGradableObjectDefined(final Long gradableObjectId) { - - if (gradableObjectId == null) { - throw new IllegalArgumentException("null gradableObjectId passed to isGradableObjectDefined"); - } - - return gradingPersistenceManager.isAssignmentDefined(gradableObjectId); - } - - @Override - public Map getViewableSectionUuidToNameMap(String gradebookUid) { - - if (gradebookUid == null) { - throw new IllegalArgumentException("Null gradebookUid passed to getViewableSectionIdToNameMap"); - } - - return gradingAuthz.getViewableSections(gradebookUid).stream().filter(Objects::nonNull) - .collect(Collectors.toMap(s -> s.getUuid(), s -> s.getTitle())); - } - - @Override - public boolean currentUserHasGradeAllPerm(final String gradebookUid) { + public boolean currentUserHasGradeAllPerm(final String siteId) { - return this.gradingAuthz.isUserAbleToGradeAll(gradebookUid); + return this.gradingAuthz.isUserAbleToGradeAll(siteId); } @Override - public boolean isUserAllowedToGradeAll(final String gradebookUid, final String userUid) { + public boolean isUserAllowedToGradeAll(final String siteId, final String userUid) { - return this.gradingAuthz.isUserAbleToGradeAll(gradebookUid, userUid); + return this.gradingAuthz.isUserAbleToGradeAll(siteId, userUid); } @Override - public boolean currentUserHasGradingPerm(String gradebookUid) { + public boolean currentUserHasGradingPerm(String siteId) { - return gradingAuthz.isUserAbleToGrade(gradebookUid); + return gradingAuthz.isUserAbleToGrade(siteId); } @Override - public boolean isUserAllowedToGrade(final String gradebookUid, final String userUid) { + public boolean isUserAllowedToGrade(final String siteId, final String userUid) { - return this.gradingAuthz.isUserAbleToGrade(gradebookUid, userUid); + return this.gradingAuthz.isUserAbleToGrade(siteId, userUid); } @Override - public boolean currentUserHasEditPerm(final String gradebookUid) { + public boolean currentUserHasEditPerm(final String siteId) { - return this.gradingAuthz.isUserAbleToEditAssessments(gradebookUid); + return this.gradingAuthz.isUserAbleToEditAssessments(siteId); } @Override - public boolean currentUserHasViewOwnGradesPerm(final String gradebookUid) { + public boolean currentUserHasViewOwnGradesPerm(final String siteId) { - return this.gradingAuthz.isUserAbleToViewOwnGrades(gradebookUid); + return this.gradingAuthz.isUserAbleToViewOwnGrades(siteId); } @Override - public boolean currentUserHasViewStudentNumbersPerm(final String gradebookUid) { + public boolean currentUserHasViewStudentNumbersPerm(final String siteId) { - return this.gradingAuthz.isUserAbleToViewStudentNumbers(gradebookUid); + return this.gradingAuthz.isUserAbleToViewStudentNumbers(siteId); } @Override - public List getGradesForStudentsForItem(final String gradebookUid, final Long gradableObjectId, + public List getGradesForStudentsForItem(final String gradebookUid, final String siteId, final Long gradableObjectId, final List studentIds) { if (gradableObjectId == null) { @@ -1650,7 +1560,7 @@ public List getGradesForStudentsForItem(final String gradebookU if (gbItem != null) { final Gradebook gradebook = gbItem.getGradebook(); - if (!this.gradingAuthz.isUserAbleToGrade(gradebook.getUid())) { + if (!this.gradingAuthz.isUserAbleToGrade(siteId)) { log.error( "User {} attempted to access grade information without permission in gb {} using gradebookService.getGradesForStudentsForItem", sessionManager.getCurrentSessionUserId(), gradebook.getUid()); @@ -1658,8 +1568,8 @@ public List getGradesForStudentsForItem(final String gradebookU } final Long categoryId = gbItem.getCategory() != null ? gbItem.getCategory().getId() : null; - final Map enrRecFunctionMap = this.gradingAuthz.findMatchingEnrollmentsForItem(gradebook.getUid(), categoryId, - gradebook.getCategoryType(), null, null); + final Map enrRecFunctionMap = this.gradingAuthz.findMatchingEnrollmentsForItem(gradebook.getUid(), siteId, categoryId, + gradebook.getCategoryType(), null, isCurrentGbSite(gradebook.getUid()) ? null : gradebook.getUid()); final Set enrRecs = enrRecFunctionMap.keySet(); final Map studentIdEnrRecMap = new HashMap(); if (enrRecs != null) { @@ -1727,7 +1637,7 @@ public List getGradesForStudentsForItem(final String gradebookU } @Override - public Map> getGradesWithoutCommentsForStudentsForItems(final String gradebookUid, + public Map> getGradesWithoutCommentsForStudentsForItems(final String gradebookUid, final String siteId, final List gradableObjectIds, final List studentIds) { if (gradableObjectIds == null || gradableObjectIds.isEmpty()) { @@ -1735,8 +1645,8 @@ public Map> getGradesWithoutCommentsForStudentsForIt } // when user is not able to grade and user isn't requesting to view only their grades throw exception - if (!this.gradingAuthz.isUserAbleToGrade(gradebookUid) && - !(currentUserHasViewOwnGradesPerm(gradebookUid) + if (!this.gradingAuthz.isUserAbleToGrade(siteId) && + !(currentUserHasViewOwnGradesPerm(siteId) && CollectionUtils.isEqualCollection(studentIds, List.of(sessionManager.getCurrentSessionUserId())))) { throw new GradingSecurityException(); } @@ -1809,7 +1719,7 @@ private GradeDefinition convertGradeRecordToGradeDefinition(final AssignmentGrad gradeDef.setGradeComment(commentText); } - Boolean excludedFromGrade = (gradeRecord.getExcludedFromGrade() != null) ? gradeRecord.getExcludedFromGrade() : Boolean.FALSE; + Boolean excludedFromGrade = (gradeRecord.getExcludedFromGrade() != null) ? gradeRecord.getExcludedFromGrade() : Boolean.FALSE; gradeDef.setExcused(excludedFromGrade); return gradeDef; @@ -1823,7 +1733,7 @@ public boolean isGradeValid(String gradebookUuid, String grade) { } Gradebook gradebook = getGradebook(gradebookUuid); - Integer gradeType = getGradebook(gradebookUuid).getGradeType(); + Integer gradeType = gradebook.getGradeType(); LetterGradePercentMapping mapping = null; if (Objects.equals(GradingConstants.GRADE_TYPE_LETTER, gradeType)) { mapping = getLetterGradePercentMapping(gradebook); @@ -1942,7 +1852,7 @@ public List identifyStudentsWithInvalidGrades(final String gradebookUid, @Override @Transactional - public void saveGradeAndCommentForStudent(final String gradebookUid, final Long gradableObjectId, final String studentUid, + public void saveGradeAndCommentForStudent(final String gradebookUid, final String siteId, final Long gradableObjectId, final String studentUid, final String grade, final String comment) { if (gradebookUid == null || gradableObjectId == null || studentUid == null) { @@ -1958,7 +1868,7 @@ public void saveGradeAndCommentForStudent(final String gradebookUid, final Long final List gradeDefList = new ArrayList<>(); gradeDefList.add(gradeDef); - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, gradableObjectId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, gradableObjectId); final AssignmentGradeRecord record = getAssignmentGradeRecord(assignment, studentUid); if (record != null) { @@ -1966,11 +1876,11 @@ public void saveGradeAndCommentForStudent(final String gradebookUid, final Long } else { gradeDef.setExcused(false); } - saveGradesAndComments(gradebookUid, gradableObjectId, gradeDefList); + saveGradesAndComments(gradebookUid, siteId, gradableObjectId, gradeDefList); } @Override - public void saveGradeAndExcuseForStudent(final String gradebookUid, final Long gradableObjectId, final String studentUid, + public void saveGradeAndExcuseForStudent(final String gradebookUid, final String siteId, final Long gradableObjectId, final String studentUid, final String grade, final boolean excuse) { if (gradebookUid == null || gradableObjectId == null || studentUid == null) { throw new IllegalArgumentException( @@ -1991,7 +1901,7 @@ public void saveGradeAndExcuseForStudent(final String gradebookUid, final Long g final List gradeDefList = new ArrayList<>(); gradeDefList.add(gradeDef); - saveGradesAndComments(gradebookUid, gradableObjectId, gradeDefList); + saveGradesAndComments(gradebookUid, siteId, gradableObjectId, gradeDefList); } /** @@ -2011,7 +1921,7 @@ public boolean getIsAssignmentExcused(final String gradebookUid, final Long assi if (gradebookUid == null || assignmentId == null || studentUid == null) { throw new IllegalArgumentException("null parameter passed to getAssignmentScoreComment. Values are gradebookUid:" + gradebookUid + " assignmentId:" + assignmentId + " studentUid:"+ studentUid); } - GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); AssignmentGradeRecord agr = getAssignmentGradeRecord(assignment, studentUid); if (agr == null) { @@ -2023,7 +1933,7 @@ public boolean getIsAssignmentExcused(final String gradebookUid, final Long assi @Override @Transactional - public void saveGradesAndComments(final String gradebookUid, final Long gradableObjectId, final List gradeDefList) { + public void saveGradesAndComments(final String gradebookUid, final String siteId, final Long gradableObjectId, final List gradeDefList) { if (gradebookUid == null || gradableObjectId == null) { throw new IllegalArgumentException("Null gradebookUid or gradableObjectId passed to saveGradesAndComments"); @@ -2038,7 +1948,7 @@ public void saveGradesAndComments(final String gradebookUid, final Long gradable throw new AssessmentNotFoundException("No gradebook item exists with gradable object id = " + gradableObjectId); } - if (!currentUserHasGradingPerm(gradebookUid)) { + if (!currentUserHasGradingPerm(siteId)) { log.warn("User attempted to save grades and comments without authorization"); throw new GradingSecurityException(); } @@ -2061,7 +1971,7 @@ public void saveGradesAndComments(final String gradebookUid, final Long gradable final List invalidStudentUUIDs = identifyStudentsWithInvalidGrades(gradebookUid, studentIdToGradeMap); if (CollectionUtils.isNotEmpty(invalidStudentUUIDs)) { throw new InvalidGradeException( - "At least one grade passed to be updated is " + "invalid. No grades or comments were updated."); + "At least one grade passed to be updated is invalid. No grades or comments were updated."); } // Retrieve all existing grade records for the given students and assignment @@ -2085,7 +1995,7 @@ public void saveGradesAndComments(final String gradebookUid, final Long gradable Gradebook gradebook = getGradebook(gradebookUid); - final boolean userHasGradeAllPerm = currentUserHasGradeAllPerm(gradebookUid); + final boolean userHasGradeAllPerm = currentUserHasGradeAllPerm(siteId); final String graderId = sessionManager.getCurrentSessionUserId(); final Date now = new Date(); LetterGradePercentMapping mapping = null; @@ -2112,7 +2022,7 @@ public void saveGradesAndComments(final String gradebookUid, final Long gradable // check specific grading privileges if user does not have // grade all perm if (!userHasGradeAllPerm) { - if (!isUserAbleToGradeItemForStudent(gradebookUid, gradableObjectId, studentId)) { + if (!isUserAbleToGradeItemForStudent(gradebookUid, siteId, gradableObjectId, studentId)) { log.warn("User {} attempted to save a grade for {} without authorization", graderId, studentId); throw new GradingSecurityException(); } @@ -2209,18 +2119,6 @@ public void saveGradesAndComments(final String gradebookUid, final Long gradable } } - /** - * Helper method to retrieve Assignment by ID without stats for the given gradebook. Reduces code duplication in several areas. - * - * @param gradebookUID - * @param gradeableObjectID - * @return - */ - private GradebookAssignment getAssignmentWithoutStatsByID(String gradebookUID, Long gradeableObjectID) { - - return getAssignmentWithoutStats(gradebookUID, gradeableObjectID); - } - /** * * @param gradeEntryType @@ -2297,48 +2195,7 @@ public Integer getGradeEntryType(String gradebookUid) { } @Override - public Map getEnteredCourseGrade(final String gradebookUid) { - - final Gradebook thisGradebook = getGradebook(gradebookUid); - - final Long gradebookId = thisGradebook.getId(); - final CourseGrade courseGrade = getCourseGrade(gradebookId); - - Map enrollmentMap; - - final Map viewableEnrollmentsMap - = gradingAuthz.findMatchingEnrollmentsForViewableCourseGrade(gradebookUid, thisGradebook.getCategoryType(), null, null); - - enrollmentMap = new HashMap(); - - final Map enrollmentMapUid = new HashMap(); - for (final Iterator iter = viewableEnrollmentsMap.keySet().iterator(); iter.hasNext();) { - final EnrollmentRecord enr = (EnrollmentRecord) iter.next(); - enrollmentMap.put(enr.getUser().getUserUid(), enr); - enrollmentMapUid.put(enr.getUser().getUserUid(), enr); - } - - final List unfilteredRecords - = gradingPersistenceManager.getCourseGradeRecordsForCourseGrade(courseGrade.getId()); - - final List records = filterAndPopulateCourseGradeRecordsByStudents(courseGrade, unfilteredRecords, enrollmentMap.keySet()); - - final Map returnMap = new HashMap(); - - for (CourseGradeRecord cgr : records) { - if (cgr.getEnteredGrade() != null && !cgr.getEnteredGrade().equalsIgnoreCase("")) { - final EnrollmentRecord enr = (EnrollmentRecord) enrollmentMapUid.get(cgr.getStudentId()); - if (enr != null) { - returnMap.put(enr.getUser().getDisplayId(), cgr.getEnteredGrade()); - } - } - } - - return returnMap; - } - - @Override - public String getAssignmentScoreString(String gradebookUid, Long assignmentId, String studentUid) + public String getAssignmentScoreString(String gradebookUid, String siteId, Long assignmentId, String studentUid) throws AssessmentNotFoundException { final boolean studentRequestingOwnScore = sessionManager.getCurrentSessionUserId().equals(studentUid); @@ -2350,13 +2207,13 @@ public String getAssignmentScoreString(String gradebookUid, Long assignmentId, S Double assignmentScore = null; - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); if (assignment == null) { throw new AssessmentNotFoundException( "There is no assignment with id " + assignmentId + " in gradebook " + gradebookUid); } - if (!studentRequestingOwnScore && !isUserAbleToViewItemForStudent(gradebookUid, assignmentId, studentUid)) { + if (!studentRequestingOwnScore && !isUserAbleToViewItemForStudent(gradebookUid, siteId, assignmentId, studentUid)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to retrieve grade for student {} for assignment {}", getUserUid(), gradebookUid, studentUid, assignment.getName()); throw new GradingSecurityException(); @@ -2395,56 +2252,10 @@ public String getAssignmentScoreString(String gradebookUid, Long assignmentId, S } @Override - public String getAssignmentScoreString(final String gradebookUid, final String assignmentName, final String studentUid) - throws AssessmentNotFoundException { - - if (gradebookUid == null || assignmentName == null || studentUid == null) { - throw new IllegalArgumentException("null parameter passed to getAssignment. Values are gradebookUid:" - + gradebookUid + " assignmentName:" + assignmentName + " studentUid:" + studentUid); - } - - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentName); - - if (assignment == null) { - throw new AssessmentNotFoundException("There is no assignment with name " + assignmentName + " in gradebook " + gradebookUid); - } - - return getAssignmentScoreString(gradebookUid, assignment.getId(), studentUid); - } - - @Override - public String getAssignmentScoreStringByNameOrId(final String gradebookUid, final String assignmentName, final String studentUid) - throws AssessmentNotFoundException { - String score = null; - try { - score = getAssignmentScoreString(gradebookUid, assignmentName, studentUid); - } catch (final AssessmentNotFoundException e) { - // Don't fail on this exception - log.debug("Assessment not found by name", e); - } catch (final GradingSecurityException gse) { - log.warn("User {} does not have permission to retrieve score for assignment {}", studentUid, assignmentName, gse); - return null; - } - - if (score == null) { - // Try to get the assignment by id - if (NumberUtils.isCreatable(assignmentName)) { - final Long assignmentId = NumberUtils.toLong(assignmentName, -1L); - try { - score = getAssignmentScoreString(gradebookUid, assignmentId, studentUid); - } catch (AssessmentNotFoundException anfe) { - log.debug("Assessment could not be found for gradebook id {} and assignment id {} and student id {}", gradebookUid, assignmentName, studentUid); - } - } - } - return score; - } - - @Override - public void setAssignmentScoreString(String gradebookUid, Long assignmentId, String studentUid, String score, String clientServiceDescription) + public void setAssignmentScoreString(String gradebookUid, String siteId, Long assignmentId, String studentUid, String score, String clientServiceDescription) throws AssessmentNotFoundException { - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); if (assignment == null) { throw new AssessmentNotFoundException( "There is no assignment with id " + assignmentId + " in gradebook " + gradebookUid); @@ -2456,7 +2267,7 @@ public void setAssignmentScoreString(String gradebookUid, Long assignmentId, Str throw new GradingSecurityException(); } - if (!isUserAbleToGradeItemForStudent(gradebookUid, assignment.getId(), studentUid)) { + if (!isUserAbleToGradeItemForStudent(gradebookUid, siteId, assignment.getId(), studentUid)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to grade student {} from {} for item {}", getUserUid(), gradebookUid, studentUid, clientServiceDescription, assignmentId); throw new GradingSecurityException(); @@ -2487,82 +2298,23 @@ public void setAssignmentScoreString(String gradebookUid, Long assignmentId, Str } @Override - public void setAssignmentScoreString(String gradebookUid, String assignmentName, String studentUid, String score, String clientServiceDescription) - throws AssessmentNotFoundException { - - GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentName); - - if (assignment == null) { - throw new AssessmentNotFoundException("There is no assignment with name " + assignmentName + " in gradebook " + gradebookUid); - } - - setAssignmentScoreString(gradebookUid, assignment.getId(), studentUid, score, clientServiceDescription); - } - - @Override - public void finalizeGrades(final String gradebookUid) { - - if (!gradingAuthz.isUserAbleToGradeAll(gradebookUid)) { - log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to finalize grades", getUserUid(), gradebookUid); - throw new GradingSecurityException(); - } - finalizeNullGradeRecords(getGradebook(gradebookUid)); - } - - @Override - public String getLowestPossibleGradeForGbItem(final String gradebookUid, final Long gradebookItemId) { - - if (gradebookUid == null || gradebookItemId == null) { - throw new IllegalArgumentException("Null gradebookUid and/or gradebookItemId " + - "passed to getLowestPossibleGradeForGbItem. gradebookUid:" + - gradebookUid + " gradebookItemId:" + gradebookItemId); - } - - final GradebookAssignment gbItem = getAssignmentWithoutStatsByID(gradebookUid, gradebookItemId); - - if (gbItem == null) { - throw new AssessmentNotFoundException("No gradebook item found with id " + gradebookItemId); - } - - final Gradebook gradebook = gbItem.getGradebook(); - - // double check that user has some permission to access gb items in this site - if (!isUserAbleToViewAssignments(gradebookUid) && !currentUserHasViewOwnGradesPerm(gradebookUid)) { - throw new GradingSecurityException(); - } - - String lowestPossibleGrade = null; - - if (gbItem.getUngraded()) { - lowestPossibleGrade = null; - } else if (Objects.equals(GradingConstants.GRADE_TYPE_PERCENTAGE, gradebook.getGradeType()) || Objects.equals(GradingConstants.GRADE_TYPE_POINTS, gradebook.getGradeType())) { - lowestPossibleGrade = "0"; - } else if (Objects.equals(GradingConstants.GRADE_TYPE_LETTER, gbItem.getGradebook().getGradeType())) { - final LetterGradePercentMapping mapping = getLetterGradePercentMapping(gradebook); - lowestPossibleGrade = mapping.getGrade(0d); - } - - return lowestPossibleGrade; - } - - @Override - public List getCategoryDefinitions(String gradebookUid) { + public List getCategoryDefinitions(String gradebookUid, String siteId) { if (gradebookUid == null) { throw new IllegalArgumentException("Null gradebookUid passed to getCategoryDefinitions"); } - if (!isUserAbleToViewAssignments(gradebookUid)) { + if (!isUserAbleToViewAssignments(siteId)) { log.warn("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to retrieve all categories without permission", getUserUid(), gradebookUid); throw new GradingSecurityException(); } return getCategories(getGradebook(gradebookUid).getId()) - .stream().map(this::buildCategoryDefinition).collect(Collectors.toList()); + .stream().map(ca -> buildCategoryDefinition(ca, siteId)).collect(Collectors.toList()); } - private CategoryDefinition buildCategoryDefinition(final Category category) { + private CategoryDefinition buildCategoryDefinition(final Category category, final String siteId) { final CategoryDefinition categoryDef = new CategoryDefinition(); if (category != null) { @@ -2572,7 +2324,7 @@ private CategoryDefinition buildCategoryDefinition(final Category category) { categoryDef.setDropLowest(category.getDropLowest()); categoryDef.setDropHighest(category.getDropHighest()); categoryDef.setKeepHighest(category.getKeepHighest()); - categoryDef.setAssignmentList(getAssignments(category.getGradebook().getUid(), category.getName())); + categoryDef.setAssignmentList(getAssignmentsWithCategory(category.getGradebook().getUid(), siteId, category.getName())); categoryDef.setDropKeepEnabled(category.isDropScores()); categoryDef.setExtraCredit(category.getExtraCredit()); categoryDef.setEqualWeight(category.getEqualWeightAssignments()); @@ -2656,9 +2408,8 @@ private List getCountedAssignments(Long gradebookId) { * * @param gradeRecords * - * NOTE: When the UI changes, this needs to be made private again */ - public void applyDropScores(final Collection gradeRecords, Integer categoryType) { + private void applyDropScores(final Collection gradeRecords, Integer categoryType) { if (gradeRecords == null || gradeRecords.size() < 1) { return; @@ -2768,44 +2519,6 @@ public void applyDropScores(final Collection gradeRecords log.debug("GradebookManager.applyDropScores took {} millis to execute", (System.currentTimeMillis() - start)); } - @Override - public PointsPossibleValidation isPointsPossibleValid(String gradebookUid, Assignment gradebookItem, Double pointsPossible) { - - if (gradebookUid == null) { - throw new IllegalArgumentException("Null gradebookUid passed to isPointsPossibleValid"); - } - if (gradebookItem == null) { - throw new IllegalArgumentException("Null gradebookItem passed to isPointsPossibleValid"); - } - - // At this time, all gradebook items follow the same business rules for - // points possible (aka relative weight in % gradebooks) so special logic - // using the properties of the gradebook item is unnecessary. - // In the future, we will have the flexibility to change - // that behavior without changing the method signature - - // the points possible must be a non-null value greater than 0 with - // no more than 2 decimal places - - if (pointsPossible == null) { - return PointsPossibleValidation.INVALID_NULL_VALUE; - } - - if (pointsPossible <= 0) { - return PointsPossibleValidation.INVALID_NUMERIC_VALUE; - } - // ensure there are no more than 2 decimal places - BigDecimal bd = new BigDecimal(pointsPossible); - bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP); // Two decimal places - double roundedVal = bd.doubleValue(); - double diff = pointsPossible - roundedVal; - if (diff != 0) { - return PointsPossibleValidation.INVALID_DECIMAL; - } - - return PointsPossibleValidation.VALID; - } - /** * * @param doubleAsString @@ -2840,9 +2553,9 @@ private Double convertStringToDouble(final String doubleAsString) { * @param categoryName * @return */ - private List getAssignments(String gradebookUid, String categoryName) { + private List getAssignmentsWithCategory(String gradebookUid, String siteId, String categoryName) { - return getAssignments(gradebookUid).stream() + return getAssignments(gradebookUid, siteId, SortType.SORT_BY_NONE).stream() .filter(a -> StringUtils.equals(a.getCategoryName(), categoryName)) .collect(Collectors.toList()); } @@ -2860,7 +2573,7 @@ private void postUpdateGradeEvent(String gradebookUid, String assignmentName, St log.debug("postUpdateGradeEvent {} {} {} {}", gradebookUid, assignmentName, studentUid, pointsEarned); postEvent("gradebook.updateItemScore", - "/gradebook/" + gradebookUid + "/" + assignmentName + "/" + studentUid + "/" + pointsEarned + "/student"); + "/gradebook/" + gradebookUid + "/" + assignmentName + "/" + studentUid + "/" + pointsEarned + "/student");//aqui se pasa el uid y en otro el id? } /** @@ -2927,13 +2640,13 @@ private void sendGradingEvent(GradingEvent gradingEvent) { */ @Override @Transactional - public String getAverageCourseGrade(final String gradebookUid) { + public String getAverageCourseGrade(final String gradebookUid, final String siteId) { if (gradebookUid == null) { throw new IllegalArgumentException("Null gradebookUid passed to getAverageCourseGrade"); } // Check user has permission to invoke method. - if (!currentUserHasGradeAllPerm(gradebookUid)) { + if (!currentUserHasGradeAllPerm(siteId)) { StringBuilder sb = new StringBuilder() .append("User ") .append(sessionManager.getCurrentSessionUserId()) @@ -2947,7 +2660,7 @@ public String getAverageCourseGrade(final String gradebookUid) { Gradebook gradebook = getGradebook(gradebookUid); if (gradebook != null) { CourseGrade courseGrade = getCourseGrade(gradebook.getId()); - Set studentUids = getAllStudentUids(gradebookUid); + Set studentUids = getAllStudentUids(siteId); // This call handles the complex rules of which assignments and grades to include in the calculation List courseGradeRecs = getPointsEarnedCourseGradeRecords(courseGrade, studentUids); if (courseGrade != null) { @@ -2969,9 +2682,9 @@ public String getAverageCourseGrade(final String gradebookUid) { */ @Override @Transactional - public void updateAssignmentOrder(final String gradebookUid, final Long assignmentId, Integer order) { + public void updateAssignmentOrder(final String gradebookUid, final String siteId, final Long assignmentId, Integer order) { - if (!gradingAuthz.isUserAbleToEditAssessments(gradebookUid)) { + if (!gradingAuthz.isUserAbleToEditAssessments(siteId)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to change the order of assignment {}", getUserUid(), gradebookUid, assignmentId); throw new GradingSecurityException(); @@ -2984,7 +2697,7 @@ public void updateAssignmentOrder(final String gradebookUid, final Long assignme final Long gradebookId = getGradebook(gradebookUid).getId(); // get all assignments for this gradebook - final List assignments = getAssignments(gradebookId, SortType.SORT_BY_SORTING, true); + final List assignments = getSortedAssignments(gradebookId, SortType.SORT_BY_SORTING, true); // find the assignment Optional optTarget = assignments.stream().filter(a -> a.getId().equals(assignmentId)).findAny(); @@ -3257,16 +2970,16 @@ private Optional calculateCategoryScore(final String studentU } @Override - public CourseGradeTransferBean getCourseGradeForStudent(String gradebookUid, String userUuid) { - return this.getCourseGradeForStudents(gradebookUid, Collections.singletonList(userUuid)).get(userUuid); + public CourseGradeTransferBean getCourseGradeForStudent(String gradebookUid, String siteId, String userUuid) { + return this.getCourseGradeForStudents(gradebookUid, siteId, Collections.singletonList(userUuid)).get(userUuid); } @Override - public Map getCourseGradeForStudents(String gradebookUid, List userUuids) { + public Map getCourseGradeForStudents(String gradebookUid, String siteId, List userUuids) { try { GradeMapping gradeMap = getGradebook(gradebookUid).getSelectedGradeMapping(); - return getCourseGradeForStudents(gradebookUid, userUuids, gradeMap.getGradeMap()); + return getCourseGradeForStudents(gradebookUid, siteId, userUuids, gradeMap.getGradeMap()); } catch (Exception e) { log.error("Error in getCourseGradeForStudents : {}", e.toString()); return Collections.emptyMap(); @@ -3275,7 +2988,7 @@ public Map getCourseGradeForStudents(String gra @Override @Transactional - public Map getCourseGradeForStudents(final String gradebookUid, + public Map getCourseGradeForStudents(final String gradebookUid, final String siteId, final List userUuids, final Map gradeMap) { final Map rval = new HashMap<>(); @@ -3285,7 +2998,7 @@ public Map getCourseGradeForStudents(final Stri // if not released, and not instructor or TA, don't do any work // note that this will return a course grade for Instructor and TA even if not released, see SAK-30119 - if (!gradebook.getCourseGradeDisplayed() && !(currentUserHasEditPerm(gradebookUid) || currentUserHasGradingPerm(gradebookUid))) { + if (!gradebook.getCourseGradeDisplayed() && !(currentUserHasEditPerm(siteId) || currentUserHasGradingPerm(siteId))) { return rval; } @@ -3354,20 +3067,20 @@ public Map getCourseGradeForStudents(final Stri } @Override - public List getViewableSections(final String gradebookUid) { + public List getViewableSections(final String gradebookUid, final String siteId) { - return gradingAuthz.getViewableSections(gradebookUid); + return gradingAuthz.getViewableSections(gradebookUid, siteId); } @Override - public void updateGradebookSettings(final String gradebookUid, final GradebookInformation gbInfo) { + public void updateGradebookSettings(final String gradebookUid, final String siteId, final GradebookInformation gbInfo) { if (gradebookUid == null) { throw new IllegalArgumentException("null gradebookUid " + gradebookUid); } // must be instructor type person - if (!currentUserHasEditPerm(gradebookUid)) { + if (!currentUserHasEditPerm(siteId)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to edit gb information", getUserUid(), gradebookUid); throw new GradingSecurityException("You do not have permission to edit gradebook information in site " + gradebookUid); } @@ -3517,7 +3230,7 @@ public void updateGradebookSettings(final String gradebookUid, final GradebookIn } // persist - updateGradebook(gradebook); + updateGradebook(gradebook, siteId); } @@ -3535,17 +3248,10 @@ public Set getGradebookGradeMappings(Long gradebookId) { } @Override - public Set getGradebookGradeMappings(String gradebookUid) { - - final Long gradebookId = getGradebook(gradebookUid).getId(); - return this.getGradebookGradeMappings(gradebookId); - } - - @Override - public void updateCourseGradeForStudent(final String gradebookUid, final String studentUuid, final String grade, final String gradeScale) { + public void updateCourseGradeForStudent(final String gradebookUid, final String siteId, final String studentUuid, final String grade, final String gradeScale) { // must be instructor type person - if (!currentUserHasEditPerm(gradebookUid)) { + if (!currentUserHasEditPerm(siteId)) { log.error("AUTHORIZATION FAILURE: User {} in gradebook {} attempted to update course grade for student: {}", getUserUid(), gradebookUid, studentUuid); throw new GradingSecurityException("You do not have permission to update course grades in " + gradebookUid); @@ -3616,9 +3322,9 @@ private List getGradebookGradeMappings(final Set assignments = getAssignments(gradebookId, SortType.SORT_BY_CATEGORY, true); + final List assignments = getSortedAssignments(gradebookId, SortType.SORT_BY_CATEGORY, true); final List assignmentsInNewCategory = new ArrayList<>(); for (final GradebookAssignment assignment : assignments) { if (assignment.getCategory() == null) { @@ -3800,11 +3506,11 @@ private List getStudentsForGradebook(Gradebook gradebook) { return rval; } - private boolean isCurrentUserFromGroup(final String gradebookUid, final String studentId) { + private boolean isCurrentUserFromGroup(final String siteId, final String studentId) { boolean isFromGroup = false; try { - final Site s = this.siteService.getSite(gradebookUid); + final Site s = this.siteService.getSite(siteId); final Group g = s.getGroup(studentId); isFromGroup = (g != null) && (g.getMember(sessionManager.getCurrentSessionUserId()) != null); } catch (final Exception e) { @@ -3814,6 +3520,15 @@ private boolean isCurrentUserFromGroup(final String gradebookUid, final String s return isFromGroup; } + private boolean isCurrentGbSite(String gradebookUid) { + try { + final Site s = this.siteService.getSite(gradebookUid); + } catch (final Exception e) { + return false; + } + return true; + } + /** * Updates all uncategorised items to exclude them from the course grade calcs * @@ -3888,10 +3603,6 @@ public void unregisterExternalAssignmentProvider(final String providerAppKey) { } } - public void init() { - log.debug("INIT"); - } - public void destroy() { log.debug("DESTROY"); if (this.externalProviders != null) { @@ -3901,175 +3612,56 @@ public void destroy() { } @Override - public void addExternalAssessment(final String gradebookUid, final String externalId, final String externalUrl, - final String title, final double points, final Date dueDate, final String externalServiceDescription, String externalData) - throws ConflictingAssignmentNameException, ConflictingExternalIdException { + @Transactional + public void removeExternalAssignment(String gradebookUid, String externalId, String externalApp) throws AssessmentNotFoundException { - // Ensure that the required strings are not empty - if (StringUtils.trimToNull(externalServiceDescription) == null || - StringUtils.trimToNull(externalId) == null || - StringUtils.trimToNull(title) == null) { - throw new RuntimeException("External service description, externalId, and title must not be empty"); - } + List gas = new ArrayList<>(); + if (gradebookUid == null) { + gas = gradingPersistenceManager.getGradebookUidByExternalId(externalId); + } else { + // Get the external assignment + final Optional optAsn = getDbExternalAssignment(gradebookUid, externalId); + if (optAsn.isEmpty()) { + throw new AssessmentNotFoundException("There is no external assessment id=" + externalId + " in gradebook uid=" + gradebookUid); + } - // Ensure that points is > zero - if (points <= 0) { - throw new AssignmentHasIllegalPointsException("Points must be > 0"); + gas.add(optAsn.get()); } - // Ensure that the assessment name is unique within this gradebook - if (isAssignmentDefined(gradebookUid, title)) { - throw new ConflictingAssignmentNameException("An assignment with that name already exists in gradebook uid=" + gradebookUid); - } + for (GradebookAssignment asn : gas) { + if (externalApp != null && !externalApp.equals(asn.getExternalAppName())) { + log.debug("Skipping gradebook item with id {} from app {}", externalId, asn.getExternalAppName()); + continue; + } + int numDeleted = gradingPersistenceManager.deleteGradingEventsForAssignment(asn); + log.debug("Deleted {} records from gb_grading_event_t", numDeleted); - // name cannot contain these chars as they are reserved for special columns in import/export - GradebookHelper.validateGradeItemName(title); + numDeleted = gradingPersistenceManager.deleteGradeRecordsForAssignment(asn); + log.info("Deleted {} externally defined scores", numDeleted); - // Ensure that the externalId is unique within this gradebook - final Long conflicts = gradingPersistenceManager.countAssignmentsByGradbookAndExternalId(gradebookUid, externalId); + numDeleted = gradingPersistenceManager.deleteCommentsForAssignment(asn); + log.info("Deleted {} externally defined comments", numDeleted); - if (conflicts.intValue() > 0) { - throw new ConflictingExternalIdException( - "An external assessment with ID=" + externalId + " already exists in gradebook uid=" + gradebookUid); + // Delete the assessment. + gradingPersistenceManager.deleteAssignment(asn); + + log.info("External assessment removed from gradebookUid={}, externalId={}, externalApp={} by userUid={}", gradebookUid, externalId, externalApp, getUserUid()); } + } - // Get the gradebook - final Gradebook gradebook = getGradebook(gradebookUid); + private Optional getDbExternalAssignment(String gradebookUid, String externalId) { - // Create the external assignment - final GradebookAssignment asn = new GradebookAssignment(gradebook, title, Double.valueOf(points), dueDate); - asn.setExternallyMaintained(true); - asn.setExternalId(externalId); - asn.setExternalInstructorLink(externalUrl); - asn.setExternalStudentLink(externalUrl); - asn.setExternalAppName(externalServiceDescription); - asn.setExternalData(externalData); - // set released to be true to support selective release - asn.setReleased(true); - asn.setUngraded(false); + if (externalId == null) { + log.warn("null externalId supplied to getDbExternalAssignment. Returning empty ..."); + return Optional.empty(); + } - Long assignmentId = gradingPersistenceManager.saveGradebookAssignment(asn).getId(); - - log.info("External assessment added to gradebookUid={}, externalId={} by userUid={} from externalApp={}", gradebookUid, externalId, - getUserUid(), externalServiceDescription); - - // Check if this ia a plus course - if ( plusService.enabled() ) { - try { - final Site site = this.siteService.getSite(gradebookUid); - if ( plusService.enabled(site) ) { - - String lineItem = plusService.createLineItem(site, assignmentId, getAssignmentDefinition(asn)); - - // Update the assignment with the new lineItem - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); - if (assignment == null) { - throw new AssessmentNotFoundException( - "There is no assignment with id " + assignmentId + " in gradebook " + gradebookUid); - } - assignment.setLineItem(lineItem); - updateAssignment(assignment); - } - } catch (Exception e) { - log.error("Could not load site associated with gradebook - lineitem not created", e); - } - } - - } - - @Override - public void updateExternalAssessment(String gradebookUid, String externalId, String externalUrl, - String externalData, String title, double points, Date dueDate) - throws AssessmentNotFoundException, AssignmentHasIllegalPointsException { - - final Optional optAsn = getDbExternalAssignment(gradebookUid, externalId); - - if (optAsn.isEmpty()) { - throw new AssessmentNotFoundException("There is no assessment id=" + externalId + " in gradebook uid=" + gradebookUid); - } - - GradebookAssignment asn = optAsn.get(); - - // Ensure that points is > zero - if (points <= 0) { - throw new AssignmentHasIllegalPointsException("Points must be > 0"); - } - - // Ensure that the required strings are not empty - if (StringUtils.trimToNull(externalId) == null || - StringUtils.trimToNull(title) == null) { - throw new RuntimeException("ExternalId, and title must not be empty"); - } - - // name cannot contain these chars as they are reserved for special columns in import/export - GradebookHelper.validateGradeItemName(title); - - asn.setExternalInstructorLink(externalUrl); - asn.setExternalStudentLink(externalUrl); - asn.setExternalData(externalData); - asn.setName(title); - asn.setDueDate(dueDate); - // support selective release - asn.setReleased(BooleanUtils.isTrue(asn.getReleased())); - asn.setPointsPossible(Double.valueOf(points)); - gradingPersistenceManager.saveAssignment(asn); - log.info("External assessment updated in gradebookUid={}, externalId={} by userUid={}", gradebookUid, externalId, - getUserUid()); - - // Check if this is a plus course - if ( plusService.enabled() ) { - try { - final Site site = this.siteService.getSite(gradebookUid); - if ( plusService.enabled(site) ) { - log.debug("Lineitem updated={} created assignment={} gradebook={}", asn.getLineItem(), asn.getName(), gradebookUid); - plusService.updateLineItem(site, getAssignmentDefinition(asn)); - } - } catch (Exception e) { - log.error("Could not load site associated with gradebook - lineitem not updated", e); - } - } - } - - @Override - @Transactional - public void removeExternalAssignment(String gradebookUid, String externalId) throws AssessmentNotFoundException { - - // Get the external assignment - final Optional optAsn = getDbExternalAssignment(gradebookUid, externalId); - if (optAsn.isEmpty()) { - throw new AssessmentNotFoundException("There is no external assessment id=" + externalId + " in gradebook uid=" + gradebookUid); - } - - GradebookAssignment asn = optAsn.get(); - - int numDeleted = gradingPersistenceManager.deleteGradingEventsForAssignment(asn); - log.debug("Deleted {} records from gb_grading_event_t", numDeleted); - - numDeleted = gradingPersistenceManager.deleteGradeRecordsForAssignment(asn); - log.info("Deleted {} externally defined scores", numDeleted); - - numDeleted = gradingPersistenceManager.deleteCommentsForAssignment(asn); - log.info("Deleted {} externally defined comments", numDeleted); - - // Delete the assessment. - gradingPersistenceManager.deleteAssignment(asn); - - log.info("External assessment removed from gradebookUid={}, externalId={} by userUid={}", gradebookUid, externalId, getUserUid()); - } - - private Optional getDbExternalAssignment(String gradebookUid, String externalId) { - - if (externalId == null) { - log.warn("null externalId supplied to getDbExternalAssignment. Returning empty ..."); - return Optional.empty(); - } - - return gradingPersistenceManager.getExternalAssignment(gradebookUid, externalId); - } + return gradingPersistenceManager.getExternalAssignment(gradebookUid, externalId); + } @Override - public void updateExternalAssessmentComments(String gradebookUid, String externalId, + public void updateExternalAssessmentComments(String gradebookUid, String siteId, String externalId, Map studentUidsToComments) throws AssessmentNotFoundException { Optional optAsn = getDbExternalAssignment(gradebookUid, externalId); @@ -4086,14 +3678,14 @@ public void updateExternalAssessmentComments(String gradebookUid, String externa List existingScores = gradingPersistenceManager.getAssignmentGradeRecordsForAssignmentAndStudents(asn, studentIds); + // Try to reduce data contention by only updating when a score + // has changed or property has been set forcing a db update every time. + boolean alwaysUpdate = isUpdateSameScore(siteId); + Set changedStudents = new HashSet<>(); for (AssignmentGradeRecord agr : existingScores) { String studentUid = agr.getStudentId(); - // Try to reduce data contention by only updating when a score - // has changed or property has been set forcing a db update every time. - boolean alwaysUpdate = isUpdateSameScore(gradebookUid); - CommentDefinition gradeComment = getAssignmentScoreComment(gradebookUid, asn.getId(), studentUid); String oldComment = gradeComment != null ? gradeComment.getCommentText() : null; String newComment = studentUidsToComments.get(studentUid); @@ -4104,11 +3696,11 @@ public void updateExternalAssessmentComments(String gradebookUid, String externa } } - log.debug("updateExternalAssessmentScores sent {} records, actually changed {}", studentIds.size(), changedStudents.size()); + log.debug("updateExternalAssessmentComments sent {} records, actually changed {}", studentIds.size(), changedStudents.size()); } @Override - public void updateExternalAssessmentScores(final String gradebookUid, final String externalId, + public void updateExternalAssessmentScores(final String gradebookUid, final String siteId, final String externalId, final Map studentUidsToScores) throws AssessmentNotFoundException { final Optional optAssignment = getDbExternalAssignment(gradebookUid, externalId); @@ -4130,14 +3722,15 @@ public void updateExternalAssessmentScores(final String gradebookUid, final Stri final Set previouslyUnscoredStudents = new HashSet<>(studentIds); final Set changedStudents = new HashSet<>(); + + // Try to reduce data contention by only updating when a score + // has changed or property has been set forcing a db update every time. + final boolean alwaysUpdate = isUpdateSameScore(siteId); + for (final AssignmentGradeRecord agr : existingScores) { final String studentUid = agr.getStudentId(); previouslyUnscoredStudents.remove(studentUid); - // Try to reduce data contention by only updating when a score - // has changed or property has been set forcing a db update every time. - final boolean alwaysUpdate = isUpdateSameScore(gradebookUid); - final Double oldPointsEarned = agr.getPointsEarned(); final Double newPointsEarned = studentUidsToScores.get(studentUid); if (alwaysUpdate || (newPointsEarned != null && !newPointsEarned.equals(oldPointsEarned)) @@ -4167,7 +3760,7 @@ public void updateExternalAssessmentScores(final String gradebookUid, final Stri } @Override - public void updateExternalAssessmentScoresString(final String gradebookUid, final String externalId, + public void updateExternalAssessmentScoresString(final String gradebookUid, final String siteId, final String externalId, final Map studentUidsToScores) throws AssessmentNotFoundException { final Optional optAssignment = getDbExternalAssignment(gradebookUid, externalId); @@ -4187,14 +3780,15 @@ public void updateExternalAssessmentScoresString(final String gradebookUid, fina final Set previouslyUnscoredStudents = new HashSet<>(studentIds); final Set changedStudents = new HashSet<>(); + + // Try to reduce data contention by only updating when a score + // has changed or property has been set forcing a db update every time. + final boolean alwaysUpdate = isUpdateSameScore(siteId); + for (final AssignmentGradeRecord agr : existingScores) { final String studentUid = agr.getStudentId(); previouslyUnscoredStudents.remove(studentUid); - // Try to reduce data contention by only updating when a score - // has changed or property has been set forcing a db update every time. - final boolean alwaysUpdate = isUpdateSameScore(gradebookUid); - // TODO: for ungraded items, needs to set ungraded-grades later... final Double oldPointsEarned = agr.getPointsEarned(); final String newPointsEarnedString = studentUidsToScores.get(studentUid); @@ -4286,136 +3880,7 @@ public boolean isExternalAssignmentVisible(final String gradebookUid, final Stri } @Override - public Map getExternalAssignmentsForCurrentUser(final String gradebookUid) { - - final Map visibleAssignments = new HashMap<>(); - final Set providedAssignments = getProvidedExternalAssignments(gradebookUid); - - for (final ExternalAssignmentProvider provider : getExternalAssignmentProviders().values()) { - final String appKey = provider.getAppKey(); - final List assignments = provider.getExternalAssignmentsForCurrentUser(gradebookUid); - for (final String externalId : assignments) { - visibleAssignments.put(externalId, appKey); - } - } - - // We include those items that the gradebook has marked as externally maintained, but no provider has - // identified as items under its authority. This maintains the behavior prior to the grouping support - // introduced for the 2.9 release (SAK-11485 and SAK-19688), where a tool that does not have a provider - // implemented does not have its items filtered for student views and grading. - final List gbAssignments = getViewableAssignmentsForCurrentUser(gradebookUid); - for (final org.sakaiproject.grading.api.Assignment assignment : gbAssignments) { - final String id = assignment.getExternalId(); - if (assignment.getExternallyMaintained() && !providedAssignments.contains(id) && !visibleAssignments.containsKey(id)) { - log.debug("External assignment in gradebook [{}] is not handled by a provider; ID: {}", gradebookUid, id); - visibleAssignments.put(id, null); - } - } - - return visibleAssignments; - } - - private Set getProvidedExternalAssignments(final String gradebookUid) { - final Set allAssignments = new HashSet<>(); - for (final ExternalAssignmentProvider provider : getExternalAssignmentProviders().values()) { - // TODO: This is a temporary cast; if this method proves to be the right fit - // and perform well enough, it will be moved to the regular interface. - if (provider instanceof ExternalAssignmentProviderCompat) { - allAssignments.addAll( - ((ExternalAssignmentProviderCompat) provider).getAllExternalAssignments(gradebookUid)); - } else if (this.providerMethods.containsKey(provider)) { - final Method m = this.providerMethods.get(provider); - try { - @SuppressWarnings("unchecked") - final List reflectedAssignments = (List) m.invoke(provider, gradebookUid); - allAssignments.addAll(reflectedAssignments); - } catch (final Exception e) { - log.debug("Exception calling getAllExternalAssignments", e); - } - } - } - return allAssignments; - } - - @Override - public Map> getVisibleExternalAssignments(final String gradebookUid, final Collection studentIds) { - - final Set providedAssignments = getProvidedExternalAssignments(gradebookUid); - - final Map> visible = new HashMap<>(); - for (final String studentId : studentIds) { - visible.put(studentId, new HashSet()); - } - - for (final ExternalAssignmentProvider provider : getExternalAssignmentProviders().values()) { - // SAK-24407 - Some tools modify this set so we can't pass it. I considered making it an unmodifableCollection but that would - // require changing a number of tools - final Set studentIdsCopy = new HashSet<>(studentIds); - final Map> externals = provider.getAllExternalAssignments(gradebookUid, (studentIdsCopy)); - for (final String studentId : externals.keySet()) { - if (visible.containsKey(studentId)) { - visible.get(studentId).addAll(externals.get(studentId)); - } - } - } - - // SAK-23733 - This covers a tricky case where items that the gradebook thinks are external - // but are not reported by any provider should be included for everyone. This is - // to accommodate tools that use the external assessment mechanisms but have not - // implemented an ExternalAssignmentProvider. - List allAssignments = getViewableAssignmentsForCurrentUser(gradebookUid); - for (Assignment assignment : allAssignments) { - String id = assignment.getExternalId(); - if (assignment.getExternallyMaintained() && !providedAssignments.contains(id)) { - for (String studentId : visible.keySet()) { - visible.get(studentId).add(id); - } - } - } - - return visible.keySet().stream() - .collect(Collectors.toMap(k -> k, k -> new ArrayList(visible.get(k)))); - } - - @Override - public void setExternalAssessmentToGradebookAssignment(final String gradebookUid, final String externalId) { - - final Optional optAssignment = getDbExternalAssignment(gradebookUid, externalId); - if (optAssignment.isEmpty()) { - throw new AssessmentNotFoundException("There is no assessment id=" + externalId + " in gradebook uid=" + gradebookUid); - } - GradebookAssignment assignment = optAssignment.get(); - assignment.setExternalAppName(null); - assignment.setExternalId(null); - assignment.setExternalInstructorLink(null); - assignment.setExternalStudentLink(null); - assignment.setExternalData(null); - assignment.setExternallyMaintained(false); - gradingPersistenceManager.saveAssignment(assignment); - log.info("Externally-managed assignment {} moved to Gradebook management in gradebookUid={} by userUid={}", externalId, - gradebookUid, getUserUid()); - } - - /** - * Wrapper created when category was added for assignments tool - */ - @Override - public void addExternalAssessment(String gradebookUid, String externalId, String externalUrl, String title, Double points, - Date dueDate, String externalServiceDescription, String externalData, Boolean ungraded) - throws ConflictingAssignmentNameException, ConflictingExternalIdException, AssignmentHasIllegalPointsException { - - addExternalAssessment(gradebookUid, externalId, externalUrl, title, points, dueDate, externalServiceDescription, externalData, ungraded, null); - } - - @Override - public void addExternalAssessment(final String gradebookUid, final String externalId, final String externalUrl, final String title, final Double points, - final Date dueDate, final String externalServiceDescription, String externalData, final Boolean ungraded, final Long categoryId) - throws ConflictingAssignmentNameException, ConflictingExternalIdException, AssignmentHasIllegalPointsException { - addExternalAssessment(gradebookUid, externalId, externalUrl, title, points, dueDate, externalServiceDescription, externalData, ungraded, categoryId, null); - } - - @Override - public void addExternalAssessment(final String gradebookUid, final String externalId, final String externalUrl, final String title, final Double points, + public void addExternalAssessment(final String gradebookUid, final String siteId, final String externalId, final String externalUrl, final String title, final Double points, final Date dueDate, final String externalServiceDescription, String externalData, final Boolean ungraded, final Long categoryId, String gradableReference) throws ConflictingAssignmentNameException, ConflictingExternalIdException, AssignmentHasIllegalPointsException { // Ensure that the required strings are not empty @@ -4432,7 +3897,7 @@ public void addExternalAssessment(final String gradebookUid, final String extern } // Ensure that the assessment name is unique within this gradebook - if (isAssignmentDefined(gradebookUid, title)) { + if (isAssignmentDefined(gradebookUid, siteId, title)) { throw new ConflictingAssignmentNameException("An assignment with that name already exists in gradebook uid=" + gradebookUid); } @@ -4495,8 +3960,8 @@ public void addExternalAssessment(final String gradebookUid, final String extern log.info("External assessment added to gradebookUid={}, externalId={} by userUid={} from externalApp={}", gradebookUid, externalId, getUserUid(), externalServiceDescription); - // Check if this ia a plus course - if ( plusService.enabled() ) { + // Check if this is a plus course and gb is site instance + if ( plusService.enabled() && isCurrentGbSite(gradebookUid)) { try { final Site site = this.siteService.getSite(gradebookUid); if ( plusService.enabled(site) ) { @@ -4505,7 +3970,7 @@ public void addExternalAssessment(final String gradebookUid, final String extern log.debug("Lineitem created={} created assignment={} gradebook={}", lineItem, asn.getName(), gradebookUid); // Update the assignment with the new lineItem - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); if (assignment == null) { throw new AssessmentNotFoundException( "There is no assignment with id " + assignmentId + " in gradebook " + gradebookUid); @@ -4519,12 +3984,6 @@ public void addExternalAssessment(final String gradebookUid, final String extern } } - @Override - public void updateExternalAssessment(String gradebookUid, String externalId, String externalUrl, String externalData, String title, Double points, Date dueDate, Boolean ungraded) - throws AssessmentNotFoundException, ConflictingAssignmentNameException, AssignmentHasIllegalPointsException { - updateExternalAssessment(gradebookUid, externalId, externalUrl, externalData, title, null, points, dueDate, ungraded); - } - @Override public void updateExternalAssessment(final String gradebookUid, final String externalId, final String externalUrl, String externalData, final String title, Long categoryId, final Double points, final Date dueDate, final Boolean ungraded) @@ -4566,14 +4025,18 @@ public void updateExternalAssessment(final String gradebookUid, final String ext asn.setUngraded(false); } if (categoryId != null) { - asn.setCategory(getCategory(categoryId)); + if (categoryId != -1L) { + asn.setCategory(getCategory(categoryId)); + } else { + asn.setCategory(null); + } } gradingPersistenceManager.saveGradebookAssignment(asn); log.info("External assessment updated in gradebookUid={}, externalId={} by userUid={}", gradebookUid, externalId, getUserUid()); // Check if this is a plus course - if ( plusService.enabled() ) { + if ( plusService.enabled() && isCurrentGbSite(gradebookUid)) { try { final Site site = this.siteService.getSite(gradebookUid); if ( plusService.enabled(site) ) { @@ -4587,7 +4050,7 @@ public void updateExternalAssessment(final String gradebookUid, final String ext } @Override - public void updateExternalAssessmentComment(final String gradebookUid, final String externalId, final String studentUid, + public void updateExternalAssessmentComment(final String gradebookUid, final String siteId, final String externalId, final String studentUid, final String comment) throws AssessmentNotFoundException { @@ -4604,7 +4067,7 @@ public void updateExternalAssessmentComment(final String gradebookUid, final Str // Try to reduce data contention by only updating when the // score has actually changed or property has been set forcing a db update every time. - final boolean alwaysUpdate = isUpdateSameScore(gradebookUid); + final boolean alwaysUpdate = isUpdateSameScore(siteId); final CommentDefinition gradeComment = getAssignmentScoreComment(gradebookUid, asn.getId(), studentUid); final String oldComment = gradeComment != null ? gradeComment.getCommentText() : null; @@ -4627,7 +4090,7 @@ public void updateExternalAssessmentComment(final String gradebookUid, final Str } @Override - public void updateExternalAssessmentScore(final String gradebookUid, final String externalId, final String studentUid, + public void updateExternalAssessmentScore(final String gradebookUid, final String siteId, final String externalId, final String studentUid, final String points) throws AssessmentNotFoundException { final Optional optAsn = getDbExternalAssignment(gradebookUid, externalId); @@ -4647,7 +4110,7 @@ public void updateExternalAssessmentScore(final String gradebookUid, final Strin // Try to reduce data contention by only updating when the // score has actually changed or property has been set forcing a db update every time. - final boolean alwaysUpdate = isUpdateSameScore(gradebookUid); + final boolean alwaysUpdate = isUpdateSameScore(siteId); // TODO: for ungraded items, needs to set ungraded-grades later... final Double oldPointsEarned = (agr == null) ? null : agr.getPointsEarned(); @@ -4686,36 +4149,6 @@ public void updateExternalAssessmentScore(final String gradebookUid, final Strin externalId, getUserUid(), points); } - /** - * - * @param s the string we want to convert to a double - * @return a locale-aware Double value representation of the given String - * @throws ParseException - */ - /* - private Double convertStringToDouble(final String s) { - Double scoreAsDouble = null; - String doubleAsString = s; - if (doubleAsString != null && !"".equals(doubleAsString)) { - try { - // check if grade uses a comma as separator because of number format and change to a comma y the external app sends a point - // as separator - final DecimalFormat dcformat = (DecimalFormat) getNumberFormat(); - final String decSeparator = dcformat.getDecimalFormatSymbols().getDecimalSeparator() + ""; - if (",".equals(decSeparator)) { - doubleAsString = doubleAsString.replace(".", ","); - } - final Number numericScore = getNumberFormat().parse(doubleAsString.trim()); - scoreAsDouble = numericScore.doubleValue(); - } catch (final ParseException e) { - log.error(e.getMessage()); - } - } - - return scoreAsDouble; - } - */ - private NumberFormat getNumberFormat() { return NumberFormat.getInstance(resourceLoader.getLocale()); } @@ -4739,18 +4172,17 @@ public Long getExternalAssessmentCategoryId(final String gradebookUId, final Str * gb_grade_record_t's 'DATE_RECORDED' field for instance. Generally uses the sakai.property * 'gradebook.externalAssessments.updateSameScore', but a site property by the same name can override it. That is to say, the site * property is checked first, and if it is not present, the sakai.property is used. - * @param gradebookUID the UID of the gradebook, used to resolve site when we can't get site ID from current context + * @param siteId the id of the site when we can't get it from current context */ - private boolean isUpdateSameScore(final String gradebookUID) { + private boolean isUpdateSameScore(final String siteId) { String siteProperty = null; try { - final String siteId = this.toolManager.getCurrentPlacement().getContext(); final Site site = this.siteService.getSite(siteId); siteProperty = site.getProperties().getProperty(UPDATE_SAME_SCORE_PROP); } catch (final NullPointerException e) { // Fallback to gradebook UID, which is also the site ID try { - siteProperty = siteService.getSite(gradebookUID).getProperties().getProperty(UPDATE_SAME_SCORE_PROP); + siteProperty = siteService.getSite(siteId).getProperties().getProperty(UPDATE_SAME_SCORE_PROP); } catch (final Exception ex) { // Can't access site. Leave it set to null } @@ -4774,7 +4206,7 @@ public boolean isCategoriesEnabled(String gradebookUid) { @Override @Transactional - public Gradebook addGradebook(final String uid) { + public Gradebook addGradebook(final String uid, final String name) { log.debug("Adding gradebook uid={} by userUid={}", uid, getUserUid()); @@ -4793,7 +4225,7 @@ public Gradebook addGradebook(final String uid) { // Create and save the gradebook final Gradebook gradebook = new Gradebook(); - gradebook.setName(uid); + gradebook.setName(name); gradebook.setUid(uid); gradingPersistenceManager.saveGradebook(gradebook); @@ -5006,7 +4438,6 @@ public void deleteGradebook(String gradebookUid) { log.debug("Deleting gradebook uid={} by userUid={}", gradebookUid, getUserUid()); - //Gradebook gradebook = gradingPersistencegetGradebook(uid); gradingPersistenceManager.deleteGradebook(gradebookUid); } @@ -5029,7 +4460,7 @@ public CommentDefinition getAssignmentScoreComment(String gradebookUid, Long ass throw new IllegalArgumentException("gradebookUid, assignmentId and studentUid must be valid."); } String assignmentName = ""; - final GradebookAssignment assignment = getAssignmentWithoutStats(gradebookUid, assignmentId); + final GradebookAssignment assignment = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); if (assignment == null) { CourseGrade courseGrade = getCourseGrade(getGradebook(gradebookUid).getId()); if(courseGrade != null && courseGrade.getId().equals(assignmentId)){ //check if this is a course grade before declaring it Not Found @@ -5060,7 +4491,7 @@ public void setAssignmentScoreComment(String gradebookUid, Long assignmentId, St throw new IllegalArgumentException("gradebookUid, assignmentId and studentUid must be valid."); } - GradebookAssignment gradebookColumn = getAssignmentWithoutStats(gradebookUid, assignmentId); + GradebookAssignment gradebookColumn = getAssignmentWithoutStatsByID(gradebookUid, assignmentId); final Optional optComment = gradingPersistenceManager.getInternalComment(studentUid, gradebookUid, assignmentId); Comment comment = null; @@ -5096,22 +4527,25 @@ public void deleteAssignmentScoreComment(String gradebookUid, Long assignmentId, gradingPersistenceManager.deleteInternalComment(studentUid, gradebookUid, assignmentId); } - public Gradebook getGradebook(String uid) { - - return gradingPersistenceManager.getGradebook(uid).orElseGet(() -> addGradebook(uid)); + private Gradebook getGradebook(String uid) { + return getGradebook(uid, uid); } - - @Transactional - public void initGradebook(String uid) { - - try { - siteService.getSite(uid); - } catch (IdUnusedException idue) { - log.warn("No site with id: {}", uid); - throw new IllegalArgumentException(uid + " is not a valid site id"); + public Gradebook getGradebook(String uid, String siteId) { + Optional gradebook = gradingPersistenceManager.getGradebook(uid); + if (gradebook.isPresent()) { + return gradebook.get(); } - - getGradebook(uid); + String name = uid; + if (!uid.equals(siteId)) { + try { + name = MessageHelper.getString("group.gradebook", resourceLoader.getLocale()) + siteService.getSite(siteId).getGroup(uid).getTitle(); + } catch (final IdUnusedException ex) { + log.error("Error looking up site: {}", siteId, ex); + return null; + } + } + return addGradebook(uid, name); + } private List getAssignments(Long gradebookId) { @@ -5134,12 +4568,12 @@ private GradebookAssignment getAssignmentWithoutStats(String gradebookUid, Strin // Check if assignmentName is really an assignmentId. If not get assignment by assignmentName (i.e., title). if (NumberUtils.isCreatable(assignmentName)) { final Long assignmentId = new Long(NumberUtils.toLong(assignmentName)); - return getAssignmentWithoutStats(gradebookUid, new Long(assignmentId)); + return getAssignmentWithoutStatsByID(gradebookUid, new Long(assignmentId)); } return gradingPersistenceManager.getAssignmentByNameAndGradebook(assignmentName, gradebookUid).orElse(null); } - private GradebookAssignment getAssignmentWithoutStats(String gradebookUid, Long assignmentId) { + private GradebookAssignment getAssignmentWithoutStatsByID(String gradebookUid, Long assignmentId) { return gradingPersistenceManager.getAssignmentByIdAndGradebook(assignmentId, gradebookUid).orElse(null); } @@ -5180,21 +4614,21 @@ public List getAssignmentsForCategory(Long categoryId) { private Category getCategory(Long categoryId) { return gradingPersistenceManager.getCategory(categoryId).get(); - } + } - public Optional getCategoryDefinition(Long categoryId) { - return gradingPersistenceManager.getCategory(categoryId).map(this::buildCategoryDefinition); + public Optional getCategoryDefinition(Long categoryId, String siteId) { + return gradingPersistenceManager.getCategory(categoryId).map(ca -> buildCategoryDefinition(ca, siteId)); } public void updateCategory(CategoryDefinition definition) { Optional optCategory = gradingPersistenceManager.getCategory(definition.getId()); - if (optCategory.isPresent()) { - gradingPersistenceManager.saveCategory(updateCategoryFromDefinition(optCategory.get(), definition)); - } else { - log.error("No category for id {}. This is not right ...", definition.getId()); - } - } + if (optCategory.isPresent()) { + gradingPersistenceManager.saveCategory(updateCategoryFromDefinition(optCategory.get(), definition)); + } else { + log.error("No category for id {}. This is not right ...", definition.getId()); + } + } public void updateCategory(final Category category) throws ConflictingCategoryNameException, StaleObjectModificationException { //session.evict(category); @@ -5430,37 +4864,172 @@ public Long createUngradedAssignment(final Long gradebookId, final String name, * @param id * @return the GradebookAssignment object with the given id */ - public GradebookAssignment getAssignment(Long id) { - return gradingPersistenceManager.getAssignmentById(id).orElse(null); + @Override + public GradebookAssignment getGradebookAssigment(String siteId, Long assignmentId) { + if (assignmentId == null || siteId == null) { + throw new IllegalArgumentException("null parameter passed to getAssignment. Values are assignmentId:" + assignmentId + " siteId:" + siteId); + } + if (!isUserAbleToViewAssignments(siteId) && !currentUserHasViewOwnGradesPerm(siteId)) { + log.warn("AUTHORIZATION FAILURE: User {} in site {} attempted to get assignment with id {}", getUserUid(), siteId, assignmentId); + throw new GradingSecurityException(); + } + + GradebookAssignment assignment = gradingPersistenceManager.getAssignmentById(assignmentId).orElse(null); + + if (assignment == null) { + throw new AssessmentNotFoundException("No gradebook item exists with gradable object id = " + assignmentId); + } + + return assignment; } @Override - public String getUrlForAssignment(Assignment assignment) { + public String getGradebookUidByAssignmentById(String siteId, Long assignmentId) { + return getAssignmentById(siteId, assignmentId).getContext(); + } + + private static final String GB_GROUP_SITE_PROPERTY = "gradebook_group"; + private static final String GB_GROUP_TOOL_PROPERTY = "gb-group"; + + @Override + public boolean isGradebookGroupEnabled(String siteId) { + Cache gradebookGroupEnabled = memoryService.getCache(gradebookGroupEnabledCache); + + if (gradebookGroupEnabled != null && gradebookGroupEnabled.containsKey(siteId)) { + log.debug(buildCacheLogDebug("cacheKeyFound", gradebookGroupEnabledCache)); + Boolean groupEnabledCacheValue = gradebookGroupEnabled.get(siteId); + + if (groupEnabledCacheValue != null) { + log.debug(buildCacheLogDebug("cacheValueFound", gradebookGroupEnabledCache)); + return (boolean) groupEnabledCacheValue; + } + } - String gbUrl = ""; try { - Site site = siteService.getSite(assignment.getContext()); - ToolConfiguration tc = site.getToolForCommonId("sakai.gradebookng"); - if (tc != null) { - gbUrl = "/portal/directtool/" + tc.getId(); - } else { - log.warn("No gradebook tool for site {}", assignment.getContext()); + final Site site = this.siteService.getSite(siteId); + boolean enabled = Boolean.parseBoolean(site.getProperties().getProperty(GB_GROUP_SITE_PROPERTY)); + + log.debug(buildCacheLogDebug("noCacheValueFound", gradebookGroupEnabledCache)); + log.debug(buildCacheLogDebug("saveNewCacheValue", gradebookGroupEnabledCache)); + gradebookGroupEnabled.put(siteId, enabled); + return enabled; + } catch (IdUnusedException idue) { + log.warn("No site for id {}", siteId); + } + return false; + } + + @Override + public List getGradebookGroupInstances(String siteId) { + Cache> gradebookGroupInstances = memoryService.getCache(gradebookGroupInstancesCache); + + if (gradebookGroupInstances != null && gradebookGroupInstances.containsKey(siteId)) { + log.debug(buildCacheLogDebug("cacheKeyFound", gradebookGroupInstancesCache)); + List gradebookGroupInstanceList = gradebookGroupInstances.get(siteId); + + if (gradebookGroupInstanceList != null) { + log.debug(buildCacheLogDebug("cacheValueFound", gradebookGroupInstancesCache)); + + return gradebookGroupInstanceList; + } + } + + List gbList = new ArrayList<>(); + + try { + final Site site = this.siteService.getSite(siteId); + Collection gbs = site.getTools("sakai.gradebookng"); + for (ToolConfiguration tc : gbs) { + Properties props = tc.getPlacementConfig(); + if (props.getProperty(GB_GROUP_TOOL_PROPERTY) != null) { + log.debug("Detected gradebook for group {}", props.getProperty(GB_GROUP_TOOL_PROPERTY)); + Optional gb = gradingPersistenceManager.getGradebook(props.getProperty(GB_GROUP_TOOL_PROPERTY)); + if (gb.isPresent()) { + gbList.add(gb.get()); + } + } } } catch (IdUnusedException idue) { - log.warn("No site for id {}", assignment.getContext()); + log.warn("No site for id {}", siteId); } - if (assignment.getExternallyMaintained()) { - if (assignment.getReference() != null) { - return entityManager.getUrl(assignment.getReference(), UrlType.PORTAL).orElse(""); - } else { - return gbUrl; + log.debug(buildCacheLogDebug("noCacheValueFound", gradebookGroupInstancesCache)); + log.debug(buildCacheLogDebug("saveNewCacheValue", gradebookGroupInstancesCache)); + gradebookGroupInstances.put(siteId, gbList); + return gbList; + } + + @Override + public List getGradebookGroupInstancesIds(String siteId) { + return getGradebookGroupInstances(siteId).stream() + .map(Gradebook::getUid) + .collect(Collectors.toList()); + } + + @Override + public Assignment getAssignmentById(String siteId, Long assignmentId) { + + if (assignmentId == null || siteId == null) { + throw new IllegalArgumentException("null parameter passed to getAssignment. Values are assignmentId:" + assignmentId + " siteId:" + siteId); + } + if (!isUserAbleToViewAssignments(siteId) && !currentUserHasViewOwnGradesPerm(siteId)) { + log.warn("AUTHORIZATION FAILURE: User {} in site {} attempted to get assignment with id {}", getUserUid(), siteId, assignmentId); + throw new GradingSecurityException(); + } + + GradebookAssignment assignment = gradingPersistenceManager.getAssignmentById(assignmentId).orElse(null); + + if (assignment == null) { + throw new AssessmentNotFoundException("No gradebook item exists with gradable object id = " + assignmentId); + } + + return getAssignmentDefinition(assignment, false); + } + + // Possible new param to do log, warn or info instead of retriving message + // I18n feature implementation replacing strings to messageProperties + private String buildCacheLogDebug(String type, String cacheKey) { + if (type != null && !StringUtils.isBlank(type) && cacheKey != null && !StringUtils.isBlank(cacheKey)) { + switch (type) { + case "creatingCache": + return "Creating cache with key '" + cacheKey + "'"; + case "cacheKeyFound": + return "Found cache key for '" + cacheKey + "'"; + case "cacheValueFound": + return "Found cache value for '" + cacheKey + "'"; + case "noCacheValueFound": + return "No cache value founded for '" + cacheKey + "'"; + case "saveNewCacheValue": + return "Saving new value for cache key '" + cacheKey + "'"; + default: + return "ERROR BUILDING CACHE LOG DEBUG ON GRADING SERVICE IMPL (INVALID TYPE)"; } } else { - return gbUrl; + return "ERROR BUILDING CACHE LOG DEBUG ON GRADING SERVICE IMPL (EMPTY PARAMETERS OR NULL)"; } } + @Override + public List getGradebookInstancesForUser(String siteId, String userId) { + if (!isGradebookGroupEnabled(siteId)) { + return List.of(siteId); + } + List allGradebooks = getGradebookGroupInstances(siteId); + List userGradebooks = new ArrayList<>(); + try { + final Site s = siteService.getSite(siteId); + for (Gradebook group : allGradebooks) { + final Group g = s.getGroup(group.getUid()); + if (g != null && g.getMember(userId) != null) { + userGradebooks.add(group.getUid()); + } + } + } catch (final Exception e) { + log.error("Error in getGradebookInstancesForUser: ", e); + } + return userGradebooks; + } + private void createDefaultLetterGradeMapping(final Map gradeMap) { if (getDefaultLetterGradePercentMapping().isEmpty()) { @@ -5511,77 +5080,6 @@ private Map getHardDefaultLetterMapping() { return gradeMap; } - private void finalizeNullGradeRecords(final Gradebook gradebook) { - - final Set studentUids = getAllStudentUids(gradebook.getUid()); - final Date now = new Date(); - final String graderId = sessionManager.getCurrentSessionUserId(); - - final List countedAssignments - = gradingPersistenceManager.getCountedAndGradedAssignmentsForGradebook(gradebook.getId()); - - final Map> visible = getVisibleExternalAssignments(gradebook, studentUids, countedAssignments); - - for (final GradebookAssignment assignment : countedAssignments) { - final List scoredGradeRecords - = gradingPersistenceManager.getAllAssignmentGradeRecordsForAssignment(assignment.getId()); - - final Map studentToGradeRecordMap = new HashMap<>(); - for (final AssignmentGradeRecord scoredGradeRecord : scoredGradeRecords) { - studentToGradeRecordMap.put(scoredGradeRecord.getStudentId(), scoredGradeRecord); - } - - for (String studentUid : studentUids) { - // SAK-11485 - We don't want to add scores for those grouped activities - // that this student should not see or be scored on. - if (assignment.getExternallyMaintained() && (!visible.containsKey(studentUid) || !visible.get(studentUid).contains(assignment))) { - continue; - } - AssignmentGradeRecord gradeRecord = studentToGradeRecordMap.get(studentUid); - if (gradeRecord != null) { - if (gradeRecord.getPointsEarned() == null) { - gradeRecord.setPointsEarned(0d); - } else { - continue; - } - } else { - gradeRecord = new AssignmentGradeRecord(assignment, studentUid, 0d); - } - gradeRecord.setGraderId(graderId); - gradeRecord.setDateRecorded(now); - gradingPersistenceManager.saveAssignmentGradeRecord(gradeRecord); - gradingPersistenceManager.saveGradingEvent(new GradingEvent(assignment, graderId, studentUid, gradeRecord.getPointsEarned())); - } - } - } - - private Map> getVisibleExternalAssignments(final Gradebook gradebook, final Collection studentIds, final List assignments) { - - final String gradebookUid = gradebook.getUid(); - final Map> allExternals = getVisibleExternalAssignments(gradebookUid, studentIds); - final Map allRequested = new HashMap(); - - for (final GradebookAssignment a : assignments) { - if (a.getExternallyMaintained()) { - allRequested.put(a.getExternalId(), a); - } - } - - final Map> visible = new HashMap>(); - for (final String studentId : allExternals.keySet()) { - if (studentIds.contains(studentId)) { - final Set studentAssignments = new HashSet(); - for (final String assignmentId : allExternals.get(studentId)) { - if (allRequested.containsKey(assignmentId)) { - studentAssignments.add(allRequested.get(assignmentId)); - } - } - visible.put(studentId, studentAssignments); - } - } - return visible; - } - private String getPropertyValue(final String name) { // TODO: ADRIAN should be caching these like this? @@ -5626,9 +5124,9 @@ private List filterGradeRecordsByStudents(final Collection gradeRecords, final C return filteredRecords; } - private Set getAllStudentUids(final String gradebookUid) { + private Set getAllStudentUids(final String siteId) { - final List enrollments = sectionAwareness.getSiteMembersInRole(gradebookUid, Role.STUDENT); + final List enrollments = sectionAwareness.getSiteMembersInRole(siteId, Role.STUDENT); return enrollments.stream().map(e -> e.getUser().getUserUid()).collect(Collectors.toSet()); } @@ -5790,4 +5288,146 @@ private void convertPointsToPercentage(Gradebook gradebook, List gradebookPointsMap, String newCategoryString) { + Long catRef = -1L; + + List categoryDefinitions = getCategoryDefinitions(gbUid, siteId); + if (!newCategoryString.equals("-1") || assignmentRef.isEmpty()) { + // NO DEBERÍA EJECUTARSE + // TODO JUANMA CATEGORIA VACIA + // catRefList = newCategoryString; + } else { + for (CategoryDefinition categorie : categoryDefinitions) { + if (categorie.isAssignmentInThisCategory(assignmentRef)) { + catRef = categorie.getId(); + } + } + } + + if (catRef != -1) { + for (CategoryDefinition thisCategoryDefinition : categoryDefinitions) { + if (Objects.equals(thisCategoryDefinition.getId(), catRef)) { + if (thisCategoryDefinition.getDropKeepEnabled() && !thisCategoryDefinition.getEqualWeight()) { + Double thisCategoryPoints = thisCategoryDefinition.getPointsForCategory(); + if (thisCategoryPoints != null) { + gradebookPointsMap.put(gbUid, thisCategoryPoints); + } + } + } + } + } + } + + @Override + public boolean checkMultiSelectorList(String siteId, List groupList, List multiSelectorList, boolean isCategory) { + if (isCategory) { + for (String categoryId : multiSelectorList) { + if (!categoryId.isEmpty() && !categoryId.isBlank()) { + boolean isCategoryInGradebook = false; + + for (String groupId : groupList) { + List categoryDefinitionList = getCategoryDefinitions(groupId, groupId); + + boolean foundCategory = categoryDefinitionList.stream() + .anyMatch(category -> category.getId().equals(Long.parseLong(categoryId))); + + if (foundCategory) { + isCategoryInGradebook = true; + break; + } + } + + if (!isCategoryInGradebook) { + return false; + } + } + } + } else { + List gbUidList = new ArrayList<>(); + + for (String gbItem : multiSelectorList) { + if (StringUtils.isNotBlank(gbItem)) { + String gbUid = getGradebookUidByAssignmentById(siteId, Long.parseLong(gbItem)); + gbUidList.add(gbUid); + } + } + + Collections.sort(gbUidList); + Collections.sort(groupList); + + boolean areEqual = gbUidList.equals(groupList); + + if (!areEqual) { + return false; + } + } + + return true; + } + + @Override + public Map buildCategoryGradebookMap(List selectedGradebookUids, String categoriesString, String siteId) { + Map gradebookCategoryMap = new HashMap<>(); + + if (categoriesString == null || categoriesString.isBlank()) { + selectedGradebookUids.forEach(gbUid -> gradebookCategoryMap.put(gbUid, "-1")); + } else { + List selectedCategories = Arrays.asList(categoriesString.split(",")); + + for (String gbUid : selectedGradebookUids) { + List categoryDefinitions = getCategoryDefinitions(gbUid, siteId); + + String categoryId = categoryDefinitions.stream() + .filter(category -> selectedCategories.contains(category.getId().toString())) + .map(category -> category.getId().toString()) + .findFirst() + .orElse("-1"); + + gradebookCategoryMap.put(gbUid, categoryId); + } + } + + return gradebookCategoryMap; + } + + public Long getMatchingUserGradebookItemId(String siteId, String userId, String gradebookItemIdString) { + Cache matchingUserGradebookItem = memoryService.getCache(matchingUserGradebookItemCache); + + if (matchingUserGradebookItem != null && matchingUserGradebookItem.containsKey(userId)) { + log.debug(buildCacheLogDebug("cacheKeyFound", gradebookGroupInstancesCache)); + Long gradebookItemId = matchingUserGradebookItem.get(userId); + + if (gradebookItemId != null) { + log.debug(buildCacheLogDebug("cacheValueFound", gradebookGroupInstancesCache)); + + return gradebookItemId; + } + } + + List userGradebookList = getGradebookInstancesForUser(siteId, userId); + List gradebookItemList = Arrays.asList(gradebookItemIdString.split(",")); + + for (String gradebookItem : gradebookItemList) { + String foundGradebookUid = getGradebookUidByAssignmentById(siteId, + Long.parseLong(gradebookItem)); + + if (userGradebookList.contains(foundGradebookUid)) { + Long gradebookItemId = Long.valueOf(gradebookItem); + + matchingUserGradebookItem.put(siteId, gradebookItemId); + return gradebookItemId; + } + } + + return null; + } } diff --git a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/VersionedExternalizable.java b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/VersionedExternalizable.java deleted file mode 100644 index 2c658fc08f97..000000000000 --- a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/VersionedExternalizable.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2003-2016 The Apereo Foundation - * - * Licensed under the Educational Community License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://opensource.org/licenses/ecl2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sakaiproject.grading.impl; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; - -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.converters.ConversionException; -import com.thoughtworks.xstream.converters.MarshallingContext; -import com.thoughtworks.xstream.converters.UnmarshallingContext; -import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter; -import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; -import com.thoughtworks.xstream.io.HierarchicalStreamReader; -import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import com.thoughtworks.xstream.io.xml.DomDriver; -import com.thoughtworks.xstream.mapper.Mapper; - -/** - * Generic helper class for serializing Java objects to and from simply-formatted XML - * for archival and reconstitution across data definition versions. - *

- * XStream is used to handle the marshalling and unmarshalling work. The main - * addition is an "externalizableVersion" attribute on the POJO's top-level - * element. That attribute can then be checked for incompatibilities before - * reconstitution, and used to convert old data into its new form. (Currently, - * if there's a version mismatch and nothing is done about it, this class throws - * a ConversionException.) - *

- * Translation to and from XML can be handled either with the static "toXML" - * and "fromXML" methods, or through the Externalizable interface. The chief - * benefit of the static methods is that they (theoretically) give subclasses - * the ability to translate across versions using XSLT, and possibly even return - * an object of a different class than the original. - *

- * TODO For the functionality being checked in (site-to-site migration), this class - * is not strictly necessary. It's here on a speculative basis for upcoming - * import/archive/merge development. - * - * @deprecated This is part of the import/export for gradebook1 which will be removed at some point - */ -@Deprecated -public abstract class VersionedExternalizable implements Externalizable { - public static String VERSION_ATTRIBUTE = "externalizableVersion"; - - /** - * @return non-null archivable version identifier for the object definition - */ - public abstract String getExternalizableVersion(); - - /** - * This XStream converter stores the externalizable version of the - * class as a Document-level attribute for easy access by translators. - * Right now, though, since we don't have any version translators, we - * don't try to reconstitute XML corresponding to anything but the current - * version. - */ - public static class Converter extends AbstractReflectionConverter { - public Converter(final Mapper mapper, final ReflectionProvider reflectionProvider) { - super(mapper, reflectionProvider); - } - - @Override - public boolean canConvert(final Class type) { - return VersionedExternalizable.class.isAssignableFrom(type); - } - - @Override - public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { - writer.addAttribute(VERSION_ATTRIBUTE, ((VersionedExternalizable) source).getExternalizableVersion()); - super.marshal(source, writer, context); - } - - @Override - public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader, final UnmarshallingContext context) { - final String currentVersion = ((VersionedExternalizable) result).getExternalizableVersion(); - final String oldVersion = reader.getAttribute(VERSION_ATTRIBUTE); - if ((oldVersion == null) || !currentVersion.equals(oldVersion)) { - // This is one place we might put a version translation method in the future.... - throw new ConversionException("Cannot convert " + result + " from version " + oldVersion + " to version " + currentVersion); - } - return super.doUnmarshal(result, reader, context); - } - } - - protected static XStream getXStream() { - final XStream xstream = new XStream(new DomDriver()); // does not require XPP3 library - xstream.registerConverter(new Converter(xstream.getMapper(), xstream.getReflectionProvider())); - return xstream; - } - - @Override - public void readExternal(final ObjectInput inputStream) throws IOException, ClassNotFoundException { - getXStream().fromXML(inputStream.readUTF(), this); - } - - @Override - public void writeExternal(final ObjectOutput outputStream) throws IOException { - outputStream.writeUTF(getXStream().toXML(this)); - } - - /** - * @param obj the Java object (usually a subclass of VersionedExternalizable) to describe - * as XML - * @return XML describing the object - */ - public static String toXml(final Object obj) { - return getXStream().toXML(obj); - } - - /** - * @param xmlString XML string (presumably created by this class) describing a Java object - * @return the Java object it describes - */ - public static Object fromXml(final String xmlString) { - return getXStream().fromXML(xmlString); - } - -} diff --git a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/repository/GradebookAssignmentRepositoryImpl.java b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/repository/GradebookAssignmentRepositoryImpl.java index ed8d053c0bc3..7fcdd41517b7 100644 --- a/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/repository/GradebookAssignmentRepositoryImpl.java +++ b/gradebookng/impl/src/main/java/org/sakaiproject/grading/impl/repository/GradebookAssignmentRepositoryImpl.java @@ -131,6 +131,17 @@ public Optional findByGradebook_UidAndExternalId(String gra return session.createQuery(query).uniqueResultOptional(); } + @Transactional(readOnly = true) + public List findByExternalId(String externalId) { + + Session session = sessionFactory.getCurrentSession(); + CriteriaBuilder cb = session.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(GradebookAssignment.class); + Root ga = query.from(GradebookAssignment.class); + query.where(cb.equal(ga.get("externalId"), externalId)); + return session.createQuery(query).list(); + } + @Transactional(readOnly = true) public Long countByGradebook_UidAndExternalId(String gradebookUid, String externalId) { diff --git a/gradebookng/impl/src/main/webapp/WEB-INF/components.xml b/gradebookng/impl/src/main/webapp/WEB-INF/components.xml index ac22dc86e03c..1b6c93cb12d4 100644 --- a/gradebookng/impl/src/main/webapp/WEB-INF/components.xml +++ b/gradebookng/impl/src/main/webapp/WEB-INF/components.xml @@ -111,6 +111,7 @@ + diff --git a/gradebookng/impl/src/test/java/org/sakaiproject/grading/impl/test/GradingServiceTests.java b/gradebookng/impl/src/test/java/org/sakaiproject/grading/impl/test/GradingServiceTests.java index da3ec022f16f..4fa13599d4ac 100644 --- a/gradebookng/impl/src/test/java/org/sakaiproject/grading/impl/test/GradingServiceTests.java +++ b/gradebookng/impl/src/test/java/org/sakaiproject/grading/impl/test/GradingServiceTests.java @@ -47,6 +47,7 @@ import org.sakaiproject.grading.api.model.LetterGradePercentMapping; import org.sakaiproject.grading.api.repository.CourseGradeRepository; import org.sakaiproject.grading.api.repository.LetterGradePercentMappingRepository; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.grading.impl.GradingServiceImpl; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; @@ -182,14 +183,14 @@ public void addAssignment() { when(securityService.unlock(GradingAuthz.PERMISSION_EDIT_ASSIGNMENTS, "/site/" + siteId)).thenReturn(false); - assertThrows(GradingSecurityException.class, () -> gradingService.addAssignment(gradebook.getUid(), ass1)); + assertThrows(GradingSecurityException.class, () -> gradingService.addAssignment(gradebook.getUid(), siteId, ass1)); when(securityService.unlock(GradingAuthz.PERMISSION_EDIT_ASSIGNMENTS, "/site/" + siteId)).thenReturn(true); //when(siteService.siteReference(gradebook.getUid())).thenReturn("/site/" + gradebook.getUid()); - gradingService.addAssignment(gradebook.getUid(), ass1); + gradingService.addAssignment(gradebook.getUid(), siteId, ass1); - List assignments = gradingService.getAssignments(gradebook.getUid()); + List assignments = gradingService.getAssignments(gradebook.getUid(), siteId, SortType.SORT_BY_SORTING); assertEquals(1, assignments.size()); assertEquals(ass1Name, assignments.get(0).getName()); assertEquals(ass1Points, assignments.get(0).getPoints()); @@ -201,10 +202,10 @@ public void getAssignments() { Gradebook gradebook = createGradebook(); Long id = createAssignment1(gradebook); - List assignments = gradingService.getAssignments(gradebook.getUid()); + List assignments = gradingService.getAssignments(gradebook.getUid(), siteId, SortType.SORT_BY_SORTING); assertEquals(1, assignments.size()); Long id2 = createAssignment2(gradebook); - assignments = gradingService.getAssignments(gradebook.getUid()); + assignments = gradingService.getAssignments(gradebook.getUid(), siteId, SortType.SORT_BY_SORTING); assertEquals(2, assignments.size()); } @@ -221,13 +222,13 @@ public void addAndUpdateExternalAssessment() { String description = "The Sakai assignments tool"; assertThrows(GradingSecurityException.class, - () -> gradingService.addExternalAssessment("none", externalId, "http://eggs.com", - title, points, dueDate, description, "data", false)); + () -> gradingService.addExternalAssessment("none", "nothing", externalId, "http://eggs.com", + title, points, dueDate, description, "data", false, null, null)); switchToInstructor(); - gradingService.addExternalAssessment(gradebook.getUid(), externalId, "http://eggs.com", title, points, dueDate, description, "data", false); - Assignment assignment = gradingService.getExternalAssignment(gradebook.getUid(), externalId); + gradingService.addExternalAssessment(gradebook.getUid(), gradebook.getUid(), externalId, "http://eggs.com", title, points, dueDate, description, "data", false, null, null); + Assignment assignment = gradingService.getExternalAssignment(gradebook.getUid(), externalId);//TODO mi caso? assertEquals(title, assignment.getName()); assertEquals(points, assignment.getPoints()); @@ -238,7 +239,7 @@ public void addAndUpdateExternalAssessment() { String newTitle = "New Title"; Double newPoints = 23.2D; - gradingService.updateExternalAssessment(gradebook.getUid(), externalId, "http://eggs.com", "data", newTitle, newPoints, assignment.getDueDate()); + gradingService.updateExternalAssessment(gradebook.getUid(), externalId, "http://eggs.com", "data", newTitle, null, newPoints, assignment.getDueDate(), null); assignment = gradingService.getExternalAssignment(gradebook.getUid(), externalId); assertEquals(newTitle, assignment.getName()); @@ -267,7 +268,7 @@ public void removeAssignment() { Long id = createAssignment1(gradebook); gradingService.removeAssignment(id); - assertEquals(0, gradingService.getAssignments(gradebook.getUid()).size()); + assertEquals(0, gradingService.getAssignments(gradebook.getUid(), siteId, SortType.SORT_BY_SORTING).size()); } @Test @@ -283,14 +284,14 @@ public void removeExternalAssignment() { switchToInstructor(); - gradingService.addExternalAssessment(gradebook.getUid(), externalId, externalUrl, - title, points, dueDate, externalServiceDescription, null, false); + gradingService.addExternalAssessment(gradebook.getUid(), gradebook.getUid(), externalId, externalUrl, + title, points, dueDate, externalServiceDescription, null, false, null, null); Assignment assignment = gradingService.getExternalAssignment(gradebook.getUid(), externalId); assertNotNull(assignment); - gradingService.removeExternalAssignment(gradebook.getUid(), externalId); + gradingService.removeExternalAssignment(gradebook.getUid(), externalId, null); assertThrows(IllegalArgumentException.class, () -> gradingService.getExternalAssignment(gradebook.getUid(), externalId)); } @@ -301,13 +302,13 @@ public void updateAssignment() { Gradebook gradebook = createGradebook(); Long id = createAssignment1(gradebook); - Assignment updated = gradingService.getAssignment(gradebook.getUid(), id); + Assignment updated = gradingService.getAssignment(gradebook.getUid(), siteId, id); updated.setExternallyMaintained(true); updated.setName("Changed Name"); updated.setPoints(80D); updated.setDueDate(new Date()); - gradingService.updateAssignment(gradebook.getUid(), id, updated); - updated = gradingService.getAssignment(gradebook.getUid(), id); + gradingService.updateAssignment(gradebook.getUid(), siteId, id, updated); + updated = gradingService.getAssignment(gradebook.getUid(), siteId, id); // You can't change the name, points or due date of externally maintained assignments assertEquals(ass1Name, updated.getName()); // You can't change the points of externally maintained assignments @@ -321,25 +322,24 @@ public void isAssignmentDefined() { Gradebook gradebook = createGradebook(); when(securityService.unlock(GradingAuthz.PERMISSION_EDIT_ASSIGNMENTS, "/site/" + gradebook.getUid())).thenReturn(false); when(securityService.unlock(GradingAuthz.PERMISSION_GRADE_ALL, "/site/" + gradebook.getUid())).thenReturn(false); - assertThrows(GradingSecurityException.class, () -> gradingService.isAssignmentDefined(gradebook.getUid(), ass1Name)); + assertThrows(GradingSecurityException.class, () -> gradingService.isAssignmentDefined(gradebook.getUid(), siteId, ass1Name)); when(securityService.unlock(GradingAuthz.PERMISSION_EDIT_ASSIGNMENTS, "/site/" + gradebook.getUid())).thenReturn(true); - assertFalse(gradingService.isAssignmentDefined(gradebook.getUid(), ass1Name)); + assertFalse(gradingService.isAssignmentDefined(gradebook.getUid(), siteId, ass1Name)); Long id = createAssignment1(gradebook); - assertTrue(gradingService.isAssignmentDefined(gradebook.getUid(), ass1Name)); + assertTrue(gradingService.isAssignmentDefined(gradebook.getUid(), siteId, ass1Name)); } @Test public void setAssignmentScoreString() { Gradebook gradebook = createGradebook(); - assertThrows(AssessmentNotFoundException.class, () -> gradingService.setAssignmentScoreString(gradebook.getUid(), ass1Name, user1, "43.0", "")); Long id = createAssignment1(gradebook); - gradingService.setAssignmentScoreString(gradebook.getUid(), ass1Name, user1, "43.0", ""); - assertEquals("43", gradingService.getAssignmentScoreString(gradebook.getUid(), ass1Name, user1)); + gradingService.setAssignmentScoreString(gradebook.getUid(), siteId, id, user1, "43.0", ""); + assertEquals("43", gradingService.getAssignmentScoreString(gradebook.getUid(), siteId, id, user1)); - gradingService.setAssignmentScoreString(gradebook.getUid(), ass1Name, user1, "27.5", ""); - assertEquals("27.5", gradingService.getAssignmentScoreString(gradebook.getUid(), ass1Name, user1)); + gradingService.setAssignmentScoreString(gradebook.getUid(), siteId, id, user1, "27.5", ""); + assertEquals("27.5", gradingService.getAssignmentScoreString(gradebook.getUid(), siteId, id, user1)); } @Test @@ -364,7 +364,7 @@ public void saveGradesAndComments() { def2.setGradeComment("Good"); def2.setGradeEntryType(GradingConstants.GRADE_TYPE_POINTS); - gradingService.saveGradesAndComments(gradebook.getUid(), id, List.of(def1, def2)); + gradingService.saveGradesAndComments(gradebook.getUid(), siteId, id, List.of(def1, def2)); List gradingEvents = gradingService.getGradingEvents(user1, id); assertEquals(1, gradingEvents.size()); @@ -377,7 +377,7 @@ public void saveGradesAndComments() { public void getAverageCourseGrade() { Gradebook gradebook = createGradebook(); - String average = gradingService.getAverageCourseGrade(gradebook.getUid()); + String average = gradingService.getAverageCourseGrade(gradebook.getUid(), siteId); assertNull(average); Long assId = createAssignment1(gradebook); @@ -385,9 +385,9 @@ public void getAverageCourseGrade() { String grade = "3.7"; String comment = "Rather shoddy"; - gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), assId, user1, grade, comment); + gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), siteId, assId, user1, grade, comment); - average = gradingService.getAverageCourseGrade(gradebook.getUid()); + average = gradingService.getAverageCourseGrade(gradebook.getUid(), siteId); //assertEquals("3.7", average); } @@ -396,12 +396,12 @@ public void createGradebookWithCategories() { switchToInstructor(); - gradingService.addGradebook(siteId); - Gradebook gradebook = gradingService.getGradebook(siteId); + gradingService.addGradebook(siteId, siteId); + Gradebook gradebook = gradingService.getGradebook(siteId, siteId); addCategories(gradebook); - GradebookInformation gradebookInformation = gradingService.getGradebookInformation(siteId); + GradebookInformation gradebookInformation = gradingService.getGradebookInformation(siteId, siteId); List categories = gradebookInformation.getCategories(); assertEquals(2, categories.size()); @@ -447,12 +447,12 @@ public void getAssignmentByNameOrId() { Gradebook gradebook = createGradebook(); - Assignment ass = gradingService.getAssignmentByNameOrId(gradebook.getUid(), "none"); + Assignment ass = gradingService.getAssignmentByNameOrId(gradebook.getUid(), siteId, "none"); assertNull(ass); Long ass1Id = createAssignment1(gradebook); - ass = gradingService.getAssignmentByNameOrId(gradebook.getUid(), ass1Id.toString()); + ass = gradingService.getAssignmentByNameOrId(gradebook.getUid(), siteId, ass1Id.toString()); assertNotNull(ass); } @@ -461,14 +461,14 @@ public void getCategoryDefinitions() { switchToInstructor(); - gradingService.addGradebook(siteId); - Gradebook gradebook = gradingService.getGradebook(siteId); - List cats = gradingService.getCategoryDefinitions(gradebook.getUid()); + gradingService.addGradebook(siteId, siteId); + Gradebook gradebook = gradingService.getGradebook(siteId, siteId); + List cats = gradingService.getCategoryDefinitions(gradebook.getUid(), siteId); assertEquals(0, cats.size()); addCategories(gradebook); - cats = gradingService.getCategoryDefinitions(gradebook.getUid()); + cats = gradingService.getCategoryDefinitions(gradebook.getUid(), siteId); assertEquals(2, cats.size()); } @@ -477,33 +477,19 @@ public void getViewableAssignmentsForCurrentUser() { Gradebook gradebook = createGradebook(); Long id = createAssignment1(gradebook); - List assignments = gradingService.getViewableAssignmentsForCurrentUser(gradebook.getUid()); + List assignments = gradingService.getViewableAssignmentsForCurrentUser(gradebook.getUid(), siteId, SortType.SORT_BY_SORTING); assertEquals(1, assignments.size()); } - - @Test - public void isPointsPossibleValid() { - - assertThrows(IllegalArgumentException.class, () -> gradingService.isPointsPossibleValid(null, null, null)); - - Gradebook gradebook = createGradebook(); - Long id = createAssignment1(gradebook); - Assignment updated = gradingService.getAssignment(gradebook.getUid(), id); - assertEquals(GradingService.PointsPossibleValidation.INVALID_NUMERIC_VALUE, gradingService.isPointsPossibleValid(gradebook.getUid(), updated, 0D)); - assertEquals(GradingService.PointsPossibleValidation.INVALID_NULL_VALUE, gradingService.isPointsPossibleValid(gradebook.getUid(), updated, null)); - assertEquals(GradingService.PointsPossibleValidation.INVALID_DECIMAL, gradingService.isPointsPossibleValid(gradebook.getUid(), updated, 2.344D)); - assertEquals(GradingService.PointsPossibleValidation.VALID, gradingService.isPointsPossibleValid(gradebook.getUid(), updated, 2.34D)); - } - +/* @Test public void isUserAbleToGradeItemForStudent() { Gradebook gradebook = createGradebook(); Long id = createAssignment1(gradebook); switchToUser1(); - assertFalse(gradingService.isUserAbleToGradeItemForStudent(gradebook.getUid(), id, user2)); + assertFalse(gradingService.isUserAbleToGradeItemForStudent(gradebook.getUid(), siteId, id, user2)); when(securityService.unlock(GradingAuthz.PERMISSION_GRADE_ALL, "/site/" + gradebook.getUid())).thenReturn(true); - assertTrue(gradingService.isUserAbleToGradeItemForStudent(gradebook.getUid(), id, user2)); + assertTrue(gradingService.isUserAbleToGradeItemForStudent(gradebook.getUid(), siteId, id, user2)); } @Test @@ -512,32 +498,32 @@ public void isUserAbleToViewItemForStudent() { Gradebook gradebook = createGradebook(); Long id = createAssignment1(gradebook); when(securityService.unlock(GradingAuthz.PERMISSION_GRADE_ALL, "/site/" + gradebook.getUid())).thenReturn(false); - assertFalse(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), id, user2)); + assertFalse(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), siteId, id, user2)); when(securityService.unlock(GradingAuthz.PERMISSION_GRADE_ALL, "/site/" + gradebook.getUid())).thenReturn(true); - assertTrue(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), id, user2)); + assertTrue(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), siteId, id, user2)); switchToUser1(); when(securityService.unlock(GradingAuthz.PERMISSION_GRADE_ALL, "/site/" + gradebook.getUid())).thenReturn(false); - assertFalse(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), id, user2)); + assertFalse(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), siteId, id, user2)); when(securityService.unlock(GradingAuthz.PERMISSION_GRADE_ALL, "/site/" + gradebook.getUid())).thenReturn(true); - assertTrue(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), id, user2)); + assertTrue(gradingService.isUserAbleToViewItemForStudent(gradebook.getUid(), siteId, id, user2)); } - +*/ @Test public void getGradeViewFunctionForUserForStudentForItem() { - assertThrows(IllegalArgumentException.class, () -> gradingService.getGradeViewFunctionForUserForStudentForItem(null, null, null)); + assertThrows(IllegalArgumentException.class, () -> gradingService.getGradeViewFunctionForUserForStudentForItem(null, null, null, null)); Gradebook gradebook = createGradebook(); Long id = createAssignment1(gradebook); - String perm = gradingService.getGradeViewFunctionForUserForStudentForItem(gradebook.getUid(), id, user1); + String perm = gradingService.getGradeViewFunctionForUserForStudentForItem(gradebook.getUid(), siteId, id, user1); assertEquals(GradingConstants.gradePermission, perm); switchToUser1(); - perm = gradingService.getGradeViewFunctionForUserForStudentForItem(gradebook.getUid(), id, user1); + perm = gradingService.getGradeViewFunctionForUserForStudentForItem(gradebook.getUid(), siteId, id, user1); assertEquals(null, perm); } @@ -555,7 +541,7 @@ public void saveGradeAndCommentForStudent() { String grade = "3.7"; String comment = "Rather shoddy"; - gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), assId, user1, grade, comment); + gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), siteId, assId, user1, grade, comment); Site site = mock(Site.class); when(site.getGroup(user1)).thenReturn(null); @@ -564,7 +550,7 @@ public void saveGradeAndCommentForStudent() { } catch (Exception e) { } - GradeDefinition gradeDef = gradingService.getGradeDefinitionForStudentForItem(gradebook.getUid(), assId, user1); + GradeDefinition gradeDef = gradingService.getGradeDefinitionForStudentForItem(gradebook.getUid(), siteId, assId, user1); assertEquals(grade, gradeDef.getGrade()); assertEquals(comment, gradeDef.getGradeComment()); @@ -579,14 +565,14 @@ public void getCourseGradeForStudents() { Map gradeMapping = new HashMap<>(); gradeMapping.put(user1, 3.0D); - Map grades = gradingService.getCourseGradeForStudents(gradebook.getUid(), Arrays.asList(user1), gradeMapping); + Map grades = gradingService.getCourseGradeForStudents(gradebook.getUid(), siteId, Arrays.asList(user1), gradeMapping); assertEquals(1, grades.size()); String grade = "3.0"; String comment = "Rather shoddy"; - gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), assId, user1, grade, comment); - grades = gradingService.getCourseGradeForStudents(gradebook.getUid(), Arrays.asList(user1), gradeMapping); + gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), siteId, assId, user1, grade, comment); + grades = gradingService.getCourseGradeForStudents(gradebook.getUid(), siteId, Arrays.asList(user1), gradeMapping); assertEquals(1, grades.size()); assertEquals("20.0", grades.get(user1).getCalculatedGrade()); } @@ -603,21 +589,21 @@ public void getGradesWithoutCommentsForStudentsForItems() { Map gradeMapping = new HashMap<>(); gradeMapping.put(user1, 3.7D); - gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), assId, user1, grade, comment); + gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), gradebook.getUid(), assId, user1, grade, comment); - assertThrows(IllegalArgumentException.class, () -> gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), null, null)); + assertThrows(IllegalArgumentException.class, () -> gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), gradebook.getUid(), null, null)); switchToUser2(); - assertThrows(GradingSecurityException.class, () -> gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), List.of(assId), List.of(user1))); + assertThrows(GradingSecurityException.class, () -> gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), gradebook.getUid(), List.of(assId), List.of(user1))); switchToUser1(); // user1 should be able to view their own grades - Map> user1Grades = gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), List.of(assId), List.of(user1)); + Map> user1Grades = gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), gradebook.getUid(), List.of(assId), List.of(user1)); assertEquals(1, user1Grades.size()); assertEquals(1, user1Grades.get(assId).size()); assertEquals(user1, user1Grades.get(assId).get(0).getStudentUid()); switchToInstructor(); - Map> gradeMap = gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), List.of(assId), List.of(user1)); + Map> gradeMap = gradingService.getGradesWithoutCommentsForStudentsForItems(gradebook.getUid(), gradebook.getUid(), List.of(assId), List.of(user1)); // The keys should be the assignment ids assertTrue(gradeMap.keySet().contains(assId)); @@ -631,50 +617,12 @@ public void getGradesWithoutCommentsForStudentsForItems() { assertNull(defs.get(0).getGradeComment()); } - @Test - public void getUrlForAssignment() { - - Gradebook gradebook = createGradebook(); - - ToolConfiguration tc = mock(ToolConfiguration.class); - when(tc.getId()).thenReturn("123456"); - - - Site site = mock(Site.class); - when(site.getToolForCommonId("sakai.gradebookng")).thenReturn(tc); - - try { - when(siteService.getSite(gradebook.getUid())).thenReturn(site); - } catch (Exception e) { - } - - String externalId = "bf3eeca2-1b97-4ead-b605-a8b50a0c6950"; - String reference = "/ref/" + externalId; - String url = "http://localhost/portal/directtool/xhelkdh"; - when(entityManager.getUrl(reference, Entity.UrlType.PORTAL)).thenReturn(Optional.of(url)); - String title = "External One"; - Double points = 55.3D; - Date dueDate = new Date(); - String description = "The Sakai assignments tool"; - - gradingService.addExternalAssessment(gradebook.getUid(), externalId, "http://eggs.com", title, points, dueDate, description, "data", false, null, reference); - Assignment assignment = gradingService.getExternalAssignment(gradebook.getUid(), externalId); - assertEquals(url, gradingService.getUrlForAssignment(assignment)); - - // If the gradable reference hasn't been supplied, we should get the gradebook tool url - String gradebookUrl = "/portal/directtool/" + tc.getId(); - title = "External Two"; - gradingService.addExternalAssessment(gradebook.getUid(), "blah", "http://ham.com", title, points, dueDate, description, "data", false, null); - assignment = gradingService.getExternalAssignment(gradebook.getUid(), "blah"); - assertEquals(gradebookUrl, gradingService.getUrlForAssignment(assignment)); - } - private Long createAssignment1(Gradebook gradebook) { when(securityService.unlock(GradingAuthz.PERMISSION_EDIT_ASSIGNMENTS, "/site/" + gradebook.getUid())).thenReturn(true); //when(siteService.siteReference(gradebook.getUid())).thenReturn("/site/" + gradebook.getUid()); - return gradingService.addAssignment(gradebook.getUid(), ass1); + return gradingService.addAssignment(gradebook.getUid(), siteId, ass1); } private Long createAssignment2(Gradebook gradebook) { @@ -682,13 +630,13 @@ private Long createAssignment2(Gradebook gradebook) { when(securityService.unlock(GradingAuthz.PERMISSION_EDIT_ASSIGNMENTS, "/site/" + gradebook.getUid())).thenReturn(true); //when(siteService.siteReference(gradebook.getUid())).thenReturn("/site/" + gradebook.getUid()); - return gradingService.addAssignment(gradebook.getUid(), ass2); + return gradingService.addAssignment(gradebook.getUid(), siteId, ass2); } private void addCategories(Gradebook gradebook) { - GradebookInformation gradebookInformation = gradingService.getGradebookInformation(gradebook.getUid()); + GradebookInformation gradebookInformation = gradingService.getGradebookInformation(gradebook.getUid(), siteId); var cd1 = new CategoryDefinition(); cd1.setName(cat1Name); @@ -716,7 +664,7 @@ private void addCategories(Gradebook gradebook) { gradebookInformation.setCategories(cats); - gradingService.updateGradebookSettings(gradebook.getUid(), gradebookInformation); + gradingService.updateGradebookSettings(gradebook.getUid(), siteId, gradebookInformation); } @@ -724,7 +672,7 @@ private Gradebook createGradebook() { switchToInstructor(); - return gradingService.addGradebook(siteId); + return gradingService.addGradebook(siteId, siteId); } private void switchToInstructor() { diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/GradebookNgBusinessService.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/GradebookNgBusinessService.java index c85fae094b9d..91987ed9f950 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/GradebookNgBusinessService.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/GradebookNgBusinessService.java @@ -60,15 +60,12 @@ import org.sakaiproject.component.api.ServerConfigurationService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.entity.api.Entity; -import org.sakaiproject.entity.api.ResourceProperties; -import org.sakaiproject.entity.api.ResourcePropertiesEdit; import org.sakaiproject.coursemanagement.api.CourseManagementService; import org.sakaiproject.coursemanagement.api.Enrollment; import org.sakaiproject.coursemanagement.api.EnrollmentSet; import org.sakaiproject.coursemanagement.api.Membership; import org.sakaiproject.coursemanagement.api.Section; import org.sakaiproject.coursemanagement.api.exception.IdNotFoundException; -import org.sakaiproject.gradebookng.business.model.*; import org.sakaiproject.section.api.coursemanagement.CourseSection; import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord; import org.sakaiproject.section.api.facade.Role; @@ -77,6 +74,7 @@ import org.sakaiproject.gradebookng.business.exception.GbAccessDeniedException; import org.sakaiproject.gradebookng.business.exception.GbException; import org.sakaiproject.gradebookng.business.importExport.CommentValidator; +import org.sakaiproject.gradebookng.business.model.*; import org.sakaiproject.gradebookng.business.util.CourseGradeFormatter; import org.sakaiproject.gradebookng.business.util.EventHelper; import org.sakaiproject.gradebookng.business.util.FormatHelper; @@ -84,6 +82,7 @@ import org.sakaiproject.gradebookng.tool.model.GradebookUiSettings; import org.sakaiproject.grading.api.GradingConstants; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.MessageHelper; import org.sakaiproject.rubrics.api.RubricsConstants; import org.sakaiproject.rubrics.api.RubricsService; import org.sakaiproject.section.api.SectionManager; @@ -105,6 +104,7 @@ import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; +import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.tasks.api.Priorities; import org.sakaiproject.tasks.api.Task; import org.sakaiproject.tasks.api.TaskService; @@ -112,9 +112,6 @@ import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.user.api.CandidateDetailProvider; -import org.sakaiproject.user.api.Preferences; -import org.sakaiproject.user.api.PreferencesEdit; -import org.sakaiproject.user.api.PreferencesService; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.user.api.UserNotDefinedException; @@ -160,9 +157,6 @@ public class GradebookNgBusinessService { @Setter private GradingPermissionService gradingPermissionService; - @Setter - private PreferencesService preferencesService; - @Setter private SectionManager sectionManager; @@ -187,8 +181,6 @@ public class GradebookNgBusinessService { @Setter private TaskService taskService; - - public static final String GB_PREF_KEY = "GBNG-"; public static final String ASSIGNMENT_ORDER_PROP = "gbng_assignment_order"; public static final String ICON_SAKAI = "si si-"; public static final String ALL = "all"; @@ -196,70 +188,33 @@ public class GradebookNgBusinessService { private static final String SAK_PROP_ALLOW_STUDENTS_TO_COMPARE_GRADES = "gradebookng.allowStudentsToCompareGradesWithClassmates"; private static final Boolean SAK_PROP_ALLOW_STUDENTS_TO_COMPARE_GRADES_DEFAULT = false; - /** - * Get a list of all users in the current site that can have grades - * - * @return a list of users as uuids or null if none - */ - public List getGradeableUsers() { - return this.getGradeableUsers(getCurrentSiteId()); - } - - /** - * Get a list of all users in the given site that can have grades - * - * @param siteId - * @return a list of users as uuids or null if none - */ - public List getGradeableUsers(final String siteId) { - return this.getGradeableUsers(siteId, null); - } - - /** - * Get the list of gradeable users - * @param groupFilter - * @return - * - */ - public List getGradeableUsers(final GbGroup groupFilter) { - return this.getGradeableUsers(null, groupFilter); - } - /** * Get a list of all users in the given site, filtered by the given group, that can have grades * * @param siteId the id of the site to lookup - * @param groupFilter GbGroupType to filter on + * @param groupFilter Group to filter on * * @return a list of users as uuids or null if none */ - public List getGradeableUsers(final String siteId, final GbGroup groupFilter) { + public List getGradeableUsers(final String gradebookUid, final String siteId, final String groupFilter) { try { - String givenSiteId = siteId; - if (StringUtils.isBlank(givenSiteId)) { - givenSiteId = getCurrentSiteId(); - } - // note that this list MUST exclude TAs as it is checked in the // GradingService and will throw a SecurityException if invalid // users are provided - Site site = siteService.getSite(givenSiteId); + Site site = siteService.getSite(siteId); final Set userUuids = site.getUsersIsAllowed(GbRole.STUDENT.getValue()); // filter the allowed list based on membership - if (groupFilter != null && groupFilter.getType() != GbGroup.Type.ALL) { - + if (StringUtils.isNotBlank(groupFilter) || !gradebookUid.equals(siteId)) { + String groupId = StringUtils.isNotBlank(groupFilter) ? groupFilter : gradebookUid; final Set groupMembers = new HashSet<>(); - if (groupFilter.getType() == GbGroup.Type.GROUP) { - final Set members = this.siteService.getSite(givenSiteId).getGroup(groupFilter.getId()) - .getMembers(); - for (final Member m : members) { - if (userUuids.contains(m.getUserId())) { - groupMembers.add(m.getUserId()); - } + final Set members = site.getGroup(groupId).getMembers(); + for (final Member m : members) { + if (userUuids.contains(m.getUserId())) { + groupMembers.add(m.getUserId()); } } @@ -267,7 +222,7 @@ public List getGradeableUsers(final String siteId, final GbGroup groupFi userUuids.retainAll(groupMembers); } - final GbRole role = this.getUserRole(givenSiteId); + final GbRole role = this.getUserRole(siteId); // if TA, pass it through the gradebook permissions (only if there // are permissions) @@ -276,27 +231,25 @@ public List getGradeableUsers(final String siteId, final GbGroup groupFi // if there are permissions, pass it through them // don't need to test TA access if no permissions - final List perms = getPermissionsForUser(user.getId(),siteId); + final List perms = getPermissionsForUser(user.getId(), gradebookUid, siteId); if (!perms.isEmpty()) { - final Gradebook gradebook = this.getGradebook(givenSiteId); - // get list of sections and groups this TA has access to - final List courseSections = this.gradingService.getViewableSections(gradebook.getUid()); + final List courseSections = this.gradingService.getViewableSections(gradebookUid, siteId); //for each section TA has access to, grab student Id's List viewableStudents = new ArrayList<>(); - Map> groupMembers = getGroupMembers(givenSiteId); + Map> groupMembers = getGroupMemberships(gradebookUid, siteId); //iterate through sections available to the TA and build a list of the student members of each section if(courseSections != null && !courseSections.isEmpty() && groupMembers!=null){ for(CourseSection section:courseSections){ if(groupMembers.containsKey(section.getUuid())) { - Set members = groupMembers.get(section.getUuid()); - for(Member member:members){ - if(givenSiteId!=null && member.getUserId()!=null && securityService.unlock(member.getUserId(), GbPortalPermission.VIEW_OWN_GRADES.getValue(), siteService.siteReference(givenSiteId))/*member.getRole().equals("S")*/){ - viewableStudents.add(member.getUserId()); + List members = groupMembers.get(section.getUuid()); + for (String member : members) { + if (siteId != null && member != null && securityService.unlock(member, GbPortalPermission.VIEW_OWN_GRADES.getValue(), siteService.siteReference(siteId))){ + viewableStudents.add(member); } } } @@ -313,7 +266,7 @@ public List getGradeableUsers(final String siteId, final GbGroup groupFi if (!viewableStudents.isEmpty()) { userUuids.retainAll(viewableStudents); // retain only those that are visible to this TA } else { - userUuids.removeAll(sectionManager.getSectionEnrollmentsForStudents(givenSiteId, userUuids).getStudentUuids()); // TA can view/grade students without section + userUuids.removeAll(sectionManager.getSectionEnrollmentsForStudents(siteId, userUuids).getStudentUuids()); // TA can view/grade students without section nonProvidedMembers.forEach(userUuids::remove); // Filter out non-provided users } } @@ -351,8 +304,7 @@ public List getUsers(final List userUuids) throws GbException { * * @return Map where the user's EID is the key and the {@link GbUser} object is the value */ - public Map getUserEidMap() { - final List users = getGbUsers(getGradeableUsers()); + public Map getUserEidMap(final List users) { final Map userEidMap = new HashMap<>(); for (final GbUser user : users) { final String eid = user.getDisplayId(); @@ -370,11 +322,11 @@ public Map getUserEidMap() { * @param userUuids * @return */ - public List getGbUsers(final List userUuids) + public List getGbUsers(final String siteId, final List userUuids) { final List gbUsers = new ArrayList<>(userUuids.size()); final List users = getUsers(userUuids); - final Site site = getCurrentSite().orElse(null); + final Site site = getSite(siteId).orElse(null); Map> userSections = (site != null) ? getUserSections(site.getId()) : Collections.emptyMap(); @@ -387,68 +339,15 @@ public List getGbUsers(final List userUuids) return gbUsers; } - /** - * Helper to get a reference to the gradebook for the current site - * - * @return the gradebook for the site - */ - public Gradebook getGradebook() { - return getGradebook(getCurrentSiteId()); - } - /** * Helper to get a reference to the gradebook for the specified site * + * @param gradebookUid the gradebookUid * @param siteId the siteId * @return the gradebook for the site */ - private Gradebook getGradebook(String siteId) { - - return gradingService.getGradebook(siteId); - } - - /** - * Get a list of assignments in the gradebook in the current site that the current user is allowed to access - * - * @return a list of assignments or empty list if none/no gradebook - */ - public List getGradebookAssignments() { - return getGradebookAssignments(getCurrentSiteId(), SortType.SORT_BY_SORTING); - } - - /** - * Get a list of assignments in the gradebook in the current site that the current user is allowed to access - * - * @param siteId - * @return a list of assignments or empty list if none/no gradebook - */ - public List getGradebookAssignments(String siteId) { - return getGradebookAssignments(siteId, SortType.SORT_BY_SORTING); - } - - /** - * Get a list of assignments in the gradebook in the current site that the current user is allowed to access sorted by the provided - * SortType - * - * @param sortBy - * @return a list of assignments or empty list if none/no gradebook - */ - public List getGradebookAssignments(final SortType sortBy) { - return getGradebookAssignments(getCurrentSiteId(), sortBy); - } - - /** - * Special operation to get a list of assignments in the gradebook that the specified student has access to. This taked into account - * externally defined assessments that may have grouping permissions applied. - * - * This should only be called if you are wanting to view the assignments that a student would see (ie if you ARE a student, or if you - * are an instructor using the student review mode) - * - * @param studentUuid - * @return a list of assignments or empty list if none/no gradebook - */ - public List getGradebookAssignmentsForStudent(final String studentUuid) { - return getGradebookAssignmentsForStudent(studentUuid, SortType.SORT_BY_SORTING); + public Gradebook getGradebook(String gradebookUid, String siteId) { + return gradingService.getGradebook(gradebookUid, siteId); } /** @@ -462,10 +361,9 @@ public List getGradebookAssignmentsForStudent(final String studentUu * * @return a list of assignments or empty list if none/no gradebook */ - public List getGradebookAssignmentsForStudent(final String studentUuid, final SortType sortedBy) { + public List getGradebookAssignmentsForStudent(final String gradebookUid, final String siteId, final String studentUuid, final SortType sortedBy) { - final Gradebook gradebook = getGradebook(getCurrentSiteId()); - final List assignments = getGradebookAssignments(sortedBy); + final List assignments = getGradebookAssignments(gradebookUid, siteId, sortedBy); // NOTE: cannot do a role check here as it assumes the current user but this could have been called by an instructor (unless we add // a new method to handle this) @@ -476,8 +374,8 @@ public List getGradebookAssignmentsForStudent(final String studentUu while (iter.hasNext()) { final Assignment a = iter.next(); if (a.getExternallyMaintained()) { - if (this.gradingService.isExternalAssignmentGrouped(gradebook.getUid(), a.getExternalId()) && - !this.gradingService.isExternalAssignmentVisible(gradebook.getUid(), a.getExternalId(), + if (this.gradingService.isExternalAssignmentGrouped(gradebookUid, a.getExternalId()) && + !this.gradingService.isExternalAssignmentVisible(gradebookUid, a.getExternalId(), studentUuid)) { iter.remove(); } @@ -489,66 +387,43 @@ public List getGradebookAssignmentsForStudent(final String studentUu /** * Get a list of assignments in the gradebook in the specified site that the current user is allowed to access, sorted by sort order * + * @param gradebookUid * @param siteId the siteId * @param sortBy * @return a list of assignments or empty list if none/no gradebook */ - public List getGradebookAssignments(final String siteId, final SortType sortBy) { + public List getGradebookAssignments(final String gradebookUid, final String siteId, final SortType sortBy) { final List assignments = new ArrayList<>(); - final Gradebook gradebook = getGradebook(siteId); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); if (gradebook != null) { // applies permissions (both student and TA) and default sort is // SORT_BY_SORTING - assignments.addAll(this.gradingService.getViewableAssignmentsForCurrentUser(gradebook.getUid(), sortBy)); + assignments.addAll(this.gradingService.getViewableAssignmentsForCurrentUser(gradebookUid, siteId, sortBy)); } log.debug("Retrieved {} assignments", assignments.size()); return assignments; } - public List getGradebookAssignmentsForCategory(final Long categoryId, final SortType sortBy) { - return getGradebookAssignmentsForCategory(this.getCurrentSiteId(), categoryId, sortBy); - } - - public List getGradebookAssignmentsForCategory(final String siteId, final Long categoryId, final SortType sortBy) { + public List getGradebookAssignmentsForCategory(final String gradebookUid, final String siteId, final Long categoryId, final SortType sortBy) { final List returnList = new ArrayList<>(); - final Gradebook gradebook = getGradebook(siteId); - if (gradebook != null) { // applies permissions (both student and TA) and default sort is SORT_BY_SORTING - final List assignments = this.gradingService.getViewableAssignmentsForCurrentUser(gradebook.getUid(), sortBy); - for (Assignment assignment : assignments) { - if (Objects.equals(assignment.getCategoryId(), categoryId)) { - returnList.add(assignment); - } + final List assignments = getGradebookAssignments(gradebookUid, siteId, sortBy); + for (Assignment assignment : assignments) { + if (Objects.equals(assignment.getCategoryId(), categoryId)) { + returnList.add(assignment); } } return returnList; } - /** - * Get a list of categories in the gradebook in the current site - * - * @return list of categories or null if no gradebook - */ - public List getGradebookCategories() { - return getGradebookCategories(getCurrentSiteId()); - } - - public Optional getCategory(Long categoryId) { - return gradingService.getCategoryDefinition(categoryId); - } - - public void updateCategory(CategoryDefinition category) { - gradingService.updateCategory(category); - } - /** * Get a list of categories in the gradebook in the specified site * * @param siteId the siteId * @return a list of categories or empty if no gradebook */ - public List getGradebookCategories(final String siteId) { - final Gradebook gradebook = getGradebook(siteId); + public List getGradebookCategories(final String gradebookUid, final String siteId) { + final Gradebook gradebook = getGradebook(gradebookUid, siteId); List rval = new ArrayList<>(); @@ -556,8 +431,8 @@ public List getGradebookCategories(final String siteId) { return rval; } - if (categoriesAreEnabled()) { - rval = this.gradingService.getCategoryDefinitions(gradebook.getUid()); + if (categoriesAreEnabled(gradebookUid, siteId)) { + rval = this.gradingService.getCategoryDefinitions(gradebookUid, siteId); } GbRole role; @@ -590,7 +465,7 @@ public List getGradebookCategories(final String siteId) { //if categories is empty (no fine grain permissions enabled), Check permissions, if they are not empty then realms perms exist //and they don't filter to category level so allow all. //This should still allow the gb_permission_t perms to override if the TA is restricted to certain categories - if(viewableCategoryIds.isEmpty() && !this.getPermissionsForUser(user.getId()).isEmpty()){ + if(viewableCategoryIds.isEmpty() && !this.getPermissionsForUser(user.getId(), gradebookUid, siteId).isEmpty()){ viewableCategoryIds = allCategoryIds; } @@ -611,6 +486,14 @@ public List getGradebookCategories(final String siteId) { return rval; } + public Optional getCategory(Long categoryId, String siteId) { + return gradingService.getCategoryDefinition(categoryId, siteId); + } + + public void updateCategory(CategoryDefinition category) { + gradingService.updateCategory(category); + } + /** * Retrieve the categories visible to the given student. * @@ -620,9 +503,9 @@ public List getGradebookCategories(final String siteId) { * @param studentUuid * @return list of visible categories */ - public List getGradebookCategoriesForStudent(String studentUuid) { + public List getGradebookCategoriesForStudent(String gradebookUid, String siteId, String studentUuid) { // find the categories that this student's visible assignments belong to - List viewableAssignments = getGradebookAssignmentsForStudent(studentUuid); + List viewableAssignments = getGradebookAssignmentsForStudent(gradebookUid, siteId, studentUuid, SortType.SORT_BY_SORTING); final List catIds = new ArrayList<>(); for (Assignment a : viewableAssignments) { Long catId = a.getCategoryId(); @@ -635,7 +518,7 @@ public List getGradebookCategoriesForStudent(String studentU SecurityAdvisor gbAdvisor = (String userId, String function, String reference) -> "gradebook.gradeAll".equals(function) ? SecurityAdvice.ALLOWED : SecurityAdvice.PASS; securityService.pushAdvisor(gbAdvisor); - List catDefs = gradingService.getCategoryDefinitions(getGradebook().getUid()); + List catDefs = gradingService.getCategoryDefinitions(gradebookUid, siteId); securityService.popAdvisor(gbAdvisor); // filter out the categories that don't match the categories of the viewable assignments @@ -643,43 +526,6 @@ public List getGradebookCategoriesForStudent(String studentU } - /** - * Get a map of course grades for all students in the given site. - * - * @param siteId siteId to get course grades for - * @return the map of course grades for students, key = studentUuid, value = course grade, or an empty map - */ - public Map getCourseGrades(final String siteId) { - final Gradebook gradebook = this.getGradebook(siteId); - final List studentUuids = this.getGradeableUsers(siteId); - return this.getCourseGrades(gradebook, studentUuids, null); - } - - /** - * Get a map of course grades for all students in the given site using the specified grading schema mapping. - * - * @param siteId siteId to get course grades for - * @param schema grading schema mapping - * @return the map of course grades for students, key = studentUuid, value = course grade, or an empty map - */ - public Map getCourseGrades(final String siteId, final Map schema) { - final Gradebook gradebook = this.getGradebook(siteId); - final List studentUuids = this.getGradeableUsers(siteId); - return this.getCourseGrades(gradebook, studentUuids, schema); - } - - - /** - * Get a map of course grades for the given users. - * - * @param studentUuids uuids for the students - * @return the map of course grades for students, key = studentUuid, value = course grade, or an empty map - */ - public Map getCourseGrades(final List studentUuids) { - final Gradebook gradebook = this.getGradebook(); - return this.getCourseGrades(gradebook, studentUuids, null); - } - /** * Get a map of course grades for the given gradebook, users and optionally the grademap you want to use. * @@ -688,13 +534,13 @@ public Map getCourseGrades(final List s * @param gradeMap the grade mapping to use. This should be left blank if you are displaying grades to students so that the currently persisted value is used. * @return the map of course grades for students, key = studentUuid, value = course grade, or an empty map */ - private Map getCourseGrades(final Gradebook gradebook, final List studentUuids, final Map gradeMap) { + public Map getCourseGrades(final String gradebookUid, final String siteId, final List studentUuids, final Map gradeMap) { Map rval = new HashMap<>(); - if (gradebook != null) { + if (gradebookUid != null) { if(gradeMap != null) { - rval = this.gradingService.getCourseGradeForStudents(gradebook.getUid(), studentUuids, gradeMap); + rval = this.gradingService.getCourseGradeForStudents(gradebookUid, siteId, studentUuids, gradeMap); } else { - rval = this.gradingService.getCourseGradeForStudents(gradebook.getUid(), studentUuids); + rval = this.gradingService.getCourseGradeForStudents(gradebookUid, siteId, studentUuids); } } return rval; @@ -706,10 +552,9 @@ private Map getCourseGrades(final Gradebook gra * @param studentUuid * @return coursegrade. May have null fields if the coursegrade has not been released */ - public CourseGradeTransferBean getCourseGrade(final String studentUuid) { + public CourseGradeTransferBean getCourseGrade(final String gradebookUid, final String siteId, final String studentUuid) { - final Gradebook gradebook = this.getGradebook(); - final CourseGradeTransferBean courseGrade = this.gradingService.getCourseGradeForStudent(gradebook.getUid(), studentUuid); + final CourseGradeTransferBean courseGrade = this.gradingService.getCourseGradeForStudent(gradebookUid, siteId, studentUuid); // handle the special case in the gradebook service where totalPointsPossible = -1 if (courseGrade != null && (courseGrade.getTotalPointsPossible() == null || courseGrade.getTotalPointsPossible() == -1)) { @@ -741,10 +586,10 @@ public Long getCourseGradeId(Long gradebookId){ * * TODO make the concurrency check a boolean instead of the null oldGrade */ - public GradeSaveResponse saveGrade(final Long assignmentId, final String studentUuid, final String oldGrade, + public GradeSaveResponse saveGrade(final String gradebookUid, final String siteId, final Long assignmentId, final String studentUuid, final String oldGrade, final String newGrade, final String comment) { - final Gradebook gradebook = this.getGradebook(); + final Gradebook gradebook = this.getGradebook(gradebookUid, siteId); if (gradebook == null) { return GradeSaveResponse.ERROR; } @@ -755,11 +600,11 @@ public GradeSaveResponse saveGrade(final Long assignmentId, final String student } // get current grade - final String storedGrade = this.gradingService.getAssignmentScoreString(gradebook.getUid(), assignmentId, + final String storedGrade = this.gradingService.getAssignmentScoreString(gradebookUid, siteId, assignmentId, studentUuid); // get assignment config - final Assignment assignment = this.getAssignment(assignmentId); + final Assignment assignment = this.getAssignment(gradebookUid, siteId, assignmentId); final Double maxPoints = assignment.getPoints(); // check what grading mode we are in @@ -874,7 +719,7 @@ public GradeSaveResponse saveGrade(final Long assignmentId, final String student try { // note, you must pass in the comment or it will be nulled out by the GB service // also, must pass in the raw grade as the service does conversions between percentage etc - this.gradingService.saveGradeAndCommentForStudent(gradebook.getUid(), assignmentId, studentUuid, + this.gradingService.saveGradeAndCommentForStudent(gradebookUid, siteId, assignmentId, studentUuid, newGrade, comment); if (rval == null) { // if we don't have some other warning, it was all OK @@ -885,18 +730,18 @@ public GradeSaveResponse saveGrade(final Long assignmentId, final String student rval = GradeSaveResponse.ERROR; } - EventHelper.postUpdateGradeEvent(gradebook, assignmentId, studentUuid, newGrade, rval, getUserRoleOrNone()); + EventHelper.postUpdateGradeEvent(gradebook, assignmentId, studentUuid, newGrade, rval, getUserRoleOrNone(siteId));//mirar si se puede quitar esto y hacer una llamada solamente desde el service? return rval; } - public GradeSaveResponse saveGradesAndCommentsForImport(final Gradebook gradebook, final Assignment assignment, final List gradeDefList) { - if (gradebook == null) { + public GradeSaveResponse saveGradesAndCommentsForImport(final String gradebookUid, final String siteId, final Assignment assignment, final List gradeDefList) { + if (gradebookUid == null) { return GradeSaveResponse.ERROR; } try { - gradingService.saveGradesAndComments(gradebook.getUid(), assignment.getId(), gradeDefList); + gradingService.saveGradesAndComments(gradebookUid, siteId, assignment.getId(), gradeDefList); return GradeSaveResponse.OK; } catch (InvalidGradeException | AssessmentNotFoundException e) { log.error("An error occurred saving the grade. {}: {}", e.getClass(), e.getMessage()); @@ -911,19 +756,18 @@ public GradeSaveResponse saveGradesAndCommentsForImport(final Gradebook gradeboo * @param excuse * @return */ - public GradeSaveResponse saveExcuse(final Long assignmentId, final String studentUuid, final boolean excuse){ - final Gradebook gradebook = this.getGradebook(); - if (gradebook == null) { + public GradeSaveResponse saveExcuse(final String gradebookUid, final String siteId, final Long assignmentId, final String studentUuid, final boolean excuse){ + if (gradebookUid == null) { return GradeSaveResponse.ERROR; } // get current grade - final String storedGrade = this.gradingService.getAssignmentScoreString(gradebook.getUid(), assignmentId, + final String storedGrade = this.gradingService.getAssignmentScoreString(gradebookUid, siteId, assignmentId, studentUuid); // if percentage entry type, reformat the grade, otherwise use points as is String storedGradeAdjusted = storedGrade; - final Integer gradingType = gradebook.getGradeType(); + final Integer gradingType = getGradebook(gradebookUid, siteId).getGradeType(); if (Objects.equals(GradingConstants.GRADE_TYPE_PERCENTAGE, gradingType)) { // the stored grade represents points so the number needs to be adjusted back to percentage Double storedGradePoints = new Double("0.0"); @@ -931,7 +775,7 @@ public GradeSaveResponse saveExcuse(final Long assignmentId, final String studen storedGradePoints = FormatHelper.validateDouble(storedGrade); } - final Double maxPoints = this.getAssignment(assignmentId).getPoints(); + final Double maxPoints = this.getAssignment(gradebookUid, siteId, assignmentId).getPoints(); final Double storedGradePointsFromPercentage = (storedGradePoints * 100) / maxPoints; storedGradeAdjusted = FormatHelper.formatDoubleToDecimal(storedGradePointsFromPercentage); } @@ -944,7 +788,7 @@ public GradeSaveResponse saveExcuse(final Long assignmentId, final String studen // save try { - this.gradingService.saveGradeAndExcuseForStudent(gradebook.getUid(), assignmentId, studentUuid, + this.gradingService.saveGradeAndExcuseForStudent(gradebookUid, siteId, assignmentId, studentUuid, storedGradeAdjusted, excuse); if (rval == null) { @@ -957,57 +801,6 @@ public GradeSaveResponse saveExcuse(final Long assignmentId, final String studen } return rval; } - /** - * Build the matrix of assignments, students and grades for all students - * - * @param assignments list of assignments - * @return - */ - public List buildGradeMatrix(final List assignments) throws GbException { - return this.buildGradeMatrix(assignments, this.getGradeableUsers()); - } - - /** - * Build the matrix of assignments and grades for the given users. In general this is just one, as we use it for the instructor view - * student summary but could be more for paging etc - * - * @param assignments list of assignments - * @param studentUuids of uuids - * @return - */ - public List buildGradeMatrix(final List assignments, final List studentUuids) throws GbException { - return this.buildGradeMatrix(assignments, studentUuids, null); - } - - /** - * Build the matrix of assignments, students and grades for all students, with the specified sortOrder - * - * @param assignments list of assignments - * @param uiSettings the UI settings. Wraps sort order and group filter (sort = null for no sort, filter = null for all groups) - * @return - */ - public List buildGradeMatrix(final List assignments, - final GradebookUiSettings uiSettings) throws GbException { - return this.buildGradeMatrix(assignments, this.getGradeableUsers(uiSettings.getGroupFilter()), uiSettings); - } - - public HashMap buildHasAssociatedRubricMap(final List assignments) { - - HashMap map = new HashMap<>(); - for (Assignment assignment : assignments) { - String externalAppName = assignment.getExternalAppName(); - if (assignment.getExternallyMaintained()) { - String assignmentId = AssignmentReferenceReckoner.reckoner().reference(assignment.getExternalId()).reckon().getId(); - boolean hasAssociatedRubric = StringUtils.equals(externalAppName, AssignmentConstants.TOOL_ID) ? rubricsService.hasAssociatedRubric(externalAppName, assignmentId) : false; - map.put(assignmentId, hasAssociatedRubric); - } else { - Long assignmentId = assignment.getId(); - boolean hasAssociatedRubric = rubricsService.hasAssociatedRubric(RubricsConstants.RBCS_TOOL_GRADEBOOKNG, assignmentId.toString()); - map.put(assignmentId.toString(), hasAssociatedRubric); - } - } - return map; - } /** * Build the matrix of assignments and grades for the given users with the specified sort order @@ -1019,7 +812,7 @@ public HashMap buildHasAssociatedRubricMap(final List buildGradeMatrix(final List assignments, + public List buildGradeMatrix(final String gradebookUid, final String siteId, final List assignments, final List studentUuids, final GradebookUiSettings uiSettings) throws GbException { // TODO move GradebookUISettings to business @@ -1031,7 +824,7 @@ public List buildGradeMatrix(final List assignme stopwatch.start(); stopwatch.timeWithContext("buildGradeMatrix", "buildGradeMatrix start", stopwatch.getTime()); - final Gradebook gradebook = this.getGradebook(); + final Gradebook gradebook = this.getGradebook(gradebookUid, siteId); if (gradebook == null) { return null; } @@ -1043,12 +836,12 @@ public List buildGradeMatrix(final List assignme // get role for current user GbRole role; try { - role = this.getUserRole(); + role = this.getUserRole(siteId); } catch (final GbAccessDeniedException e) { throw new GbException("Error getting role for current user", e); } - final Site site = getCurrentSite().orElse(null); + final Site site = getSite(siteId).orElse(null); // get users final List gbStudents = getGbUsersForUiSettings(studentUuids, settings, site); @@ -1058,15 +851,15 @@ public List buildGradeMatrix(final List assignme final Map matrix = new LinkedHashMap<>(); // get course grades - putCourseGradesInMatrix(matrix, gbStudents, studentUuids, gradebook, role, isCourseGradeVisible(currentUserUuid), settings); + putCourseGradesInMatrix(matrix, gbStudents, studentUuids, gradebook, siteId, role, isCourseGradeVisible(gradebookUid, siteId, currentUserUuid), settings); stopwatch.timeWithContext("buildGradeMatrix", "putCourseGradesInMatrix", stopwatch.getTime()); // get assignments and categories - putAssignmentsAndCategoryItemsInMatrix(matrix, gbStudents, studentUuids, assignments, gradebook, currentUserUuid, role, settings); + putAssignmentsAndCategoryItemsInMatrix(matrix, gbStudents, studentUuids, assignments, gradebook, siteId, currentUserUuid, role, settings); stopwatch.timeWithContext("buildGradeMatrix", "putAssignmentsAndCategoryItemsInMatrix", stopwatch.getTime()); // sorting - List items = sortGradeMatrix(matrix, settings); + List items = sortGradeMatrix(gradebookUid, siteId, matrix, settings); stopwatch.timeWithContext("buildGradeMatrix", "sortGradeMatrix", stopwatch.getTime()); return items; @@ -1079,13 +872,13 @@ public List buildGradeMatrix(final List assignme * @param groupFilter * @return */ - public List buildGradeMatrixForImportExport(final List assignments, GbGroup groupFilter) throws GbException { + public List buildGradeMatrixForImportExport(final String gradebookUid, final String siteId, final List assignments, String groupFilter) throws GbException { // ------------- Initialization ------------- final GbStopWatch stopwatch = new GbStopWatch(); stopwatch.start(); stopwatch.timeWithContext("buildGradeMatrixForImportExport", "buildGradeMatrix start", stopwatch.getTime()); - final Gradebook gradebook = this.getGradebook(); + final Gradebook gradebook = this.getGradebook(gradebookUid, siteId); if (gradebook == null) { return Collections.EMPTY_LIST; } @@ -1097,7 +890,7 @@ public List buildGradeMatrixForImportExport(final List buildGradeMatrixForImportExport(final List studentUUIDs = getGradeableUsers(groupFilter); - final List gbStudents = getGbUsers(studentUUIDs); + final List studentUUIDs = getGradeableUsers(gradebookUid, siteId, groupFilter); + final List gbStudents = getGbUsers(siteId, studentUUIDs); stopwatch.timeWithContext("buildGradeMatrixForImportExport", "getGbUsersForUiSettings", stopwatch.getTime()); // ------------- Course Grades ------------- final Map matrix = new LinkedHashMap<>(); - putCourseGradesInMatrix(matrix, gbStudents, studentUUIDs, gradebook, role, isCourseGradeVisible(currentUserUuid), settings); + putCourseGradesInMatrix(matrix, gbStudents, studentUUIDs, gradebook, siteId, role, isCourseGradeVisible(gradebookUid, siteId, currentUserUuid), settings); stopwatch.timeWithContext("buildGradeMatrixForImportExport", "putCourseGradesInMatrix", stopwatch.getTime()); // ------------- Assignments ------------- - putAssignmentsAndCategoryItemsInMatrix(matrix, gbStudents, studentUUIDs, assignments, gradebook, currentUserUuid, role, settings); + putAssignmentsAndCategoryItemsInMatrix(matrix, gbStudents, studentUUIDs, assignments, gradebook, siteId, currentUserUuid, role, settings); stopwatch.timeWithContext("buildGradeMatrixForImportExport", "putAssignmentsAndCategoryItemsInMatrix", stopwatch.getTime()); // ------------- Sorting ------------- - List items = sortGradeMatrix(matrix, settings); + List items = sortGradeMatrix(gradebook.getUid(), siteId, matrix, settings); stopwatch.timeWithContext("buildGradeMatrixForImportExport", "sortGradeMatrix", stopwatch.getTime()); return items; } - public List buildMatrixForGradeComparison(Assignment assignment, Integer gradingType, GradebookInformation settings){ + public List buildMatrixForGradeComparison(String gradebookUid, String siteId, Assignment assignment, Integer gradingType, GradebookInformation settings){ // Only return the list if the feature is activated boolean serverPropertyOn = serverConfigService.getConfig( SAK_PROP_ALLOW_STUDENTS_TO_COMPARE_GRADES, @@ -1153,7 +946,7 @@ public List buildMatrixForGradeComparison(Assignment assi SecurityAdvisor advisor = null; try { advisor = addSecurityAdvisor(); - data = buildGradeMatrix(Collections.singletonList(assignment)) + data = buildGradeMatrix(gradebookUid, siteId, Collections.singletonList(assignment), getGradeableUsers(gradebookUid, siteId, null), null) .stream().map(GbGradeComparisonItem::new) .map(el -> { if(isComparingOrDisplayingFullName){ @@ -1300,15 +1093,16 @@ public List getGbUsersForUiSettings(List userUuids, GradebookUiS * @param matrix mapping of student uids to GbStudentGradeInfo in which to store course grades * @param gbStudents list of student for whom to retrieve course grades * @param studentUuids list of student UUIDs so we don't have to parse the list of GbUsers to extract the values if we already have them - * @param gradebook current site's gradebook + * @param gradebook current gradebook + * @param siteId current site * @param role current user's GbRole in the site * @param isCourseGradeVisible whether the current user can see course grades in this site * @param settings GradebookUiSettings instance */ - public void putCourseGradesInMatrix(Map matrix, List gbStudents, List studentUuids, Gradebook gradebook, GbRole role, + public void putCourseGradesInMatrix(Map matrix, List gbStudents, List studentUuids, Gradebook gradebook, String siteId, GbRole role, boolean isCourseGradeVisible, GradebookUiSettings settings) { // Get the course grades - final Map courseGrades = getCourseGrades(studentUuids); + final Map courseGrades = getCourseGrades(gradebook.getUid(), siteId, studentUuids, null); // Return quickly if it is empty (maybe failed permission checks) if (courseGrades == null || courseGrades.isEmpty()) return; @@ -1331,7 +1125,7 @@ public void putCourseGradesInMatrix(Map matrix, List gbCourseGrade.setDisplayString(courseGradeFormatter.format(courseGrade)); } sg.setCourseGrade(gbCourseGrade); - sg.setHasCourseGradeComment(StringUtils.isNotBlank(getAssignmentGradeComment(getCurrentSiteId(),courseGrade.getId(),uid))); + sg.setHasCourseGradeComment(StringUtils.isNotBlank(getAssignmentGradeComment(gradebook.getUid(), courseGrade.getId(),uid))); // Add to map so we can build on it later matrix.put(uid, sg); } @@ -1344,12 +1138,13 @@ public void putCourseGradesInMatrix(Map matrix, List * @param studentUuids list of student UUIDs, so we don't have to extract out of gbStudents * @param assignments the list of assignments for which to retrieve grading data. Computes category scores associated with these assignments as appropriate * @param gradebook the gradebook containing the assignments, etc. + * @param siteId current site * @param currentUserUuid * @param role the current user's role * @param settings the GradebookUiSettings instance associated with the user's session; used to determine whether the context is anonymous. If null, all grading data will be retrieved without any anonymous aware filtering */ public void putAssignmentsAndCategoryItemsInMatrix(Map matrix, List gbStudents, List studentUuids, List assignments, - Gradebook gradebook, String currentUserUuid, GbRole role, GradebookUiSettings settings) { + Gradebook gradebook, String siteId, String currentUserUuid, GbRole role, GradebookUiSettings settings) { // Ensure the matrix is populated with GbStudentGradeInfo instances for each student gbStudents.stream().forEach(gbStudent -> { @@ -1361,7 +1156,7 @@ public void putAssignmentsAndCategoryItemsInMatrix(Map categories = this.getGradebookCategories(); + final List categories = this.getGradebookCategories(gradebook.getUid(), siteId); // for TA's, build a lookup map of visible categoryIds so we can filter // the assignment list to not fetch grades @@ -1424,7 +1219,7 @@ public void putAssignmentsAndCategoryItemsInMatrix(Map defs = this.gradingService.getGradesForStudentsForItem(gradebook.getUid(), assignment.getId(), studentUuids); + final List defs = this.gradingService.getGradesForStudentsForItem(gradebook.getUid(), siteId, assignment.getId(), studentUuids); // iterate the definitions returned and update the record for each // student with the grades @@ -1489,7 +1284,7 @@ public void putAssignmentsAndCategoryItemsInMatrix(Map permissions = getPermissionsForUser(currentUserUuid); + final List permissions = getPermissionsForUser(currentUserUuid, gradebook.getUid(), siteId); log.debug("All permissions: {}", permissions.size()); @@ -1512,7 +1307,7 @@ public void putAssignmentsAndCategoryItemsInMatrix(Map> groupMembershipsMap = getGroupMemberships(); + final Map> groupMembershipsMap = getGroupMemberships(gradebook.getUid(), siteId); //Pair group <-> category Map > permByCat = new HashMap<>(); @@ -1593,11 +1388,12 @@ public void putAssignmentsAndCategoryItemsInMatrix(Map matrix, List gbStudents, List studentUuids, List assignments, - Gradebook gradebook, String currentUserUuid, GbRole role) { + Gradebook gradebook, String siteId, String currentUserUuid, GbRole role) { // Collect list of studentUuids, and ensure the matrix is populated with GbStudentGradeInfo instances for each student gbStudents.stream().forEach(gbStudent -> { String userUuid = gbStudent.getUserUuid(); @@ -1615,7 +1411,7 @@ public void putAssignmentsInMatrixForExport(Map matr for (final Assignment assignment : assignments) { // get grades - final List defs = this.gradingService.getGradesForStudentsForItem(gradebook.getUid(), assignment.getId(), studentUuids); + final List defs = this.gradingService.getGradesForStudentsForItem(gradebook.getUid(), siteId, assignment.getId(), studentUuids); // iterate the definitions returned and update the record for each // student with the grades @@ -1638,7 +1434,7 @@ public void putAssignmentsInMatrixForExport(Map matr if (role == GbRole.TA) { // get permissions - final List permissions = getPermissionsForUser(currentUserUuid); + final List permissions = getPermissionsForUser(currentUserUuid, gradebook.getUid(), siteId); log.debug("All permissions: {}", permissions.size()); @@ -1661,7 +1457,7 @@ public void putAssignmentsInMatrixForExport(Map matr } // get the group membership for the students - final Map> groupMembershipsMap = getGroupMemberships(); + final Map> groupMembershipsMap = getGroupMemberships(gradebook.getUid(), siteId); // for every student for (final GbUser student : gbStudents) { @@ -1735,11 +1531,13 @@ public void putAssignmentsInMatrixForExport(Map matr /** * Takes the value set of the matrix (a map), and sorts the value set appropriately wrt the GradebookUiSettings + * @param gradebookUid + * @param siteId * @param matrix * @param settings * @return the valueSet of the matrix as an appropriately sorted List */ - public List sortGradeMatrix(Map matrix, GradebookUiSettings settings) { + public List sortGradeMatrix(String gradebookUid, String siteId, Map matrix, GradebookUiSettings settings) { // get the matrix as a list of GbStudentGradeInfo final List items = new ArrayList<>(matrix.values()); @@ -1773,7 +1571,7 @@ public List sortGradeMatrix(Map } if (settings.getCourseGradeSortOrder() != null) { - Comparator comp = new CourseGradeComparator(getGradebookSettings()); + Comparator comp = new CourseGradeComparator(getGradebookSettings(gradebookUid, siteId)); // reverse if required if (settings.getCourseGradeSortOrder() == SortDirection.DESCENDING) { @@ -1792,8 +1590,7 @@ public List sortGradeMatrix(Map * * @return a list of sections and groups in the current site */ - public List getSiteSectionsAndGroups() { - final String siteId = getCurrentSiteId(); + public List getSiteSectionsAndGroups(String gradebookUid, String siteId) { final List rval = new ArrayList<>(); @@ -1809,9 +1606,10 @@ public List getSiteSectionsAndGroups() { try { final Site site = this.siteService.getSite(siteId); final Collection groups = isSuperUser() || role == GbRole.INSTRUCTOR ? site.getGroups() : site.getGroupsWithMember(userDirectoryService.getCurrentUser().getId()); - for (final Group group : groups) { - rval.add(new GbGroup(group.getId(), group.getTitle(), group.getReference(), GbGroup.Type.GROUP)); + if (gradebookUid.equals(siteId) || gradebookUid.equals(group.getId())) { + rval.add(new GbGroup(group.getId(), group.getTitle(), group.getReference(), GbGroup.Type.GROUP)); + } } } catch (final IdUnusedException e) { @@ -1823,7 +1621,7 @@ public List getSiteSectionsAndGroups() { // if user is a TA, get the groups they can see and filter the GbGroup // list to keep just those if (role == GbRole.TA) { - final Gradebook gradebook = this.getGradebook(siteId); + final Gradebook gradebook = this.getGradebook(gradebookUid, siteId); final User user = getCurrentUser(); boolean canGradeAll = false; @@ -1845,7 +1643,7 @@ public List getSiteSectionsAndGroups() { //FIXME: Another realms hack. The above method only returns groups from gb_permission_t. If this list is empty, //need to check realms to see if user has privilege to grade any groups. This is already done in if (CollectionUtils.isEmpty(viewableGroupIds)) { - List realmsPerms = this.getPermissionsForUser(user.getId()); + List realmsPerms = this.getPermissionsForUser(user.getId(), gradebookUid, siteId); if (CollectionUtils.isNotEmpty(realmsPerms)) { for (PermissionDefinition permDef : realmsPerms) { if (permDef.getGroupReference() != null) { @@ -1875,99 +1673,13 @@ public List getSiteSectionsAndGroups() { return rval; } - private List getSiteSectionsAndGroups(final String siteId) { - - final List rval = new ArrayList<>(); - - // get groups (handles both groups and sections) - try { - final Site site = this.siteService.getSite(siteId); - final Collection groups = site.getGroups(); - - for (final Group group : groups) { - rval.add(new GbGroup(group.getId(), group.getTitle(), group.getReference(), GbGroup.Type.GROUP)); - } - - } catch (final IdUnusedException e) { - // essentially ignore and use what we have - log.error("Error retrieving groups", e); - } - - GbRole role; - try { - role = this.getUserRole(siteId); - } catch (final GbAccessDeniedException e) { - log.warn("GbAccessDeniedException trying to getGradebookCategories", e); - return rval; - } - - // if user is a TA, get the groups they can see and filter the GbGroup - // list to keep just those - if (role == GbRole.TA) { - final Gradebook gradebook = this.getGradebook(siteId); - final User user = getCurrentUser(); - - // need list of all groups as REFERENCES (not ids) - final List allGroupIds = new ArrayList<>(); - for (final GbGroup group : rval) { - allGroupIds.add(group.getReference()); - } - - // get the ones the TA can actually view - // note that if a group is empty, it will not be included. - List viewableGroupIds = this.gradingPermissionService - .getViewableGroupsForUser(gradebook.getId(), user.getId(), allGroupIds); - - //FIXME: Another realms hack. The above method only returns groups from gb_permission_t. If this list is empty, - //need to check realms to see if user has privilege to grade any groups. This is already done in - if(CollectionUtils.isEmpty(viewableGroupIds)){ - List realmsPerms = this.getPermissionsForUser(user.getId(),siteId); - if(CollectionUtils.isNotEmpty(realmsPerms)){ - for(PermissionDefinition permDef : realmsPerms){ - if(permDef.getGroupReference()!=null){ - viewableGroupIds.add(permDef.getGroupReference()); - } - } - } - } - - // remove the ones that the user can't view - final Iterator iter = rval.iterator(); - while (iter.hasNext()) { - final GbGroup group = iter.next(); - if (!viewableGroupIds.contains(group.getReference())) { - iter.remove(); - } - } - - } - - Collections.sort(rval); - - return rval; - } - - /** - * Helper to get siteid. This will ONLY work in a portal site context, it will return null otherwise (ie via an entityprovider). - * - * @return - */ - public String getCurrentSiteId() { - try { - return this.toolManager.getCurrentPlacement().getContext(); - } catch (final Exception e) { - return null; - } - } - /** * Helper to get site. This will ONLY work in a portal site context, it will return empty otherwise (ie via an entityprovider). * * @return */ - public Optional getCurrentSite() + public Optional getSite(String siteId) { - final String siteId = getCurrentSiteId(); if (siteId != null) { try @@ -2004,45 +1716,45 @@ public boolean isSuperUser() { /** * Add a new assignment definition to the gradebook * + * @param gradebookUid + * @param siteId * @param assignment * @return id of the newly created assignment or null if there were any errors */ - public Long addAssignment(final Assignment assignment) { + public Long addAssignment(final String gradebookUid, final String siteId, final Assignment assignment) { - final Gradebook gradebook = getGradebook(); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); if (gradebook != null) { - final String gradebookId = gradebook.getUid(); - - final Long assignmentId = this.gradingService.addAssignment(gradebookId, assignment); + final Long assignmentId = this.gradingService.addAssignment(gradebookUid, siteId, assignment); // Force the assignment to sit at the end of the list if (assignment.getSortOrder() == null) { - final List allAssignments = this.gradingService.getAssignments(gradebookId); + final List allAssignments = this.gradingService.getAssignments(gradebookUid, siteId, SortType.SORT_BY_NONE); int nextSortOrder = allAssignments.size(); for (final Assignment anotherAssignment : allAssignments) { if (anotherAssignment.getSortOrder() != null && anotherAssignment.getSortOrder() >= nextSortOrder) { nextSortOrder = anotherAssignment.getSortOrder() + 1; } } - updateAssignmentOrder(assignmentId, nextSortOrder); + updateAssignmentOrder(gradebookUid, siteId, assignmentId, nextSortOrder); } // also update the categorized order - updateAssignmentCategorizedOrder(gradebook.getUid(), assignment.getCategoryId(), assignmentId, + updateAssignmentCategorizedOrder(gradebookUid, siteId, assignment.getCategoryId(), assignmentId, Integer.MAX_VALUE); - EventHelper.postAddAssignmentEvent(gradebook, assignmentId, assignment, getUserRoleOrNone()); + EventHelper.postAddAssignmentEvent(gradebook, assignmentId, assignment, getUserRoleOrNone(siteId)); if (assignment.getReleased()) { - String reference = GradingConstants.REFERENCE_ROOT + Entity.SEPARATOR + "a" + Entity.SEPARATOR + getCurrentSiteId() + Entity.SEPARATOR + assignmentId; + String reference = GradingConstants.REFERENCE_ROOT + Entity.SEPARATOR + "a" + Entity.SEPARATOR + siteId + Entity.SEPARATOR + assignmentId; Task task = new Task(); - task.setSiteId(getCurrentSiteId()); + task.setSiteId(siteId); task.setReference(reference); task.setSystem(true); task.setDescription(assignment.getName()); task.setDue((assignment.getDueDate() == null) ? null : assignment.getDueDate().toInstant()); - Set users = new HashSet<>(this.getGradeableUsers()); + Set users = new HashSet<>(this.getGradeableUsers(gradebookUid, siteId, null)); taskService.createTask(task, users, Priorities.HIGH); } @@ -2053,81 +1765,47 @@ public Long addAssignment(final Assignment assignment) { return null; } - /** - * Update the order of an assignment for the current site. - * - * @param assignmentId - * @param order - */ - public void updateAssignmentOrder(final long assignmentId, final int order) { - - final String siteId = getCurrentSiteId(); - this.updateAssignmentOrder(siteId, assignmentId, order); - } - /** * Update the order of an assignment. If calling outside of GBNG, use this method as you can provide the site id. * + * @param gradebookUid the gradebookUid * @param siteId the siteId * @param assignmentId the assignment we are reordering * @param order the new order */ - public void updateAssignmentOrder(final String siteId, final long assignmentId, final int order) { - - final Gradebook gradebook = this.getGradebook(siteId); - this.gradingService.updateAssignmentOrder(gradebook.getUid(), assignmentId, order); - } - - /** - * Update the categorized order of an assignment. - * - * @param assignmentId the assignment we are reordering - * @param order the new order - * @throws IdUnusedException - * @throws PermissionException - */ - public void updateAssignmentCategorizedOrder(final long assignmentId, final int order) - throws IdUnusedException, PermissionException { - final String siteId = getCurrentSiteId(); - updateAssignmentCategorizedOrder(siteId, assignmentId, order); + public void updateAssignmentOrder(final String gradebookUid, final String siteId, final long assignmentId, final int order) { + this.gradingService.updateAssignmentOrder(gradebookUid, siteId, assignmentId, order); } /** * Update the categorized order of an assignment. * + * @param gradebookUid the gradebookUid * @param siteId the site's id * @param assignmentId the assignment we are reordering * @param order the new order * @throws IdUnusedException * @throws PermissionException */ - public void updateAssignmentCategorizedOrder(final String siteId, final long assignmentId, final int order) + public void updateAssignmentCategorizedOrder(final String gradebookUid, final String siteId, final long assignmentId, final int order) throws IdUnusedException, PermissionException { - // validate site - try { - this.siteService.getSite(siteId); - } catch (final IdUnusedException e) { - log.warn("IdUnusedException trying to updateAssignmentCategorizedOrder", e); - return; - } - - final Gradebook gradebook = (Gradebook) this.gradingService.getGradebook(siteId); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); if (gradebook == null) { - log.error(String.format("Gradebook not in site %s", siteId)); + log.error("Gradebook {} not found", gradebookUid); return; } - final Assignment assignmentToMove = this.gradingService.getAssignment(gradebook.getUid(), assignmentId); + final Assignment assignmentToMove = this.gradingService.getAssignment(gradebookUid, siteId, assignmentId); if (assignmentToMove == null) { // TODO Handle assignment not in gradebook - log.error(String.format("GradebookAssignment %d not in site %s", assignmentId, siteId)); + log.error("GradebookAssignment {} not found in gradebook {}", assignmentId, gradebookUid); return; } - updateAssignmentCategorizedOrder(gradebook.getUid(), assignmentToMove.getCategoryId(), assignmentToMove.getId(), + updateAssignmentCategorizedOrder(gradebookUid, siteId, assignmentToMove.getCategoryId(), assignmentToMove.getId(), order); } @@ -2135,29 +1813,31 @@ public void updateAssignmentCategorizedOrder(final String siteId, final long ass * Update the categorized order of an assignment via the gradebook service. * * @param gradebookId the gradebook's id + * @param siteId the site's id * @param categoryId the id for the cataegory in which we are reordering * @param assignmentId the assignment we are reordering * @param order the new order */ - private void updateAssignmentCategorizedOrder(final String gradebookId, final Long categoryId, + private void updateAssignmentCategorizedOrder(final String gradebookId, final String siteId, final Long categoryId, final Long assignmentId, final int order) { - this.gradingService.updateAssignmentCategorizedOrder(gradebookId, categoryId, assignmentId, order); + this.gradingService.updateAssignmentCategorizedOrder(gradebookId, siteId, categoryId, assignmentId, order); } /** * Get a list of edit events for this gradebook. Excludes any events for the current user * * @param gradebookUid the gradebook that we are interested in + * @param siteId the site id * @param since the time to check for changes from * @return */ - public List getEditingNotifications(final String gradebookUid, final Date since) { + public List getEditingNotifications(final String gradebookUid, final String siteId, final Date since) { final User currentUser = getCurrentUser(); final List rval = new ArrayList<>(); - final List assignments = this.gradingService.getViewableAssignmentsForCurrentUser(gradebookUid, + final List assignments = this.gradingService.getViewableAssignmentsForCurrentUser(gradebookUid, siteId, SortType.SORT_BY_SORTING); log.debug("Retrieved {} assignments", assignments.size()); final List assignmentIds = assignments.stream().map(a -> a.getId()).collect(Collectors.toList()); @@ -2184,56 +1864,34 @@ public List getEditingNotifications(final String gradebookUid, fina return rval; } - - /** - * Get an GradebookAssignment in the current site given the assignment id - * - * @param assignmentId - * @return - */ - public Assignment getAssignment(final long assignmentId) { - return this.getAssignment(getCurrentSiteId(), assignmentId); - } - /** * Get an GradebookAssignment in the specified site given the assignment id * + * @param gradebookUid * @param siteId * @param assignmentId * @return */ - public Assignment getAssignment(final String siteId, final long assignmentId) { - final Gradebook gradebook = getGradebook(siteId); - if (gradebook != null) { - return this.gradingService.getAssignment(gradebook.getUid(), assignmentId); + public Assignment getAssignment(final String gradebookUid, final String siteId, final long assignmentId) { + if (gradebookUid != null) { + return this.gradingService.getAssignment(gradebookUid, siteId, assignmentId); } return null; } - /** - * Get an GradebookAssignment in the current site given the assignment name This should be avoided where possible but is required for the import - * process to allow modification of assignment point values - * - * @param assignmentName - * @return - */ - public Assignment getAssignment(final String assignmentName) { - return this.getAssignment(getCurrentSiteId(), assignmentName); - } - /** * Get an GradebookAssignment in the specified site given the assignment name This should be avoided where possible but is required for the * import process to allow modification of assignment point values * + * @param gradebookUid * @param siteId * @param assignmentName * @return */ @SuppressWarnings("deprecation") - public Assignment getAssignment(final String siteId, final String assignmentName) { - final Gradebook gradebook = getGradebook(siteId); - if (gradebook != null) { - return this.gradingService.getAssignment(gradebook.getUid(), assignmentName); + public Assignment getAssignment(final String gradebookUid, final String siteId, final String assignmentName) { + if (gradebookUid != null) { + return this.gradingService.getAssignment(gradebookUid, siteId, assignmentName); } return null; } @@ -2245,15 +1903,15 @@ public Assignment getAssignment(final String siteId, final String assignmentName * This means that we can always determine the most current sort order for an assignment, even if the list has never been sorted. * * + * @param gradebookUid + * @param siteId * @param assignmentId * @return sort order if set, or calculated, or -1 if cannot determine at all. */ - public int getAssignmentSortOrder(final long assignmentId) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); + public int getAssignmentSortOrder(final String gradebookUid, final String siteId, final long assignmentId) { - if (gradebook != null) { - final Assignment assignment = this.gradingService.getAssignment(gradebook.getUid(), assignmentId); + if (gradebookUid != null) { + final Assignment assignment = this.gradingService.getAssignment(gradebookUid, siteId, assignmentId); // if the assignment has a sort order, return that if (assignment.getSortOrder() != null) { @@ -2262,7 +1920,7 @@ public int getAssignmentSortOrder(final long assignmentId) { // otherwise we need to determine the assignment sort order within // the list of assignments - final List assignments = this.getGradebookAssignments(siteId); + final List assignments = this.getGradebookAssignments(gradebookUid, siteId, SortType.SORT_BY_SORTING); for (int i = 0; i < assignments.size(); i++) { final Assignment a = assignments.get(i); @@ -2278,20 +1936,21 @@ public int getAssignmentSortOrder(final long assignmentId) { /** * Update the details of an assignment * + * @param gradebookUid + * @param siteId * @param assignment * @return */ - public void updateAssignment(final Assignment assignment) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); + public void updateAssignment(final String gradebookUid, final String siteId, final Assignment assignment) { + final Gradebook gradebook = getGradebook(gradebookUid, siteId); // need the original name as the service needs that as the key... - final Assignment original = this.getAssignment(assignment.getId()); + final Assignment original = this.getAssignment(gradebookUid, siteId, assignment.getId()); - gradingService.updateAssignment(gradebook.getUid(), original.getId(), assignment); + gradingService.updateAssignment(gradebook.getUid(), siteId, original.getId(), assignment); // Update task - String reference = GradingConstants.REFERENCE_ROOT + Entity.SEPARATOR + "a" + Entity.SEPARATOR + getCurrentSiteId() + Entity.SEPARATOR + original.getId(); + String reference = GradingConstants.REFERENCE_ROOT + Entity.SEPARATOR + "a" + Entity.SEPARATOR + siteId + Entity.SEPARATOR + original.getId(); Optional optTask = taskService.getTask(reference); if (optTask.isPresent()) { Task task = optTask.get(); @@ -2301,53 +1960,43 @@ public void updateAssignment(final Assignment assignment) { } else if(assignment.getReleased()) { // Create the task Task task = new Task(); - task.setSiteId(getCurrentSiteId()); + task.setSiteId(siteId); task.setReference(reference); task.setSystem(true); task.setDescription(assignment.getName()); task.setDue((assignment.getDueDate() == null) ? null : assignment.getDueDate().toInstant()); - Set users = new HashSet<>(this.getGradeableUsers()); + Set users = new HashSet<>(this.getGradeableUsers(gradebookUid, siteId, null)); taskService.createTask(task, users, Priorities.HIGH); } - EventHelper.postUpdateAssignmentEvent(gradebook, assignment, getUserRoleOrNone()); + EventHelper.postUpdateAssignmentEvent(gradebook, assignment, getUserRoleOrNone(siteId)); if (original.getCategoryId() != null && assignment.getCategoryId() != null && original.getCategoryId().longValue() != assignment.getCategoryId().longValue()) { - updateAssignmentCategorizedOrder(gradebook.getUid(), assignment.getCategoryId(), assignment.getId(), + updateAssignmentCategorizedOrder(gradebook.getUid(), siteId, assignment.getCategoryId(), assignment.getId(), Integer.MAX_VALUE); } } - /** - * Updates ungraded items in the given assignment with the given grade - * - * @param assignmentId - * @param grade - * @return - */ - public boolean updateUngradedItems(final long assignmentId, final String grade) { - return updateUngradedItems(assignmentId, grade, null); - } - /** * Updates ungraded items in the given assignment for students within a particular group and with the given grade * + * @param gradebookUid + * @param siteId * @param assignmentId * @param grade * @param group * @return */ - public boolean updateUngradedItems(final long assignmentId, final String grade, final GbGroup group) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); - final Assignment assignment = getAssignment(assignmentId); + public boolean updateUngradedItems(final String gradebookUid, final String siteId, final long assignmentId, final String grade, final String group) { + final Gradebook gradebook = getGradebook(gradebookUid, siteId); + final Assignment assignment = getAssignment(gradebookUid, siteId, assignmentId); // get students - final List studentUuids = (group == null) ? this.getGradeableUsers() : this.getGradeableUsers(group); + final List studentUuids = this.getGradeableUsers(gradebookUid, siteId, group); // get grades (only returns those where there is a grade, or comment; does not return those where there is no grade AND no comment) - final List defs = this.gradingService.getGradesForStudentsForItem(gradebook.getUid(), assignmentId, studentUuids); + final List defs = this.gradingService.getGradesForStudentsForItem(gradebook.getUid(), siteId, assignmentId, studentUuids); // Remove students who already have a grade studentUuids.removeIf(studentUUID -> defs.stream().anyMatch(def -> studentUUID.equals(def.getStudentUid()) && StringUtils.isNotBlank(def.getGrade()))); @@ -2377,8 +2026,8 @@ public boolean updateUngradedItems(final long assignmentId, final String grade, // Batch update the GradeDefinitions, and post an event on completion try { - gradingService.saveGradesAndComments(gradebook.getUid(), assignmentId, defs); - EventHelper.postUpdateUngradedEvent(gradebook, assignmentId, String.valueOf(grade), getUserRoleOrNone()); + gradingService.saveGradesAndComments(gradebook.getUid(), siteId, assignmentId, defs); + EventHelper.postUpdateUngradedEvent(gradebook, assignmentId, String.valueOf(grade), getUserRoleOrNone(siteId)); return true; } catch (final Exception e) { log.error("An error occurred updating the assignment", e); @@ -2423,27 +2072,16 @@ public GbUser getUser(final String userUuid) { /** * Get the comment for a given student assignment grade * - * @param assignmentId id of assignment - * @param studentUuid uuid of student - * @return the comment or null if none - */ - public String getAssignmentGradeComment(final long assignmentId, final String studentUuid) { - return getAssignmentGradeComment(getCurrentSiteId(), assignmentId, studentUuid); - } - - /** - * Get the comment for a given student assignment grade - * + * @param gradebookUid * @param siteId site id * @param assignmentId id of assignment * @param studentUuid uuid of student * @return the comment or null if none */ - public String getAssignmentGradeComment(final String siteId, final long assignmentId, final String studentUuid) { - final Gradebook gradebook = getGradebook(siteId); + public String getAssignmentGradeComment(final String gradebookUid, final long assignmentId, final String studentUuid) { try { - final CommentDefinition def = this.gradingService.getAssignmentScoreComment(gradebook.getUid(), + final CommentDefinition def = this.gradingService.getAssignmentScoreComment(gradebookUid, assignmentId, studentUuid); if (def != null) { return def.getCommentText(); @@ -2454,15 +2092,10 @@ public String getAssignmentGradeComment(final String siteId, final long assignme return null; } - public String getAssignmentExcuse(final long assignmentId, final String studentUuid){ - return getAssignmentExcuse(getCurrentSiteId(), assignmentId, studentUuid); - } - - public String getAssignmentExcuse(final String siteId, final long assignmentId, final String studentUuid){ - final Gradebook gradebook = getGradebook(siteId); + public String getAssignmentExcuse(final String gradebookUid, final long assignmentId, final String studentUuid){ try{ - final boolean excuse = this.gradingService.getIsAssignmentExcused(gradebook.getUid(), assignmentId, studentUuid); + final boolean excuse = this.gradingService.getIsAssignmentExcused(gradebookUid, assignmentId, studentUuid); if(excuse){ return "1"; }else{ @@ -2477,23 +2110,24 @@ public String getAssignmentExcuse(final String siteId, final long assignmentId, /** * Update (or set) the comment for a student's assignment * + * @param gradebookUid + * @param siteId * @param assignmentId id of assignment * @param studentUuid uuid of student * @param comment the comment * @return true/false */ - public boolean updateAssignmentGradeComment(final long assignmentId, final String studentUuid, + public boolean updateAssignmentGradeComment(final String gradebookUid, final String siteId, final long assignmentId, final String studentUuid, final String comment) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); try { // could do a check here to ensure we aren't overwriting someone // else's comment that has been updated in the interim... - this.gradingService.setAssignmentScoreComment(gradebook.getUid(), assignmentId, studentUuid, comment); + this.gradingService.setAssignmentScoreComment(gradebookUid, assignmentId, studentUuid, comment); - EventHelper.postUpdateCommentEvent(getGradebook(), assignmentId, studentUuid, comment, getUserRoleOrNone()); + EventHelper.postUpdateCommentEvent(gradebook, assignmentId, studentUuid, comment, getUserRoleOrNone(siteId)); return true; } catch (AssessmentNotFoundException | IllegalArgumentException e) { @@ -2503,17 +2137,6 @@ public boolean updateAssignmentGradeComment(final long assignmentId, final Strin return false; } - /** - * Get the role of the current user in the current site - * - * @return GbRole - * @throws GbAccessDeniedException if something goes wrong checking the site or user permissions - */ - public GbRole getUserRole() throws GbAccessDeniedException { - final String siteId = getCurrentSiteId(); - return this.getUserRole(siteId); - } - /** * Get the role of the current user in the given site * @@ -2550,11 +2173,12 @@ public GbRole getUserRole(final String siteId) throws GbAccessDeniedException { /** * Get the role of the current user in the given site or GbRole.NONE if the user does not have access * + * @param siteId the siteId to check * @return GbRole for the current user */ - public GbRole getUserRoleOrNone() { + public GbRole getUserRoleOrNone(String siteId) { try { - return getUserRole(); + return getUserRole(siteId); } catch (GbAccessDeniedException e) { return GbRole.NONE; } @@ -2563,16 +2187,17 @@ public GbRole getUserRoleOrNone() { /** * Get a map of grades for the given student. Safe to call when logged in as a student. * + * @param gradebookUid + * @param siteId * @param studentUuid * @return map of assignment to GbGradeInfo */ - public Map getGradesForStudent(final String studentUuid) { + public Map getGradesForStudent(final String gradebookUid, final String siteId, final String studentUuid) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); // will apply permissions and only return those the student can view - final List assignments = getGradebookAssignmentsForStudent(studentUuid); + final List assignments = getGradebookAssignmentsForStudent(gradebookUid, siteId, studentUuid, SortType.SORT_BY_SORTING); final Map rval = new LinkedHashMap<>(); @@ -2597,7 +2222,7 @@ public Map getGradesForStudent(final String studentUuid) { } for (final Assignment assignment : assignments) { - final GradeDefinition def = this.gradingService.getGradeDefinitionForStudentForItem(gradebook.getUid(), + final GradeDefinition def = this.gradingService.getGradeDefinitionForStudentForItem(gradebookUid, siteId, assignment.getId(), studentUuid); rval.put(assignment.getId(), new GbGradeInfo(def)); } @@ -2605,21 +2230,23 @@ public Map getGradesForStudent(final String studentUuid) { return rval; } - public GradeDefinition getGradeForStudentForItem(String studentId, Long assignmentId) { - return this.gradingService.getGradeDefinitionForStudentForItem(getCurrentSiteId(), assignmentId, studentId); + public GradeDefinition getGradeForStudentForItem(String gradebookUid, String siteId, String studentId, Long assignmentId) { + return this.gradingService.getGradeDefinitionForStudentForItem(gradebookUid, siteId, assignmentId, studentId); } /** * Get the category score for the given student. * + * @param gradebookUid + * @param siteId * @param categoryId id of category * @param studentUuid uuid of student * @param isInstructor will calculate the category score with non-released items for instructors but not for students * @return */ - public Optional getCategoryScoreForStudent(final Long categoryId, final String studentUuid, final boolean isInstructor) { + public Optional getCategoryScoreForStudent(final String gradebookUid, final String siteId, final Long categoryId, final String studentUuid, final boolean isInstructor) { - final Gradebook gradebook = getGradebook(); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); final Optional result = gradingService.calculateCategoryScore(gradebook.getId(), studentUuid, categoryId, isInstructor, gradebook.getCategoryType(), null); log.debug("Category score for category: {}, student: {}:{}", categoryId, studentUuid, result.map(r -> r.score).orElse(null)); @@ -2627,28 +2254,19 @@ public Optional getCategoryScoreForStudent(final Long categor return result; } - /** - * Get the settings for this gradebook. Note that this CANNOT be called by an - * entityprovider - * - * @return - */ - public GradebookInformation getGradebookSettings() { - return getGradebookSettings(getCurrentSiteId()); - } - /** * Get the settings for this gradebook. Safe to use from an entityprovider. * + * @param gradebookUid + * @param siteId * @return */ - public GradebookInformation getGradebookSettings(final String siteId) { - final Gradebook gradebook = getGradebook(siteId); + public GradebookInformation getGradebookSettings(final String gradebookUid, final String siteId) { SecurityAdvisor advisor = null; try { advisor = addSecurityAdvisor(); - final GradebookInformation settings = this.gradingService.getGradebookInformation(gradebook.getUid()); + final GradebookInformation settings = this.gradingService.getGradebookInformation(gradebookUid, siteId); Collections.sort(settings.getCategories(), CategoryDefinition.orderComparator); return settings; } finally { @@ -2660,14 +2278,15 @@ public GradebookInformation getGradebookSettings(final String siteId) { * Update the settings for this gradebook. Note that this CANNOT be called by a * student. * + * @param gradebookUid + * @param siteId * @param settings GradebookInformation settings */ - public void updateGradebookSettings(final GradebookInformation settings) { + public void updateGradebookSettings(final String gradebookUid, final String siteId, final GradebookInformation settings) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); - this.gradingService.updateGradebookSettings(gradebook.getUid(), settings); + this.gradingService.updateGradebookSettings(gradebookUid, siteId, settings); EventHelper.postUpdateSettingsEvent(gradebook); } @@ -2675,31 +2294,38 @@ public void updateGradebookSettings(final GradebookInformation settings) { /** * Remove an assignment from its gradebook * + * @param gradebookUid + * @param siteId * @param assignmentId the id of the assignment to remove */ - public void removeAssignment(final Long assignmentId) { + public void removeAssignment(final String gradebookUid, final String siteId, final Long assignmentId) { // Delete task - String reference = GradingConstants.REFERENCE_ROOT + Entity.SEPARATOR + "a" + Entity.SEPARATOR + getCurrentSiteId() + Entity.SEPARATOR + assignmentId; + String reference = GradingConstants.REFERENCE_ROOT + Entity.SEPARATOR + "a" + Entity.SEPARATOR + siteId + Entity.SEPARATOR + assignmentId; taskService.removeTaskByReference(reference); rubricsService.deleteRubricAssociationsByItemIdPrefix(assignmentId.toString(), RubricsConstants.RBCS_TOOL_GRADEBOOKNG); this.gradingService.removeAssignment(assignmentId); - EventHelper.postDeleteAssignmentEvent(getGradebook(), assignmentId, getUserRoleOrNone()); + EventHelper.postDeleteAssignmentEvent(getGradebook(gradebookUid, siteId), assignmentId, getUserRoleOrNone(siteId)); } /** * Get a list of teaching assistants in the current site * + * @param gradebookUid + * @param siteId * @return */ - public List getTeachingAssistants() { + public List getTeachingAssistants(String gradebookUid, String siteId) { - final String siteId = getCurrentSiteId(); final List rval = new ArrayList<>(); try { - final Set userUuids = this.siteService.getSite(siteId).getUsersIsAllowed(GbRole.TA.getValue()); + Set userUuids = this.siteService.getSite(siteId).getUsersIsAllowed(GbRole.TA.getValue()); + if (!siteId.equals(gradebookUid)) { + Group group = siteService.findGroup(gradebookUid); + userUuids = group.getUsersIsAllowed(GbRole.TA.getValue()); + } for (final String userUuid : userUuids) { GbUser user = getUser(userUuid); if (user != null) { @@ -2713,37 +2339,8 @@ public List getTeachingAssistants() { return rval; } - /** - * Get a list of permissions defined for the given user. Note: These are currently only defined/used for a teaching assistant. - * - * @param userUuid - * @return list of permissions or empty list if none - */ - public List getPermissionsForUser(final String userUuid) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); - - List permissions = this.gradingPermissionService - .getPermissionsForUser(gradebook.getUid(), userUuid); - - //if db permissions are null, check realms permissions. - if (permissions == null || permissions.isEmpty()) { - //This method should return empty arraylist if they have no realms perms - permissions = this.gradingPermissionService.getRealmsPermissionsForUser(userUuid, siteId, Role.TA); - } - return permissions; - } - - private List getPermissionsForUser(final String userUuid, String siteId) { - - if(siteId==null) { - siteId = getCurrentSiteId(); - } - - final Gradebook gradebook = getGradebook(siteId); - - List permissions = this.gradingPermissionService - .getPermissionsForUser(gradebook.getUid(), userUuid); + public List getPermissionsForUser(final String userUuid, String gradebookUid, String siteId) { + List permissions = this.gradingPermissionService.getPermissionsForUser(gradebookUid, userUuid); //if db permissions are null, check realms permissions. if (permissions == null || permissions.isEmpty()) { @@ -2756,25 +2353,22 @@ private List getPermissionsForUser(final String userUuid, /** * Update the permissions for the user. Note: These are currently only defined/used for a teaching assistant. * + * @param gradebookUid * @param userUuid * @param permissions */ - public void updatePermissionsForUser(final String userUuid, final List permissions) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); - - this.gradingPermissionService.updatePermissionsForUser(gradebook.getUid(), userUuid, permissions); + public void updatePermissionsForUser(final String gradebookUid, final String userUuid, final List permissions) { + this.gradingPermissionService.updatePermissionsForUser(gradebookUid, userUuid, permissions); } /** * Remove all permissions for the user. Note: These are currently only defined/used for users with the Teaching Assistant role. * + * @param gradebookUid * @param userUuid */ - public void clearPermissionsForUser(final String userUuid) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); - this.gradingPermissionService.clearPermissionsForUser(gradebook.getUid(), userUuid); + public void clearPermissionsForUser(final String gradebookUid, final String userUuid) { + this.gradingPermissionService.clearPermissionsForUser(gradebookUid, userUuid); } /** @@ -2785,12 +2379,12 @@ public void clearPermissionsForUser(final String userUuid) { * method checks if the TA has any permissions assigned for the site, and if one of them is the course grade permission, then they have * access. * + * @param gradebookUid + * @param siteId * @param userUuid user to check * @return boolean */ - public boolean isCourseGradeVisible(final String userUuid) { - - final String siteId = getCurrentSiteId(); + public boolean isCourseGradeVisible(final String gradebookUid, final String siteId, final String userUuid) { GbRole role; try { @@ -2809,7 +2403,7 @@ public boolean isCourseGradeVisible(final String userUuid) { if (role == GbRole.TA) { // if no defs, implicitly allowed - final List defs = getPermissionsForUser(userUuid); + final List defs = getPermissionsForUser(userUuid, gradebookUid, siteId); if (defs.isEmpty()) { return true; } @@ -2826,7 +2420,7 @@ public boolean isCourseGradeVisible(final String userUuid) { // if student, check the settings // this could actually get the settings but it would be more processing if (role == GbRole.STUDENT) { - final Gradebook gradebook = this.getGradebook(siteId); + final Gradebook gradebook = this.getGradebook(gradebookUid, siteId); if (gradebook.getCourseGradeDisplayed()) { return true; @@ -2841,18 +2435,19 @@ public boolean isCourseGradeVisible(final String userUuid) { /** * Are student numbers visible to the current user in the current site? * + * @param siteId * @return true if student numbers are visible */ - public boolean isStudentNumberVisible() + public boolean isStudentNumberVisible(final String siteId) { if (getCandidateDetailProvider() == null) { return false; } final User user = getCurrentUser(); - final Optional site = getCurrentSite(); + final Optional site = getSite(siteId); return user != null && site.isPresent() && getCandidateDetailProvider().isInstitutionalNumericIdEnabled(site.get()) - && this.gradingService.currentUserHasViewStudentNumbersPerm(getGradebook().getUid()); + && this.gradingService.currentUserHasViewStudentNumbersPerm(siteId); } public String getStudentNumber(final User u, final Site site) @@ -2868,9 +2463,9 @@ public String getStudentNumber(final User u, final Site site) /** * Are there any sections in the current site? */ - public boolean isSectionsVisible() { + public boolean isSectionsVisible(String siteId) { - final Optional site = getCurrentSite(); + final Optional site = getSite(siteId); return site.isPresent() && !sectionManager.getSections(site.get().getId()).isEmpty(); } @@ -2879,9 +2474,7 @@ public boolean isSectionsVisible() { * * @return */ - public Map> getGroupMemberships() { - - final String siteId = getCurrentSiteId(); + public Map> getGroupMemberships(final String gradebookUid, final String siteId) { Site site; try { @@ -2892,7 +2485,7 @@ public Map> getGroupMemberships() { } // filtered for the user - final List viewableGroups = getSiteSectionsAndGroups(); + final List viewableGroups = getSiteSectionsAndGroups(gradebookUid, siteId); final Map> rval = new HashMap<>(); @@ -2916,46 +2509,13 @@ public Map> getGroupMemberships() { return rval; } - /** - * Build a list of group references to site membership (as Member) for the groups that are viewable for the current user. - * - * @return - */ - private Map> getGroupMembers(final String siteId) { - - Site site; - try { - site = this.siteService.getSite(siteId); - } catch (final IdUnusedException e) { - log.error("Error looking up site: {}", siteId, e); - return null; - } - - // filtered for the user - final List viewableGroups = getSiteSectionsAndGroups(siteId); - - final Map> rval = new HashMap<>(); - - - for (final GbGroup gbGroup : viewableGroups) { - final String groupReference = gbGroup.getReference(); - final Group group = site.getGroup(groupReference); - if (group != null) { - rval.put(groupReference, group.getMembers()); - } - } - - return rval; - } - /** * Have categories been enabled for the gradebook? * * @return if the gradebook is setup for either "Categories Only" or "Categories & Weighting" */ - public boolean categoriesAreEnabled() { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); + public boolean categoriesAreEnabled(String gradebookUid, String siteId) { + final Gradebook gradebook = getGradebook(gradebookUid, siteId); return Objects.equals(GradingConstants.CATEGORY_TYPE_ONLY_CATEGORY, gradebook.getCategoryType()) || Objects.equals(GradingConstants.CATEGORY_TYPE_WEIGHTED_CATEGORY, gradebook.getCategoryType()); @@ -2964,29 +2524,28 @@ public boolean categoriesAreEnabled() { /** * Get the currently configured gradebook category type * - * @return GradingCategoryType wrapper around the int value + * @return GradingCategoryType int value */ - public Integer getGradebookCategoryType() { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); - + public Integer getGradebookCategoryType(String gradebookUid, String siteId) { + final Gradebook gradebook = getGradebook(gradebookUid, siteId); return gradebook.getCategoryType(); } /** * Update the course grade (override) for this student * + * @param gradebookUid + * @param siteId * @param studentUuid uuid of the student * @param grade the new grade * @return */ - public boolean updateCourseGrade(final String studentUuid, final String grade, final String gradeScale) { + public boolean updateCourseGrade(final String gradebookUid, final String siteId, final String studentUuid, final String grade, final String gradeScale) { - final String siteId = getCurrentSiteId(); - final Gradebook gradebook = getGradebook(siteId); + final Gradebook gradebook = getGradebook(gradebookUid, siteId); try { - gradingService.updateCourseGradeForStudent(gradebook.getUid(), studentUuid, grade, gradeScale); + gradingService.updateCourseGradeForStudent(gradebookUid, siteId, studentUuid, grade, gradeScale); EventHelper.postOverrideCourseGradeEvent(gradebook, studentUuid, grade, grade != null); return true; } catch (final Exception e) { @@ -3006,60 +2565,6 @@ public Locale getUserPreferredLocale() { return rl.getLocale(); } - /** - * Get the user's custom GbUiSettings from PreferencesService - * - * @return String - */ - public String getUserGbPreference(final String prefName) { - final String siteId = getCurrentSiteId(); - final String currentUserId = getCurrentUser().getId(); - Preferences userPrefs = preferencesService.getPreferences(currentUserId); - ResourceProperties rp = userPrefs.getProperties(GB_PREF_KEY + siteId); - return rp.getProperty(prefName); - } - - /** - * Set the user's custom GbUiSettings in PreferencesService - * - * @return - */ - public void setUserGbPreference(final String prefName, final String prefValue) { - if (StringUtils.isBlank(prefName)) return; - - String siteId = getCurrentSiteId(); - String userId = getCurrentUser().getId(); - - PreferencesEdit preference = null; - try { - try { - preference = preferencesService.edit(userId); - } catch (IdUnusedException iue) { - preference = preferencesService.add(userId); - } - } catch (Exception e) { - log.warn("Could not get the preferences for user [{}], {}", userId, e.toString()); - } - - if (preference != null) { - String key = GB_PREF_KEY + siteId; - try { - ResourcePropertiesEdit props = preference.getPropertiesEdit(key); - if (prefValue != null) { - props.addProperty(prefName, prefValue); - } else { - props.removeProperty(prefName); - } - } catch (Exception e) { - log.warn("Could not set the property [{}] for user [{}] in key [{}], {}", prefName, userId, siteId, e.toString()); - preferencesService.cancel(preference); - preference = null; - } finally { - if (preference != null) preferencesService.commit(preference); - } - } - } - /** * Helper to check if a user is roleswapped * @@ -3074,8 +2579,8 @@ public boolean isUserRoleSwapped() { * * @return true if yes, false if no. */ - public boolean isUserAbleToEditAssessments(){ - return gradingService.currentUserHasEditPerm(getCurrentSiteId()); + public boolean isUserAbleToEditAssessments(String siteId) { + return gradingService.currentUserHasEditPerm(siteId); } /** @@ -3155,17 +2660,19 @@ private String getAttendanceIconClass() { /** * Gets a list of assignment averages for a category. + * @param gradebookUid + * @param siteId * @param category category - * @param group group of students + * @param group group of students - apparently never used so far * @return allAssignmentGrades list of assignment averages for a specific group */ - public List getCategoryAssignmentTotals(CategoryDefinition category, GbGroup group){ + public List getCategoryAssignmentTotals(String gradebookUid, String siteId, CategoryDefinition category, String group){ final List allAssignmentGrades = new ArrayList<>(); - final List groupUsers = getGradeableUsers(group); + final List groupUsers = getGradeableUsers(gradebookUid, siteId, group); final List studentUUIDs = new ArrayList<>(); studentUUIDs.addAll(groupUsers); final List assignments = category.getAssignmentList(); - final List grades = buildGradeMatrix(assignments, studentUUIDs); + final List grades = buildGradeMatrix(gradebookUid, siteId, assignments, studentUUIDs, null); for (final Assignment assignment : assignments) { if (assignment != null) { final List allGrades = new ArrayList<>(); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/LetterGradeComparator.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/LetterGradeComparator.java deleted file mode 100644 index 3e5d547e234b..000000000000 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/LetterGradeComparator.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2003-2017 The Apereo Foundation - * - * Licensed under the Educational Community License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://opensource.org/licenses/ecl2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sakaiproject.gradebookng.business; - -import java.io.Serializable; -import java.util.Comparator; - -import org.apache.commons.lang3.StringUtils; - -/** - * Comparator to ensure correct ordering of letter grades, catering for + and - in the grade Copied from GradingService and made - * Serializable as we use it in a TreeMap. Also has the fix from SAK-30094. If this changes, be sure to update the other. - */ -public class LetterGradeComparator implements Comparator, Serializable { - - private static final long serialVersionUID = 1L; - - @Override - public int compare(final String o1, final String o2) { - if (o1.toLowerCase().charAt(0) == o2.toLowerCase().charAt(0)) { - // only take the first 2 chars, to cater for GradePointsMapping as well - final String s1 = StringUtils.trim(StringUtils.left(o1, 2)); - final String s2 = StringUtils.trim(StringUtils.left(o2, 2)); - - if (s1.length() == 2 && s2.length() == 2) { - if (s1.charAt(1) == '+') { - return -1; // SAK-30094 - } else { - return 1; - } - } - if (s1.length() == 1 && s2.length() == 2) { - if (o2.charAt(1) == '+') { - return 1; // SAK-30094 - } else { - return -1; - } - } - if (s1.length() == 2 && s2.length() == 1) { - if (s1.charAt(1) == '+') { - return -1; // SAK-30094 - } else { - return 1; - } - } - return 0; - } else { - return o1.toLowerCase().compareTo(o2.toLowerCase()); - } - } -} diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/model/GbGroup.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/model/GbGroup.java index 1667e459fbd7..b6bb8cb0b240 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/model/GbGroup.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/model/GbGroup.java @@ -48,7 +48,6 @@ public class GbGroup implements Comparable, Serializable { * Type of group */ public enum Type { - SECTION, GROUP, ALL; } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/CourseGradeFormatter.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/CourseGradeFormatter.java index 207a6c5fefa2..36c2c05a7773 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/CourseGradeFormatter.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/CourseGradeFormatter.java @@ -25,7 +25,9 @@ import org.sakaiproject.gradebookng.business.GbRole; import org.sakaiproject.grading.api.CourseGradeTransferBean; import org.sakaiproject.grading.api.GradingConstants; +import org.sakaiproject.grading.api.MessageHelper; import org.sakaiproject.grading.api.model.Gradebook; +import org.sakaiproject.util.ResourceLoader; /** * Helper class to handle the formatting of the course grade display string @@ -41,6 +43,9 @@ public class CourseGradeFormatter { private final boolean showOverride; private final boolean showCalculatedGrade; + @SuppressWarnings("unchecked") + private static ResourceLoader RL = new ResourceLoader(); + /** * Constructor to initialise the data * @@ -80,14 +85,14 @@ public String format(final CourseGradeTransferBean courseGrade) { // something has gone wrong and there's no course grade! if (courseGrade == null) { - rval = MessageHelper.getString("coursegrade.display.none"); + rval = MessageHelper.getString("coursegrade.display.none", RL.getLocale()); // instructor, can view } else if (this.currentUserRole == GbRole.INSTRUCTOR) { rval = build(courseGrade); // TA, permission check } else if (this.currentUserRole == GbRole.TA) { if (!this.isCourseGradeVisible) { - rval = MessageHelper.getString("label.coursegrade.nopermission"); + rval = MessageHelper.getString("label.coursegrade.nopermission", RL.getLocale()); } else { rval = build(courseGrade); } @@ -95,12 +100,12 @@ public String format(final CourseGradeTransferBean courseGrade) { } else { if (this.gradebook.getCourseGradeDisplayed()) { if (!this.isCourseGradeVisible) { - rval = MessageHelper.getString("label.coursegrade.nopermission"); + rval = MessageHelper.getString("label.coursegrade.nopermission", RL.getLocale()); } else { rval = build(courseGrade); } } else { - rval = MessageHelper.getString("label.coursegrade.studentnotreleased"); + rval = MessageHelper.getString("label.coursegrade.studentnotreleased", RL.getLocale()); } } @@ -170,10 +175,10 @@ private String build(final CourseGradeTransferBean courseGrade) { final String pointsEarnedDisplayString = FormatHelper.formatGradeForDisplay(pointsEarned); final String totalPointsPossibleDisplayString = FormatHelper.formatGradeForDisplay(totalPointsPossible); if (parts.isEmpty()) { - parts.add(MessageHelper.getString("coursegrade.display.points-first", pointsEarnedDisplayString, + parts.add(MessageHelper.getString("coursegrade.display.points-first", RL.getLocale(), pointsEarnedDisplayString, totalPointsPossibleDisplayString)); } else { - parts.add(MessageHelper.getString("coursegrade.display.points-second", pointsEarnedDisplayString, + parts.add(MessageHelper.getString("coursegrade.display.points-second", RL.getLocale(), pointsEarnedDisplayString, totalPointsPossibleDisplayString)); } } @@ -183,7 +188,7 @@ private String build(final CourseGradeTransferBean courseGrade) { // if parts is empty, there are no grades, display a - if (parts.isEmpty()) { - parts.add(MessageHelper.getString("coursegrade.display.none")); + parts.add(MessageHelper.getString("coursegrade.display.none", RL.getLocale())); } return String.join(" ", parts); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/FormatHelper.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/FormatHelper.java index 7d4f5cbf03b6..c1309e151b3d 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/FormatHelper.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/FormatHelper.java @@ -41,6 +41,7 @@ import lombok.extern.slf4j.Slf4j; import org.sakaiproject.grading.api.CategoryDefinition; +import org.sakaiproject.grading.api.MessageHelper; @Slf4j public class FormatHelper { @@ -252,7 +253,7 @@ public static String formatGradeForLocale(final String grade, final Locale local * @return */ private static String formatDate(final Date date) { - final String dateFormatString = MessageHelper.getString("format.date"); + final String dateFormatString = MessageHelper.getString("format.date", RL.getLocale()); final SimpleDateFormat df = new SimpleDateFormat(dateFormatString); return df.format(date); } @@ -360,13 +361,13 @@ public static List formatCategoryDropInfo(CategoryDefinition category) { List info = new ArrayList<>(2); if (dropHighest > 0) { - info.add(MessageHelper.getString("label.category.drophighest", dropHighest)); + info.add(MessageHelper.getString("label.category.drophighest", RL.getLocale(), dropHighest)); } if (dropLowest > 0) { - info.add(MessageHelper.getString("label.category.droplowest", dropLowest)); + info.add(MessageHelper.getString("label.category.droplowest", RL.getLocale(), dropLowest)); } if (keepHighest > 0) { - info.add(MessageHelper.getString("label.category.keephighest", keepHighest)); + info.add(MessageHelper.getString("label.category.keephighest", RL.getLocale(), keepHighest)); } return info; diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/ImportGradesHelper.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/ImportGradesHelper.java index 4b4db891058f..0ccec496046a 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/ImportGradesHelper.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/business/util/ImportGradesHelper.java @@ -67,6 +67,8 @@ import org.sakaiproject.gradebookng.tool.model.ImportWizardModel; import org.sakaiproject.gradebookng.tool.pages.ImportExportPage; import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.MessageHelper; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.util.ResourceLoader; @@ -106,23 +108,6 @@ public class ImportGradesHelper { private static ResourceLoader RL = new ResourceLoader(); - /** - * Helper to parse the imported file into an {@link ImportedSpreadsheetWrapper} depending on its type - * - * @param is - * @param mimetype - * @param filename - * @param businessService - * @return - * @throws GbImportExportInvalidFileTypeException - * @throws IOException - * @throws InvalidFormatException - */ - public static ImportedSpreadsheetWrapper parseImportedGradeFile(final InputStream is, final String mimetype, final String filename, - final GradebookNgBusinessService businessService) throws GbImportExportInvalidFileTypeException, IOException, InvalidFormatException { - return parseImportedGradeFile(is, mimetype, filename, businessService, ""); - } - /** * Helper to parse the imported file into an {@link ImportedSpreadsheetWrapper} depending on its type * @@ -137,15 +122,17 @@ public static ImportedSpreadsheetWrapper parseImportedGradeFile(final InputStrea * @throws InvalidFormatException */ public static ImportedSpreadsheetWrapper parseImportedGradeFile(final InputStream is, final String mimetype, final String filename, - final GradebookNgBusinessService businessService, String userDecimalSeparator) throws GbImportExportInvalidFileTypeException, IOException, InvalidFormatException { + final GradebookNgBusinessService businessService, String userDecimalSeparator, final String gUid, final String siteId) throws GbImportExportInvalidFileTypeException, IOException, InvalidFormatException { ImportedSpreadsheetWrapper rval = null; + Map userEidMap = businessService.getUserEidMap(businessService.getGbUsers(siteId, businessService.getGradeableUsers(gUid, siteId, null))); + // It would be great if we could depend on the browser mimetype, but Windows + Excel will always send an Excel mimetype if (StringUtils.endsWithAny(filename, CSV_FILE_EXTS) || ArrayUtils.contains(CSV_MIME_TYPES, mimetype)) { - rval = ImportGradesHelper.parseCsv(is, businessService, userDecimalSeparator); + rval = ImportGradesHelper.parseCsv(is, userEidMap, userDecimalSeparator); } else if (StringUtils.endsWithAny(filename, XLS_FILE_EXTS) || ArrayUtils.contains(XLS_MIME_TYPES, mimetype)) { - rval = ImportGradesHelper.parseXls(is, businessService, userDecimalSeparator); + rval = ImportGradesHelper.parseXls(is, userEidMap, userDecimalSeparator); } else { throw new GbImportExportInvalidFileTypeException("Invalid file type for grade import: " + mimetype); } @@ -161,7 +148,7 @@ public static ImportedSpreadsheetWrapper parseImportedGradeFile(final InputStrea * @throws GbImportExportInvalidColumnException * @throws GbImportExportDuplicateColumnException */ - private static ImportedSpreadsheetWrapper parseCsv(final InputStream is, final GradebookNgBusinessService businessService, String userDecimalSeparator) + private static ImportedSpreadsheetWrapper parseCsv(final InputStream is, Map userEidMap, String userDecimalSeparator) throws IOException { // manually parse method so we can support arbitrary columns @@ -182,7 +169,6 @@ private static ImportedSpreadsheetWrapper parseCsv(final InputStream is, final G int lineCount = 0; final List list = new ArrayList<>(); Map mapping = new LinkedHashMap<>(); - Map userEidMap = businessService.getUserEidMap(); final ImportedSpreadsheetWrapper importedGradeWrapper = new ImportedSpreadsheetWrapper(); try { @@ -227,13 +213,12 @@ private static ImportedSpreadsheetWrapper parseCsv(final InputStream is, final G * @throws GbImportExportInvalidColumnException * @Throws GbImportExportDuplicateColumnException */ - private static ImportedSpreadsheetWrapper parseXls(final InputStream is, final GradebookNgBusinessService businessService, String userDecimalSeparator) + private static ImportedSpreadsheetWrapper parseXls(final InputStream is, final Map userEidMap, String userDecimalSeparator) throws InvalidFormatException, IOException { int lineCount = 0; final List list = new ArrayList<>(); Map mapping = new LinkedHashMap<>(); - Map userEidMap = businessService.getUserEidMap(); final ImportedSpreadsheetWrapper importedGradeWrapper = new ImportedSpreadsheetWrapper(); final Workbook wb = WorkbookFactory.create(is); @@ -353,10 +338,10 @@ private static ImportedRow mapLine(final String[] line, final Map duplicateHeadings = headingReport.getDuplicateHeadings(); if (!duplicateHeadings.isEmpty()) { String duplicates = StringUtils.join(duplicateHeadings, ", "); - sourcePanel.error(MessageHelper.getString("importExport.error.duplicateColumns", duplicates)); + sourcePanel.error(MessageHelper.getString("importExport.error.duplicateColumns", RL.getLocale(), duplicates)); hasValidationErrors = true; } @@ -385,14 +370,14 @@ public static boolean setupImportWizardModelForSelectionStep(ImportExportPage so SortedSet invalidHeadings = headingReport.getInvalidHeadings(); if (!invalidHeadings.isEmpty()) { String invalids = StringUtils.join(invalidHeadings, ", "); - sourcePanel.error(MessageHelper.getString("importExport.error.invalidColumns", invalids)); + sourcePanel.error(MessageHelper.getString("importExport.error.invalidColumns", RL.getLocale(), invalids)); hasValidationErrors = true; } // If there are blank headings, tell the user now int blankHeadings = headingReport.getBlankHeaderTitleCount(); if (blankHeadings > 0) { - sourcePanel.error(MessageHelper.getString("importExport.error.blankHeadings", blankHeadings)); + sourcePanel.error(MessageHelper.getString("importExport.error.blankHeadings", RL.getLocale(), blankHeadings)); hasValidationErrors = true; } @@ -401,7 +386,7 @@ public static boolean setupImportWizardModelForSelectionStep(ImportExportPage so SortedSet duplicateStudents = userReport.getDuplicateUsers(); if (!duplicateStudents.isEmpty()) { String duplicates = StringUtils.join(duplicateStudents, ", "); - sourcePanel.error(MessageHelper.getString("importExport.error.duplicateStudents", duplicates)); + sourcePanel.error(MessageHelper.getString("importExport.error.duplicateStudents", RL.getLocale(), duplicates)); hasValidationErrors = true; } @@ -419,7 +404,7 @@ public static boolean setupImportWizardModelForSelectionStep(ImportExportPage so } String badGrades = StringUtils.join(badGradeEntries, ", "); - sourcePanel.error(MessageHelper.getString("importExport.error.invalidGradeData", MessageHelper.getString("grade.notifications.invalid"), badGrades)); + sourcePanel.error(MessageHelper.getString("importExport.error.invalidGradeData", RL.getLocale(), MessageHelper.getString("grade.notifications.invalid", RL.getLocale()), badGrades)); hasValidationErrors = true; } @@ -435,13 +420,13 @@ public static boolean setupImportWizardModelForSelectionStep(ImportExportPage so } String badComments = StringUtils.join(badCommentEntries, ", "); - sourcePanel.error(MessageHelper.getString("importExport.error.invalidComments", CommentValidator.getMaxCommentLength(businessService.getServerConfigService()), badComments)); + sourcePanel.error(MessageHelper.getString("importExport.error.invalidComments", RL.getLocale(), CommentValidator.getMaxCommentLength(businessService.getServerConfigService()), badComments)); hasValidationErrors = true; } // get existing data - final List assignments = businessService.getGradebookAssignments(); - final List grades = businessService.buildGradeMatrixForImportExport(assignments, null); + final List assignments = businessService.getGradebookAssignments(gradebookUid, siteId, SortType.SORT_BY_SORTING); + final List grades = businessService.buildGradeMatrixForImportExport(gradebookUid, siteId, assignments, null); // process file List processedGradeItems = processImportedGrades(spreadsheetWrapper, assignments, grades); @@ -450,24 +435,24 @@ public static boolean setupImportWizardModelForSelectionStep(ImportExportPage so SortedSet orphanedCommentColumns = headingReport.getOrphanedCommentHeadings(); if (!orphanedCommentColumns.isEmpty()) { String invalids = StringUtils.join(orphanedCommentColumns, ", "); - sourcePanel.error(MessageHelper.getString("importExport.error.orphanedComments", invalids)); + sourcePanel.error(MessageHelper.getString("importExport.error.orphanedComments", RL.getLocale(), invalids)); hasValidationErrors = true; } // if the file has no valid users, tell the user now if (userReport.getIdentifiedUsers().isEmpty()) { hasValidationErrors = true; - sourcePanel.error(MessageHelper.getString("importExport.error.noValidStudents")); + sourcePanel.error(MessageHelper.getString("importExport.error.noValidStudents", RL.getLocale())); } // if empty there are no grade columns, tell the user now if (processedGradeItems.isEmpty() && !userReport.getIdentifiedUsers().isEmpty()) { hasValidationErrors = true; - sourcePanel.error(MessageHelper.getString("importExport.error.noValidGrades")); + sourcePanel.error(MessageHelper.getString("importExport.error.noValidGrades", RL.getLocale())); } // if assignment is in a category that uses keep / drop, check if all assignments points in that category are equal - final List categories = businessService.getGradebookCategories(); + final List categories = businessService.getGradebookCategories(gradebookUid, siteId); for (CategoryDefinition category : categories) { List catAssignmentList = category.getAssignmentList(); if (category.getDropKeepEnabled() && catAssignmentList != null) { @@ -479,7 +464,7 @@ public static boolean setupImportWizardModelForSelectionStep(ImportExportPage so matchedPoints = Double.parseDouble(processedGradeItem.getItemPointValue()); } else if (!matchedPoints.equals(Double.parseDouble(processedGradeItem.getItemPointValue()))) { hasValidationErrors = true; - sourcePanel.error(MessageHelper.getString("importExport.error.dropKeepPointsMismatch")); + sourcePanel.error(MessageHelper.getString("importExport.error.dropKeepPointsMismatch", RL.getLocale())); } break; } @@ -505,7 +490,7 @@ public static boolean setupImportWizardModelForSelectionStep(ImportExportPage so if ((!hasChanges && !processedGradeItems.isEmpty()) && !userReport.getIdentifiedUsers().isEmpty()) { hasValidationErrors = true; - sourcePanel.error(MessageHelper.getString("importExport.error.noChanges")); + sourcePanel.error(MessageHelper.getString("importExport.error.noChanges", RL.getLocale())); } // Return errors before processing further diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/framework/GradebookNgEntityProducer.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/framework/GradebookNgEntityProducer.java index 9adcff0ccd05..c1cd1b955523 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/framework/GradebookNgEntityProducer.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/framework/GradebookNgEntityProducer.java @@ -15,16 +15,20 @@ */ package org.sakaiproject.gradebookng.framework; +import java.util.ArrayList; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.Stack; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.sakaiproject.entity.api.Entity; @@ -42,7 +46,9 @@ import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.GradebookInformation; import org.sakaiproject.grading.api.GradeMappingDefinition; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; +import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.api.ToolConfiguration; @@ -57,6 +63,7 @@ * Entity Producer for GradebookNG. This is required to participate in other entity actions but also handles the transfer of data between * sites */ +@Slf4j public class GradebookNgEntityProducer implements EntityProducer, EntityTransferrer { protected static final String[] TOOL_IDS = { "sakai.gradebookng" }; @@ -129,12 +136,12 @@ public String archive(final String siteId, final Document doc, final Stack Element gradebookConfigEl = doc.createElement("GradebookConfig"); - Gradebook gradebook = this.gradingService.getGradebook(siteId); + Gradebook gradebook = this.gradingService.getGradebook(siteId, siteId); if (gradebook == null) { return "ERROR: Gradebook not found in site\n"; } - GradebookInformation settings = this.gradingService.getGradebookInformation(gradebook.getUid()); + GradebookInformation settings = this.gradingService.getGradebookInformation(gradebook.getUid(), siteId); List gradeMappings = settings.getGradeMappings(); String configuredGradeMappingId = settings.getSelectedGradeMappingId(); GradeMappingDefinition configuredGradeMapping = gradeMappings.stream() @@ -226,7 +233,7 @@ public String archive(final String siteId, final Document doc, final Stack - List gradebookItems = this.businessService.getGradebookAssignments(siteId); + List gradebookItems = this.businessService.getGradebookAssignments(siteId, siteId, SortType.SORT_BY_NONE); gradebookItems = gradebookItems.stream().filter(item -> { return !item.getExternallyMaintained(); @@ -315,38 +322,135 @@ public String[] myToolIds() { @Override public List> getEntityMap(String fromContext) { - return this.gradingService.getAssignments(fromContext).stream() + List> entityList = new ArrayList<>(); + if (gradingService.isGradebookGroupEnabled(fromContext)){ + List gradebooks = gradingService.getGradebookGroupInstances(fromContext); + + for (Gradebook gradebook: gradebooks){ + String gradebookUid = gradebook.getUid(); + + List assignments = this.gradingService.getAssignments(gradebookUid, fromContext, SortType.SORT_BY_NONE); + + assignments.stream() + .map(ass -> Map.of("id", ass.getId().toString(), "title", ass.getName())) + .forEach(entityList::add); + } + } else { + return this.gradingService.getAssignments(fromContext, fromContext, SortType.SORT_BY_NONE).stream() .map(ass -> Map.of("id", ass.getId().toString(), "title", ass.getName())).collect(Collectors.toList()); + } + return entityList; } @Override public Map transferCopyEntities(String fromContext, String toContext, List ids, List options) { - final Gradebook gradebook = (Gradebook) this.gradingService.getGradebook(fromContext); + Map resultGradebookTransfer = new HashMap<>(); + + final Gradebook gradebook = (Gradebook) this.gradingService.getGradebook(fromContext, fromContext); + + final GradebookInformation gradebookInformation = this.gradingService.getGradebookInformation(gradebook.getUid(), fromContext); + + final List assignments = this.gradingService.getAssignments(fromContext, fromContext, SortType.SORT_BY_NONE); + + if(gradingService.isGradebookGroupEnabled(fromContext)) { + try { + Site siteFrom = siteService.getSite(fromContext); + Collection groupListFrom = siteFrom.getGroups(); + + Site siteTo = siteService.getSite(toContext); + Collection groupListTo = siteTo.getGroups(); + + groupListFrom.forEach(groupFrom -> { + String groupNameFrom = groupFrom.getTitle(); + + Optional opGroup = groupListTo.stream() + .filter(groupTo -> groupTo.getTitle().equals(groupNameFrom)) + .findFirst(); + + Gradebook gradebookGroupFrom = gradingService.getGradebook(groupFrom.getId(), fromContext); + + if (opGroup.isPresent() && gradebookGroupFrom != null) { + Group groupTo = opGroup.get(); - final GradebookInformation gradebookInformation = this.gradingService.getGradebookInformation(gradebook.getUid()); + Gradebook gradebookGroupTo = gradingService.getGradebook(groupTo.getId(), toContext); - final List assignments = this.gradingService.getAssignments(fromContext); + if (gradebookGroupTo != null) { + GradebookInformation gradebookInfoFrom = gradingService.getGradebookInformation(gradebookGroupFrom.getUid(), fromContext); - return this.gradingService.transferGradebook(gradebookInformation, assignments, toContext, fromContext); + List assignmentsFrom = gradingService.getAssignments(gradebookGroupFrom.getUid(), fromContext, SortType.SORT_BY_NONE); + + assignmentsFrom.forEach(assignment -> { + String newAssigmentName = gradebookGroupFrom.getName() + "/" + groupNameFrom + "-" + assignment.getName(); + assignment.setName(newAssigmentName); + }); + Map transfer = gradingService.transferGradebook(gradebookInfoFrom, assignmentsFrom, gradebookGroupTo.getUid(), fromContext); + resultGradebookTransfer.putAll(transfer); + } + } + }); + } catch (IdUnusedException e) { + log.error("Error while trying to get gradebooks for site {} : {}", fromContext, e.getMessage()); + return new HashMap<>(); + } + } else { + Map transfer = this.gradingService.transferGradebook(gradebookInformation, assignments, toContext, fromContext); + resultGradebookTransfer.putAll(transfer); + } + return resultGradebookTransfer; } @Override public Map transferCopyEntities(String fromContext, String toContext, List ids, List options, boolean cleanup) { if (cleanup == true) { + if (!gradingService.isGradebookGroupEnabled(fromContext)) { + final Gradebook gradebook = (Gradebook) this.gradingService.getGradebook(toContext, toContext); - final Gradebook gradebook = (Gradebook) this.gradingService.getGradebook(toContext); + // remove assignments in 'to' site + final List assignments = this.gradingService.getAssignments(gradebook.getUid(), toContext, SortType.SORT_BY_NONE); + assignments.forEach(a -> this.gradingService.removeAssignment(a.getId())); - // remove assignments in 'to' site - final List assignments = this.gradingService.getAssignments(gradebook.getUid()); - assignments.forEach(a -> this.gradingService.removeAssignment(a.getId())); + // remove categories in 'to' site + final List categories = this.gradingService.getCategoryDefinitions(gradebook.getUid(), toContext); + categories.forEach(c -> this.gradingService.removeCategory(c.getId())); + } else { + try { + Site siteFrom = siteService.getSite(fromContext); + Collection groupListFrom = siteFrom.getGroups(); - // remove categories in 'to' site - final List categories = this.gradingService.getCategoryDefinitions(gradebook.getUid()); - categories.forEach(c -> this.gradingService.removeCategory(c.getId())); - } + Site siteTo = siteService.getSite(toContext); + Collection groupListTo = siteTo.getGroups(); + + groupListFrom.forEach(groupFrom -> { + String groupNameFrom = groupFrom.getTitle(); + + Optional opGroup = groupListTo.stream() + .filter(groupTo -> groupTo.getTitle().equals(groupNameFrom)) + .findFirst(); + Gradebook gradebookGroupFrom = gradingService.getGradebook(groupFrom.getId(), fromContext); + + if (opGroup.isPresent() && gradebookGroupFrom != null) { + Group groupTo = opGroup.get(); + + Gradebook gradebookGroupTo = gradingService.getGradebook(groupTo.getId(), toContext); + + if (gradebookGroupTo != null) { + List groupAssignmentsTo = gradingService.getAssignments(gradebookGroupTo.getUid(), toContext, SortType.SORT_BY_NONE); + groupAssignmentsTo.forEach(a -> this.gradingService.removeAssignment(a.getId())); + + List groupCategoriesTo = this.gradingService.getCategoryDefinitions(gradebookGroupTo.getUid(), toContext); + groupCategoriesTo.forEach(c -> this.gradingService.removeCategory(c.getId())); + } + } + }); + } catch (IdUnusedException e) { + log.error("Error while trying to get gradebooks for site {} : {}", fromContext, e.getMessage()); + return new HashMap<>(); + } + } + } // now migrate return this.transferCopyEntities(fromContext, toContext, ids, null); } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/rest/GradebookNgEntityProvider.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/rest/GradebookNgEntityProvider.java index 932bffa3eaed..b8b0315a913b 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/rest/GradebookNgEntityProvider.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/rest/GradebookNgEntityProvider.java @@ -137,6 +137,7 @@ public void updateAssignmentOrder(final EntityReference ref, final Map isAnotherUserEditing(final EntityView view, final Map isAnotherUserEditing(final EntityView view, final Map params) { // get params final String siteId = (String) params.get("siteId"); + final String gradebookUid = (String) params.get("gUid"); final long assignmentId = NumberUtils.toLong((String) params.get("assignmentId")); final String studentUuid = (String) params.get("studentUuid"); @@ -236,10 +240,10 @@ public String getComments(final EntityView view, final Map param "Request data was missing / invalid"); } - checkValidSite(siteId); + checkValidGradebook(siteId, gradebookUid); checkInstructorOrTA(siteId); - return formattedText.escapeHtml(businessService.getAssignmentGradeComment(siteId, assignmentId, studentUuid)); + return formattedText.escapeHtml(businessService.getAssignmentGradeComment(gradebookUid, assignmentId, studentUuid)); } @SuppressWarnings("unused") @@ -247,6 +251,7 @@ public String getComments(final EntityView view, final Map param public String getCourseGradeComment(final EntityView view, final Map params) { // get params final String siteId = (String) params.get("siteId"); + final String gradebookUid = (String) params.get("gUid"); final long courseGradeId = NumberUtils.toLong((String) params.get("courseGradeId")); final String studentUuid = (String) params.get("studentUuid"); final long gradebookId = NumberUtils.toLong((String) params.get("gradebookId")); @@ -254,14 +259,15 @@ public String getCourseGradeComment(final EntityView view, final Map getRecipients(Map params) { final String siteId = (String) params.get("siteId"); + final String gradebookUid = (String) params.get("gUid"); final long assignmentId = NumberUtils.toLong((String) params.get("assignmentId")); final String action = (String) params.get("action"); final String groupRef = (String) params.get("groupRef"); @@ -292,7 +298,7 @@ private Set getRecipients(Map params) { } List grades - = gradingService.getGradesForStudentsForItem(siteId, assignmentId, new ArrayList(recipients)); + = gradingService.getGradesForStudentsForItem(gradebookUid, siteId, assignmentId, new ArrayList(recipients)); if (MESSAGE_GRADED.equals(action)) { // We want to message graded students. Filter by min and max score, if needed. @@ -394,29 +400,6 @@ public ActionReturn messageStudents(final EntityView view, final Map averageData = businessService.getCategoryScoreForStudent(Long.valueOf(categoryId), studentId, true); + final Optional averageData = businessService.getCategoryScoreForStudent(currentGradebookUid, currentSiteId, Long.valueOf(categoryId), studentId, true); if (averageData.isPresent()) { double average = averageData.get().score; return FormatHelper.formatDoubleToDecimal(average); @@ -171,7 +171,7 @@ private String getCategoryScore(String categoryId, String studentId) { private List getDroppedItems(String categoryId, String studentId){ Optional catData = categoryId == null ? - Optional.empty() : businessService.getCategoryScoreForStudent(Long.valueOf(categoryId), studentId, true); + Optional.empty() : businessService.getCategoryScoreForStudent(currentGradebookUid, currentSiteId, Long.valueOf(categoryId), studentId, true); return catData.map(c -> c.droppedItems).orElse(Collections.emptyList()); } } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/GradeUpdateAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/GradeUpdateAction.java index c3e87c9787f3..4c010e2293bd 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/GradeUpdateAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/GradeUpdateAction.java @@ -153,10 +153,10 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget // We don't pass the comment from the use interface, // but the service needs it otherwise it will assume 'null' // so pull it back from the service and poke it in there! - final String comment = businessService.getAssignmentGradeComment(Long.valueOf(assignmentId), studentUuid); + final String comment = businessService.getAssignmentGradeComment(currentGradebookUid, Long.valueOf(assignmentId), studentUuid); // for concurrency, get the original grade we have in the UI and pass it into the service as a check - final GradeSaveResponse result = businessService.saveGrade(Long.valueOf(assignmentId), + final GradeSaveResponse result = businessService.saveGrade(currentGradebookUid, currentSiteId, Long.valueOf(assignmentId), studentUuid, oldGrade, newGrade, @@ -174,12 +174,12 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget return new SaveGradeErrorResponse(result); } - final CourseGradeTransferBean studentCourseGrade = businessService.getCourseGrade(studentUuid); - final Gradebook gradebook = businessService.getGradebook(); + final CourseGradeTransferBean studentCourseGrade = businessService.getCourseGrade(currentGradebookUid, currentSiteId, studentUuid); + final Gradebook gradebook = businessService.getGradebook(currentGradebookUid, currentSiteId); final CourseGradeFormatter courseGradeFormatter = new CourseGradeFormatter( gradebook, page.getCurrentRole(), - businessService.isCourseGradeVisible(businessService.getCurrentUser().getId()), + businessService.isCourseGradeVisible(currentGradebookUid, currentSiteId, businessService.getCurrentUser().getId()), page.getUiSettings().getShowPoints(), true, true); @@ -189,7 +189,7 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget final String[] courseGradeData = GbGradebookData.getCourseGradeData(studentCourseGrade, gradebook.getSelectedGradeMapping().getGradeMap()); Optional catData = categoryId == null ? - Optional.empty() : businessService.getCategoryScoreForStudent(Long.valueOf(categoryId), studentUuid, true); + Optional.empty() : businessService.getCategoryScoreForStudent(currentGradebookUid, currentSiteId, Long.valueOf(categoryId), studentUuid, true); String categoryScore = catData.map(c -> String.valueOf(c.score)).orElse("-"); List droppedItems = catData.map(c -> c.droppedItems).orElse(Collections.emptyList()); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/InjectableAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/InjectableAction.java index c986209db7d5..730bc2084427 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/InjectableAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/InjectableAction.java @@ -22,4 +22,13 @@ public InjectableAction() { // inject Spring dependencies into this class and derived instances Injector.get().inject(this); } + + protected String currentGradebookUid; + protected String currentSiteId; + + public void setCurrentGradebookAndSite(String gUid, String siteId) { + currentGradebookUid = gUid; + currentSiteId = siteId; + } + } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentAction.java index 3cfd634d598b..e81ca09ae66b 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentAction.java @@ -16,22 +16,59 @@ package org.sakaiproject.gradebookng.tool.actions; import com.fasterxml.jackson.databind.JsonNode; +import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.spring.injection.annot.SpringBean; import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; +import org.sakaiproject.gradebookng.tool.model.GradebookUiSettings; +import org.sakaiproject.gradebookng.tool.pages.GradebookPage; import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.SortType; import java.io.Serializable; import java.util.List; import java.util.stream.Collectors; -abstract public class MoveAssignmentAction extends InjectableAction implements Serializable { +public class MoveAssignmentAction extends InjectableAction implements Serializable { private static final long serialVersionUID = 1L; @SpringBean(name = "org.sakaiproject.gradebookng.business.GradebookNgBusinessService") protected GradebookNgBusinessService businessService; - public MoveAssignmentAction() { + private int movement; + public MoveAssignmentAction(int mov) { + movement = mov; + } + + public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget target) { + final GradebookPage gradebookPage = (GradebookPage) target.getPage(); + + final Long assignmentId = Long.valueOf(params.get("assignmentId").asText()); + + GradebookUiSettings settings = gradebookPage.getUiSettings(); + + if (settings == null) { + settings = new GradebookUiSettings(); + gradebookPage.setUiSettings(settings); + } + + if (settings.isCategoriesEnabled() && settings.isGroupedByCategory()) { + try { + final Integer order = calculateCurrentCategorizedSortOrder(assignmentId); + businessService.updateAssignmentCategorizedOrder(currentGradebookUid, currentSiteId, assignmentId, + (order.intValue() + movement)); + } catch (final Exception e) { + return new ArgumentErrorResponse("Error reordering within category: " + e.getMessage()); + } + } else { + final int order = businessService.getAssignmentSortOrder(currentGradebookUid, currentSiteId, assignmentId.longValue()); + businessService.updateAssignmentOrder(currentGradebookUid, currentSiteId, assignmentId.longValue(), (order + movement)); + } + + // refresh the page + target.appendJavaScript("location.reload();"); + + return new EmptyOkResponse(); } /** @@ -42,12 +79,12 @@ public MoveAssignmentAction() { * @return the current sort index of the assignment within their category */ protected Integer calculateCurrentCategorizedSortOrder(final Long assignmentId) { - final Assignment assignment = MoveAssignmentAction.this.businessService.getAssignment(assignmentId.longValue()); + final Assignment assignment = businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId.longValue()); Integer order = assignment.getCategorizedSortOrder(); if (order == null) { // if no categorized order for assignment, calculate one based on the default sort order - final List assignments = MoveAssignmentAction.this.businessService.getGradebookAssignments(); + final List assignments = businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, SortType.SORT_BY_SORTING); final List assignmentIdsInCategory = assignments.stream() .filter(a -> (a.getCategoryId() != null) && a.getCategoryId().equals(assignment.getCategoryId())) .map(Assignment::getId) diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentLeftAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentLeftAction.java deleted file mode 100644 index 7c997e367600..000000000000 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentLeftAction.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2003-2017 The Apereo Foundation - * - * Licensed under the Educational Community License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://opensource.org/licenses/ecl2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sakaiproject.gradebookng.tool.actions; - -import com.fasterxml.jackson.databind.JsonNode; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; -import org.sakaiproject.gradebookng.tool.model.GradebookUiSettings; -import org.sakaiproject.gradebookng.tool.pages.GradebookPage; - -import java.io.Serializable; - -public class MoveAssignmentLeftAction extends MoveAssignmentAction implements Serializable { - - private static final long serialVersionUID = 1L; - - public MoveAssignmentLeftAction() { - } - - @Override - public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget target) { - final GradebookPage gradebookPage = (GradebookPage) target.getPage(); - - final Long assignmentId = Long.valueOf(params.get("assignmentId").asText()); - - GradebookUiSettings settings = gradebookPage.getUiSettings(); - - if (settings == null) { - settings = new GradebookUiSettings(); - gradebookPage.setUiSettings(settings); - } - - if (settings.isCategoriesEnabled() && settings.isGroupedByCategory()) { - try { - final Integer order = calculateCurrentCategorizedSortOrder(assignmentId); - MoveAssignmentLeftAction.this.businessService.updateAssignmentCategorizedOrder(assignmentId, - (order.intValue() - 1)); - } catch (final Exception e) { - return new ArgumentErrorResponse("Error reordering within category: " + e.getMessage()); - } - } else { - final int order = MoveAssignmentLeftAction.this.businessService.getAssignmentSortOrder(assignmentId.longValue()); - MoveAssignmentLeftAction.this.businessService.updateAssignmentOrder(assignmentId.longValue(), (order - 1)); - } - - // refresh the page - target.appendJavaScript("location.reload();"); - - return new EmptyOkResponse(); - } -} diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentRightAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentRightAction.java deleted file mode 100644 index 59b0a9452fbd..000000000000 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/MoveAssignmentRightAction.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2003-2017 The Apereo Foundation - * - * Licensed under the Educational Community License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://opensource.org/licenses/ecl2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sakaiproject.gradebookng.tool.actions; - -import com.fasterxml.jackson.databind.JsonNode; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; -import org.sakaiproject.gradebookng.tool.model.GradebookUiSettings; -import org.sakaiproject.gradebookng.tool.pages.GradebookPage; - -import java.io.Serializable; - -public class MoveAssignmentRightAction extends MoveAssignmentAction implements Serializable { - - private static final long serialVersionUID = 1L; - - public MoveAssignmentRightAction() { - } - - @Override - public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget target) { - final GradebookPage gradebookPage = (GradebookPage) target.getPage(); - - final Long assignmentId = Long.valueOf(params.get("assignmentId").asText()); - - GradebookUiSettings settings = gradebookPage.getUiSettings(); - - if (settings == null) { - settings = new GradebookUiSettings(); - gradebookPage.setUiSettings(settings); - } - - if (settings.isCategoriesEnabled() && settings.isGroupedByCategory()) { - try { - final Integer order = calculateCurrentCategorizedSortOrder(assignmentId); - MoveAssignmentRightAction.this.businessService.updateAssignmentCategorizedOrder(assignmentId, - (order.intValue() + 1)); - } catch (final Exception e) { - return new ArgumentErrorResponse("Error reordering within category: " + e.getMessage()); - } - } else { - final int order = MoveAssignmentRightAction.this.businessService.getAssignmentSortOrder(assignmentId.longValue()); - MoveAssignmentRightAction.this.businessService.updateAssignmentOrder(assignmentId.longValue(), (order + 1)); - } - - // refresh the page - target.appendJavaScript("location.reload();"); - - return new EmptyOkResponse(); - } -} diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/OverrideCourseGradeAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/OverrideCourseGradeAction.java index 157235c16294..725c8022a30e 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/OverrideCourseGradeAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/OverrideCourseGradeAction.java @@ -39,9 +39,11 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget final GbModalWindow window = gradebookPage.getUpdateCourseGradeDisplayWindow(); window.setStudentToReturnFocusTo(studentUuid); window.setReturnFocusToCourseGrade(); - window.setContent(new CourseGradeOverridePanel(window.getContentId(), + CourseGradeOverridePanel cgop = new CourseGradeOverridePanel(window.getContentId(), Model.of(studentUuid), - window)); + window); + cgop.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + window.setContent(cgop); window.showUnloadConfirmation(false); window.show(target); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/SetScoreForUngradedAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/SetScoreForUngradedAction.java index 78ac2b17d8d5..81d4f13ed8d9 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/SetScoreForUngradedAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/SetScoreForUngradedAction.java @@ -42,6 +42,7 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget Model.of(Long.valueOf(assignmentId)), window); + panel.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); window.setTitle(gradebookPage.getString("heading.updateungradeditems")); window.setAssignmentToReturnFocusTo(assignmentId); window.setContent(panel); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewAssignmentStatisticsAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewAssignmentStatisticsAction.java index 0dcd8e61ed13..d90d3057f2e3 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewAssignmentStatisticsAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewAssignmentStatisticsAction.java @@ -38,9 +38,11 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget final GradebookPage gradebookPage = (GradebookPage) target.getPage(); final GbModalWindow window = gradebookPage.getAssignmentStatisticsWindow(); window.setAssignmentToReturnFocusTo(assignmentId); - window.setContent(new AssignmentStatisticsPanel(window.getContentId(), + AssignmentStatisticsPanel content = new AssignmentStatisticsPanel(window.getContentId(), Model.of(Long.valueOf(assignmentId)), - window)); + window); + content.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + window.setContent(content); window.show(target); return new EmptyOkResponse(); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeLogAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeLogAction.java index be3f16357f52..58bc57bb2a47 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeLogAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeLogAction.java @@ -40,7 +40,9 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget window.setStudentToReturnFocusTo(studentUuid); window.setReturnFocusToCourseGrade(); - window.setContent(new CourseGradeOverrideLogPanel(window.getContentId(), Model.of(studentUuid), window)); + CourseGradeOverrideLogPanel cgolp = new CourseGradeOverrideLogPanel(window.getContentId(), Model.of(studentUuid), window); + cgolp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + window.setContent(cgolp); window.showUnloadConfirmation(false); window.show(target); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeStatisticsAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeStatisticsAction.java index 97f20ff36236..697a2c6528d7 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeStatisticsAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewCourseGradeStatisticsAction.java @@ -35,12 +35,12 @@ public ViewCourseGradeStatisticsAction() { @Override public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget target) { - final String siteId = params.get("siteId").asText(); - final GradebookPage gradebookPage = (GradebookPage) target.getPage(); final GbModalWindow window = gradebookPage.getGradeLogWindow(); - window.setContent(new CourseGradeStatisticsPanel(window.getContentId(), Model.of(siteId), window)); + CourseGradeStatisticsPanel cgsp = new CourseGradeStatisticsPanel(window.getContentId(), window); + cgsp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + window.setContent(cgsp); window.show(target); return new EmptyOkResponse(); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewGradeSummaryAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewGradeSummaryAction.java index e1cc0fa3c7a3..5aefef017f12 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewGradeSummaryAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewGradeSummaryAction.java @@ -58,6 +58,7 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget final GbModalWindow window = gradebookPage.getStudentGradeSummaryWindow(); final Component content = new StudentGradeSummaryPanel(window.getContentId(), Model.ofMap(model), window); + ((StudentGradeSummaryPanel)content).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); if (window.isShown() && window.isVisible()) { window.replace(content); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricGradeAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricGradeAction.java index e03910d5ae21..8f924cd5c471 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricGradeAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricGradeAction.java @@ -44,7 +44,9 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget window.setAssignmentToReturnFocusTo(assignmentId); window.setStudentToReturnFocusTo(studentUuid); - window.setContent(new RubricGradePanel(window.getContentId(), Model.ofMap(model), window)); + RubricGradePanel rgp = new RubricGradePanel(window.getContentId(), Model.ofMap(model), window); + rgp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + window.setContent(rgp); window.show(target); return new EmptyOkResponse(); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricPreviewAction.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricPreviewAction.java index 30e92c9c15b2..bdaace89c1d2 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricPreviewAction.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/actions/ViewRubricPreviewAction.java @@ -37,7 +37,9 @@ public ActionResponse handleEvent(final JsonNode params, final AjaxRequestTarget final GradebookPage gradebookPage = (GradebookPage) target.getPage(); final GbModalWindow window = gradebookPage.getRubricPreviewWindow(); window.setAssignmentToReturnFocusTo(assignmentId); - window.setContent(new RubricPreviewPanel(window.getContentId(), Model.of(model), window)); + RubricPreviewPanel rpp = new RubricPreviewPanel(window.getContentId(), Model.of(model), window); + rpp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + window.setContent(rpp); window.show(target); return new EmptyOkResponse(); } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/AssignmentGradeChart.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/AssignmentGradeChart.java index a39b4ad0644f..3caa3afa89c8 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/AssignmentGradeChart.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/AssignmentGradeChart.java @@ -25,10 +25,11 @@ import org.apache.wicket.model.StringResourceModel; import org.sakaiproject.gradebookng.business.model.GbGradeInfo; import org.sakaiproject.gradebookng.business.model.GbStudentGradeInfo; -import org.sakaiproject.gradebookng.business.util.MessageHelper; import org.sakaiproject.gradebookng.tool.model.GbChartData; import org.sakaiproject.grading.api.Assignment; import org.sakaiproject.grading.api.GradingConstants; +import org.sakaiproject.grading.api.MessageHelper; +import org.sakaiproject.util.ResourceLoader; /** * Panel that renders the individual assignment grade charts @@ -41,6 +42,9 @@ public class AssignmentGradeChart extends BaseChart { private final String studentGrade; + @SuppressWarnings("unchecked") + private static ResourceLoader RL = new ResourceLoader(); + public AssignmentGradeChart(final String id, final long assignmentId, final String studentGrade) { super(id); this.assignmentId = assignmentId; @@ -59,9 +63,9 @@ protected GbChartData getData() { // so students can get grade stats addAdvisor(); - final Integer gradingType = this.businessService.getGradebook().getGradeType(); - final Assignment assignment = this.businessService.getAssignment(this.assignmentId); - final List gradeInfo = this.businessService.buildGradeMatrix(Arrays.asList(assignment)); + final Integer gradingType = this.businessService.getGradebook(currentGradebookUid, currentSiteId).getGradeType(); + final Assignment assignment = this.businessService.getAssignment(currentGradebookUid, currentSiteId, this.assignmentId); + final List gradeInfo = this.businessService.buildGradeMatrix(currentGradebookUid, currentSiteId, Arrays.asList(assignment), this.businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null), null); // get all grades for this assignment final List allGrades = new ArrayList<>(); @@ -98,9 +102,9 @@ protected GbChartData getData() { data.add(determineKeyForGrade(percentage, range)); } - data.setChartTitle(MessageHelper.getString("label.statistics.chart.title")); - data.setXAxisLabel(MessageHelper.getString("label.statistics.chart.xaxis")); - data.setYAxisLabel(MessageHelper.getString("label.statistics.chart.yaxis")); + data.setChartTitle(MessageHelper.getString("label.statistics.chart.title", RL.getLocale())); + data.setXAxisLabel(MessageHelper.getString("label.statistics.chart.xaxis", RL.getLocale())); + data.setYAxisLabel(MessageHelper.getString("label.statistics.chart.yaxis", RL.getLocale())); data.setChartType("bar"); data.setChartId(this.getMarkupId()); if (this.studentGrade != null) { diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/BaseChart.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/BaseChart.java index 297434b214de..8cfbb9580f61 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/BaseChart.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/BaseChart.java @@ -49,6 +49,14 @@ public abstract class BaseChart extends WebComponent { private transient SecurityAdvisor advisor; + protected String currentGradebookUid; + protected String currentSiteId; + + public void setCurrentGradebookAndSite(String gUid, String siteId) { + currentGradebookUid = gUid; + currentSiteId = siteId; + } + public BaseChart(final String id) { super(id); setOutputMarkupPlaceholderTag(true); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/CourseGradeChart.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/CourseGradeChart.java index e8aac3ec7d75..7ea06dd766f4 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/CourseGradeChart.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/chart/CourseGradeChart.java @@ -20,11 +20,12 @@ import java.util.Set; import org.apache.wicket.ajax.AjaxRequestTarget; -import org.sakaiproject.gradebookng.business.util.MessageHelper; import org.sakaiproject.gradebookng.tool.model.GbChartData; import org.sakaiproject.grading.api.CourseGradeTransferBean; import org.sakaiproject.grading.api.GradeMappingDefinition; import org.sakaiproject.grading.api.GradebookInformation; +import org.sakaiproject.grading.api.MessageHelper; +import org.sakaiproject.util.ResourceLoader; /** * Panel that renders the course grade chart for a site. @@ -33,13 +34,13 @@ public class CourseGradeChart extends BaseChart { private static final long serialVersionUID = 1L; - private final String siteId; - private CourseGradeTransferBean studentGrade; - public CourseGradeChart(final String id, final String siteId, CourseGradeTransferBean studentGrade) { + @SuppressWarnings("unchecked") + private static ResourceLoader RL = new ResourceLoader(); + + public CourseGradeChart(final String id, CourseGradeTransferBean studentGrade) { super(id); - this.siteId = siteId; this.studentGrade = studentGrade; } @@ -61,14 +62,14 @@ public void refresh(final AjaxRequestTarget target, final Map sc */ @Override protected GbChartData getData() { - final GradebookInformation info = this.businessService.getGradebookSettings(this.siteId); + final GradebookInformation info = this.businessService.getGradebookSettings(currentGradebookUid, currentSiteId); final Map gradingSchema = info.getSelectedGradingScaleBottomPercents(); final GbChartData data = getData(gradingSchema); - data.setChartTitle(MessageHelper.getString("settingspage.gradingschema.chart.heading")); - data.setXAxisLabel(MessageHelper.getString("settingspage.gradingschema.chart.xaxis")); - data.setYAxisLabel(MessageHelper.getString("settingspage.gradingschema.chart.yaxis")); + data.setChartTitle(MessageHelper.getString("settingspage.gradingschema.chart.heading", RL.getLocale())); + data.setXAxisLabel(MessageHelper.getString("settingspage.gradingschema.chart.xaxis", RL.getLocale())); + data.setYAxisLabel(MessageHelper.getString("settingspage.gradingschema.chart.yaxis", RL.getLocale())); data.setChartType("horizontalBar"); data.setChartId(this.getMarkupId()); if (this.studentGrade != null) { @@ -90,7 +91,7 @@ private GbChartData getData(final Map gradingSchema) { final Map schema = GradeMappingDefinition.sortGradeMapping(gradingSchema); // get the course grades and re-map. Also sorts the data so it is ready for the consumer to use - final Map courseGrades = this.businessService.getCourseGrades(this.siteId, schema); + final Map courseGrades = this.businessService.getCourseGrades(currentGradebookUid, currentSiteId, businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null), schema); final GbChartData data = reMap(courseGrades, gradingSchema.keySet()); return data; diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/component/GbGradeTable.html b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/component/GbGradeTable.html index 900ab7c7e6dd..011fb5b10d28 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/component/GbGradeTable.html +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/component/GbGradeTable.html @@ -165,7 +165,7 @@ {/if}

diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradeTableData.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradeTableData.java index fc0b3b519331..b74b093cb8be 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradeTableData.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradeTableData.java @@ -19,6 +19,9 @@ import java.util.List; import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.sakaiproject.assignment.api.AssignmentConstants; +import org.sakaiproject.assignment.api.AssignmentReferenceReckoner; import org.sakaiproject.gradebookng.business.GbRole; import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; import org.sakaiproject.gradebookng.business.exception.GbAccessDeniedException; @@ -28,6 +31,9 @@ import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.GradebookInformation; import org.sakaiproject.grading.api.SortType; +import org.sakaiproject.rubrics.api.RubricsConstants; +import org.sakaiproject.rubrics.api.RubricsService; +import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.grading.api.model.Gradebook; import lombok.EqualsAndHashCode; @@ -50,12 +56,14 @@ public class GbGradeTableData { private Long gradebookId; private boolean isStudentNumberVisible; private boolean isSectionsVisible; + private String gradebookUid; - public GbGradeTableData(final GradebookNgBusinessService businessService, - final GradebookUiSettings settings) { + public GbGradeTableData(final String currentGradebookUid, final String currentSiteId, final GradebookNgBusinessService businessService, + final GradebookUiSettings settings, final ToolManager toolManager, final RubricsService rubricsService) { final GbStopWatch stopwatch = new GbStopWatch(); stopwatch.time("GbGradeTableData init", stopwatch.getTime()); + this.gradebookUid = currentGradebookUid; uiSettings = settings; SortType sortBy = SortType.SORT_BY_SORTING; @@ -65,42 +73,62 @@ public GbGradeTableData(final GradebookNgBusinessService businessService, } try { - role = businessService.getUserRole(); + role = businessService.getUserRole(currentSiteId); } catch (GbAccessDeniedException e) { throw new RuntimeException(e); } - isUserAbleToEditAssessments = businessService.isUserAbleToEditAssessments(); - assignments = businessService.getGradebookAssignments(sortBy); + isUserAbleToEditAssessments = businessService.isUserAbleToEditAssessments(currentSiteId); + assignments = businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, sortBy); assignments.stream() .filter(assignment -> assignment.getExternallyMaintained()) .forEach(assignment -> assignment.setExternalToolTitle(businessService.getExternalAppName(assignment.getExternalAppName())) ); stopwatch.time("getGradebookAssignments", stopwatch.getTime()); - grades = businessService.buildGradeMatrix( + String groupFilter = uiSettings.getGroupFilter() != null ? uiSettings.getGroupFilter().getId() : null; + grades = businessService.buildGradeMatrix(currentGradebookUid, currentSiteId, assignments, + businessService.getGradeableUsers(currentGradebookUid, currentSiteId, groupFilter), settings); stopwatch.time("buildGradeMatrix", stopwatch.getTime()); - categories = businessService.getGradebookCategories(); + categories = businessService.getGradebookCategories(currentGradebookUid, currentSiteId); stopwatch.time("getGradebookCategories", stopwatch.getTime()); - gradebookInformation = businessService.getGradebookSettings(); + gradebookInformation = businessService.getGradebookSettings(currentGradebookUid, currentSiteId); stopwatch.time("getGradebookSettings", stopwatch.getTime()); toolNameToIconCSS = businessService.getIconClassMap(); defaultIconCSS = businessService.getDefaultIconClass(); stopwatch.time("toolNameToIconCSS", stopwatch.getTime()); - final Gradebook gradebook = businessService.getGradebook(); + final Gradebook gradebook = businessService.getGradebook(currentGradebookUid, currentSiteId); courseGradeMap = gradebook.getSelectedGradeMapping().getGradeMap(); - hasAssociatedRubricMap = businessService.buildHasAssociatedRubricMap(assignments); + hasAssociatedRubricMap = buildHasAssociatedRubricMap(assignments, toolManager, rubricsService); gradebookId = gradebook.getId(); courseGradeId = businessService.getCourseGradeId(gradebookId); - isStudentNumberVisible = businessService.isStudentNumberVisible(); + isStudentNumberVisible = businessService.isStudentNumberVisible(currentSiteId); - isSectionsVisible = businessService.isSectionsVisible(); + isSectionsVisible = businessService.isSectionsVisible(currentSiteId); + + } + + public HashMap buildHasAssociatedRubricMap(final List assignments, final ToolManager toolManager, final RubricsService rubricsService) { + HashMap map = new HashMap(); + for (Assignment assignment : assignments) { + String externalAppName = assignment.getExternalAppName(); + if(assignment.getExternallyMaintained()) { + String assignmentId = AssignmentReferenceReckoner.reckoner().reference(assignment.getExternalId()).reckon().getId(); + boolean hasAssociatedRubric = StringUtils.equals(externalAppName, AssignmentConstants.TOOL_ID) ? rubricsService.hasAssociatedRubric(externalAppName, assignmentId) : false; + map.put(assignmentId, hasAssociatedRubric); + } else { + Long assignmentId = assignment.getId(); + boolean hasAssociatedRubric = rubricsService.hasAssociatedRubric(RubricsConstants.RBCS_TOOL_GRADEBOOKNG, assignmentId.toString()); + map.put(assignmentId.toString(), hasAssociatedRubric); + } + } + return map; } } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradebookData.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradebookData.java index 682f7c490199..15e7aa72cf94 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradebookData.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/model/GbGradebookData.java @@ -81,6 +81,7 @@ public class GbGradebookData { private final Map hasAssociatedRubricMap; private final boolean isStudentNumberVisible; private final boolean isSectionsVisible; + private final String gUid; private final Map categoryMap = new HashMap<>(); private final Component parent; @@ -242,6 +243,7 @@ public GbGradebookData(final GbGradeTableData gbGradeTableData, final Component this.isUserAbleToEditAssessments = gbGradeTableData.isUserAbleToEditAssessments(); this.courseGradeMap = gbGradeTableData.getCourseGradeMap(); + this.gUid = gbGradeTableData.getGradebookUid(); this.courseGradeId = gbGradeTableData.getCourseGradeId(); this.gradebookId = gbGradeTableData.getGradebookId(); this.isStudentNumberVisible = gbGradeTableData.isStudentNumberVisible(); @@ -426,6 +428,7 @@ private Map serializeSettings() { result.put("isSectionsVisible", this.isSectionsVisible && ServerConfigurationService.getBoolean("gradebookng.showSections", true)); result.put("isSetUngradedToZeroEnabled", ServerConfigurationService.getBoolean(SAK_PROP_SHOW_SET_ZERO_SCORE, SAK_PROP_SHOW_SET_ZERO_SCORE_DEFAULT)); result.put("isShowDisplayCourseGradeToStudentEnabled", ServerConfigurationService.getBoolean(SAK_PROP_SHOW_COURSE_GRADE_STUDENT, SAK_PROP_SHOW_COURSE_GRADE_STUDENT_DEFAULT)); + result.put("gUid", this.gUid); return result; }; diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/BasePage.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/BasePage.java index 156d92877f77..08b5ac6300e1 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/BasePage.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/BasePage.java @@ -16,6 +16,7 @@ package org.sakaiproject.gradebookng.tool.pages; import java.util.Locale; +import java.util.Properties; import javax.servlet.http.HttpServletRequest; @@ -36,12 +37,25 @@ import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.spring.injection.annot.SpringBean; import org.sakaiproject.component.api.ServerConfigurationService; +import org.sakaiproject.entity.api.ResourceProperties; +import org.sakaiproject.entity.api.ResourcePropertiesEdit; +import org.sakaiproject.exception.IdUnusedException; +import org.sakaiproject.exception.IdUsedException; +import org.sakaiproject.exception.InUseException; +import org.sakaiproject.exception.PermissionException; import org.sakaiproject.gradebookng.business.GbRole; import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; import org.sakaiproject.gradebookng.business.exception.GbAccessDeniedException; import org.sakaiproject.gradebookng.tool.component.GbFeedbackPanel; import org.sakaiproject.portal.util.PortalUtils; import org.sakaiproject.rubrics.api.RubricsService; +import org.sakaiproject.tool.api.Placement; +import org.sakaiproject.tool.api.ToolManager; +import org.sakaiproject.user.api.Preferences; +import org.sakaiproject.user.api.PreferencesEdit; +import org.sakaiproject.user.api.PreferencesService; +import org.sakaiproject.user.api.User; +import org.sakaiproject.user.api.UserDirectoryService; import lombok.extern.slf4j.Slf4j; @@ -65,6 +79,17 @@ public class BasePage extends WebPage { @SpringBean(name = "org.sakaiproject.component.api.ServerConfigurationService") protected ServerConfigurationService serverConfigService; + @SpringBean(name = "org.sakaiproject.user.api.PreferencesService") + protected PreferencesService preferencesService; + + @SpringBean(name = "org.sakaiproject.tool.api.ToolManager") + protected ToolManager toolManager; + + @SpringBean(name = "org.sakaiproject.user.api.UserDirectoryService") + protected UserDirectoryService userDirectoryService; + + public static final String GB_PREF_KEY = "GBNG-"; + Link gradebookPageLink; Link settingsPageLink; Link importExportPageLink; @@ -90,7 +115,7 @@ public BasePage() { this.currentUserUuid = this.businessService.getCurrentUser().getId(); role = GbRole.NONE; try { - this.role = this.businessService.getUserRole(); + this.role = this.businessService.getUserRole(getCurrentSiteId()); } catch (final GbAccessDeniedException e) { log.error("Error getting user role", e); // do not redirect here, let the subclasses handle this! @@ -133,7 +158,7 @@ public boolean isVisible() { @Override public boolean isVisible() { - return (businessService.isUserAbleToEditAssessments()); + return (businessService.isUserAbleToEditAssessments(getCurrentSiteId())); } }; this.importExportPageLink.add(new Label("screenreaderlabel", getString("link.screenreader.tabnotselected"))); @@ -157,7 +182,7 @@ public boolean isVisible() { @Override public boolean isVisible() { - return (businessService.isUserAbleToEditAssessments()); + return (businessService.isUserAbleToEditAssessments(getCurrentSiteId())); } }; this.settingsPageLink.add(new Label("screenreaderlabel", getString("link.screenreader.tabnotselected"))); @@ -169,7 +194,7 @@ public boolean isVisible() { @Override public boolean isVisible() { - return (businessService.isUserAbleToEditAssessments()); + return (businessService.isUserAbleToEditAssessments(getCurrentSiteId())); } }; this.quickEntryPageLink.add(new Label("screenreaderlabel", getString("link.screenreader.tabnotselected"))); @@ -310,10 +335,76 @@ protected final void defaultRoleChecksForInstructorOnlyPage() case STUDENT: throw new RestartResponseException(StudentPage.class); default: - if(businessService.isUserAbleToEditAssessments()) { + if(businessService.isUserAbleToEditAssessments(getCurrentSiteId())) { break; } throw new RestartResponseException(GradebookPage.class); } } + + protected String getCurrentSiteId() { + try { + return this.toolManager.getCurrentPlacement().getContext(); + } catch (final Exception e) { + return null; + } + } + + protected String getCurrentGradebookUid() { + String gradebookUid = getCurrentSiteId(); + Placement placement = toolManager.getCurrentPlacement(); + Properties props = placement.getPlacementConfig(); + if (props.getProperty("gb-group") != null) { + gradebookUid = props.getProperty("gb-group"); + } + + return gradebookUid; + } + + public User getCurrentUser() { + return this.userDirectoryService.getCurrentUser(); + } + + /** + * Get the user's custom GbUiSettings from PreferencesService + * + * @return String + */ + public String getUserGbPreference(final String prefName) { + final String siteId = getCurrentSiteId(); + final String currentUserId = getCurrentUser().getId(); + Preferences userPrefs = preferencesService.getPreferences(currentUserId); + ResourceProperties rp = userPrefs.getProperties(GB_PREF_KEY + siteId); + return rp.getProperty(prefName); + } + + /** + * Set the user's custom GbUiSettings in PreferencesService + * + * @return + */ + public void setUserGbPreference(final String prefName, final String prefValue) { + final String siteId = getCurrentSiteId(); + final String currentUserId = getCurrentUser().getId(); + PreferencesEdit prefsEdit = null; + try { + prefsEdit = preferencesService.edit(currentUserId); + } + catch (IdUnusedException e) { + try { + prefsEdit = preferencesService.add(currentUserId); + } catch (PermissionException e1) { + log.warn("setUserGbPreference PermissionException attempting to add prefs for user {}, prefName={}", currentUserId, prefName); + } catch (IdUsedException e1) { + log.warn("setUserGbPreference IdUsedException attempting to add prefs for user {}, prefName={}", currentUserId, prefName); + } + } catch (PermissionException e) { + log.warn("setUserGbPreference PermissionException attempting to edit prefs for user {}, prefName={}", currentUserId, prefName); + } catch (InUseException e) { + log.warn("setUserGbPreference InUseException attempting to edit prefs for user {}, prefName={}", currentUserId, prefName); + } + ResourcePropertiesEdit props = prefsEdit.getPropertiesEdit(GB_PREF_KEY + siteId); + props.addProperty(prefName, prefValue); + preferencesService.commit(prefsEdit); + } } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/GradebookPage.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/GradebookPage.java index 9541848839c4..0c643cd273a5 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/GradebookPage.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/GradebookPage.java @@ -52,8 +52,7 @@ import org.sakaiproject.gradebookng.tool.actions.EditSettingsAction; import org.sakaiproject.gradebookng.tool.actions.ExcuseGradeAction; import org.sakaiproject.gradebookng.tool.actions.GradeUpdateAction; -import org.sakaiproject.gradebookng.tool.actions.MoveAssignmentLeftAction; -import org.sakaiproject.gradebookng.tool.actions.MoveAssignmentRightAction; +import org.sakaiproject.gradebookng.tool.actions.MoveAssignmentAction; import org.sakaiproject.gradebookng.tool.actions.OverrideCourseGradeAction; import org.sakaiproject.gradebookng.tool.actions.QuickEntryAction; import org.sakaiproject.gradebookng.tool.actions.SetScoreForUngradedAction; @@ -126,6 +125,9 @@ public class GradebookPage extends BasePage { boolean showGroupFilter = true; private GbGradeTable gradeTable; + private String gradebookUid; + private String siteId; + private final WebMarkupContainer tableArea; @SuppressWarnings({ "rawtypes", "unchecked", "serial" }) @@ -136,8 +138,11 @@ public GradebookPage() { sendToAccessDeniedPage(getString("error.role")); } + gradebookUid = getCurrentGradebookUid(); + siteId = getCurrentSiteId(); + // get Gradebook to save additional calls later - final Gradebook gradebook = this.businessService.getGradebook(); + final Gradebook gradebook = this.businessService.getGradebook(gradebookUid, siteId); // students cannot access this page, they have their own if (this.role == GbRole.STUDENT) { @@ -153,14 +158,14 @@ public GradebookPage() { } // no perms - this.permissions = this.businessService.getPermissionsForUser(this.currentUserUuid); + this.permissions = this.businessService.getPermissionsForUser(this.currentUserUuid, gradebookUid, siteId); if (this.permissions.isEmpty() || (this.permissions.size() == 1 && StringUtils.equals(this.permissions.get(0).getFunctionName(), GraderPermission.NONE.toString()))) { sendToAccessDeniedPage(getString("ta.nopermission")); } } // This is not a Student or TA, so it is either custom role or an Instructor. - else if (!this.businessService.isUserAbleToEditAssessments()) { + else if (!this.businessService.isUserAbleToEditAssessments(siteId)) { sendToAccessDeniedPage(getString("ta.nopermission")); } @@ -171,7 +176,8 @@ else if (!this.businessService.isUserAbleToEditAssessments()) { this.form = new Form<>("form"); add(this.form); - this.form.add(new AttributeModifier("data-siteid", this.businessService.getCurrentSiteId())); + this.form.add(new AttributeModifier("data-siteid", siteId)); + this.form.add(new AttributeModifier("data-guid", gradebook != null ? gradebookUid : siteId)); this.form.add(new AttributeModifier("data-gradestimestamp", new Date().getTime())); /** @@ -240,14 +246,43 @@ else if (!this.businessService.isUserAbleToEditAssessments()) { sortBy = SortType.SORT_BY_CATEGORY; this.form.add(new AttributeAppender("class", "gb-grouped-by-category")); } + // section and group dropdown + final List groups = this.businessService.getSiteSectionsAndGroups(gradebookUid, siteId); + + final DropDownChoice groupFilter = new DropDownChoice<>("groupFilter", new Model<>(), + groups, new ChoiceRenderer() { + private static final long serialVersionUID = 1L; + + @Override + public Object getDisplayValue(final GbGroup g) { + return g.getTitle(); + } + + @Override + public String getIdValue(final GbGroup g, final int index) { + return g.getId(); + } + }); + + if (!gradebookUid.equals(siteId)) { + for (GbGroup g : groups) { + if (g.getId() != null && g.getId().equals(gradebookUid)) { + settings.setGroupFilter(g); + setUiSettings(settings); + groupFilter.setVisible(false); + break; + } + } + } - final List assignments = this.businessService.getGradebookAssignments(sortBy); - final List students = this.businessService.getGradeableUsers(); + final List assignments = this.businessService.getGradebookAssignments(gradebookUid, siteId, sortBy); + String selectedGroup = settings.getGroupFilter() != null ? settings.getGroupFilter().getId() : null; + final List students = this.businessService.getGradeableUsers(gradebookUid, siteId, selectedGroup); this.hasGradebookItems = !assignments.isEmpty(); this.hasStudents = !students.isEmpty(); // categories enabled? - final boolean categoriesEnabled = this.businessService.categoriesAreEnabled(); + final boolean categoriesEnabled = this.businessService.categoriesAreEnabled(gradebookUid, siteId); this.tableArea = new WebMarkupContainer("gradeTableArea"); if (!this.hasGradebookItems) { @@ -266,7 +301,7 @@ else if (!this.businessService.isUserAbleToEditAssessments()) { final GbAddButton addGradeItem2 = new GbAddButton("addGradeItem2") { @Override public boolean isVisible() { - return businessService.isUserAbleToEditAssessments(); + return businessService.isUserAbleToEditAssessments(siteId); } }; addGradeItem2.setDefaultFormProcessing(false); @@ -292,32 +327,71 @@ public boolean isVisible() { new LoadableDetachableModel() { @Override public GbGradeTableData load() { - return new GbGradeTableData(GradebookPage.this.businessService, settings); + return new GbGradeTableData(gradebookUid, siteId, businessService, settings, toolManager, rubricsService); } }); - this.gradeTable.addEventListener("setScore", new GradeUpdateAction()); - this.gradeTable.addEventListener("gradeRubric", new ViewRubricGradeAction()); + GradeUpdateAction setScore = new GradeUpdateAction(); + setScore.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("setScore", setScore); + ViewRubricGradeAction gradeRubric = new ViewRubricGradeAction(); + gradeRubric.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("gradeRubric", gradeRubric); this.gradeTable.addEventListener("viewLog", new ViewGradeLogAction()); - this.gradeTable.addEventListener("editAssignment", new EditAssignmentAction()); - this.gradeTable.addEventListener("viewStatistics", new ViewAssignmentStatisticsAction()); - this.gradeTable.addEventListener("previewRubric", new ViewRubricPreviewAction()); - this.gradeTable.addEventListener("overrideCourseGrade", new OverrideCourseGradeAction()); - this.gradeTable.addEventListener("editComment", new EditCommentAction()); - this.gradeTable.addEventListener("editCourseGradeComment", new EditCourseGradeCommentAction()); + EditAssignmentAction editAssignment = new EditAssignmentAction(); + editAssignment.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("editAssignment", editAssignment); + ViewAssignmentStatisticsAction viewStatistics = new ViewAssignmentStatisticsAction(); + viewStatistics.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("viewStatistics", viewStatistics); + OverrideCourseGradeAction overrideCourseGrade = new OverrideCourseGradeAction(); + overrideCourseGrade.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("overrideCourseGrade", overrideCourseGrade); + EditCommentAction editComment = new EditCommentAction(); + editComment.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("editComment", editComment); + ViewGradeSummaryAction viewGradeSummary = new ViewGradeSummaryAction(); + viewGradeSummary.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("viewGradeSummary", viewGradeSummary); + SetZeroScoreAction setZeroScore = new SetZeroScoreAction(); + setZeroScore.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("setZeroScore", setZeroScore); + ViewCourseGradeLogAction viewCourseGradeLog = new ViewCourseGradeLogAction(); + viewCourseGradeLog.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("viewCourseGradeLog", viewCourseGradeLog); + DeleteAssignmentAction deleteAssignment = new DeleteAssignmentAction(); + deleteAssignment.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("deleteAssignment", deleteAssignment); + SetScoreForUngradedAction setUngraded = new SetScoreForUngradedAction(); + setUngraded.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("setUngraded", setUngraded); this.gradeTable.addEventListener("viewGradeSummary", new ViewGradeSummaryAction()); - this.gradeTable.addEventListener("setZeroScore", new SetZeroScoreAction()); - this.gradeTable.addEventListener("viewCourseGradeLog", new ViewCourseGradeLogAction()); - this.gradeTable.addEventListener("quickEntry", new QuickEntryAction()); - this.gradeTable.addEventListener("deleteAssignment", new DeleteAssignmentAction()); - this.gradeTable.addEventListener("setUngraded", new SetScoreForUngradedAction()); this.gradeTable.addEventListener("setStudentNameOrder", new SetStudentNameOrderAction()); this.gradeTable.addEventListener("toggleCourseGradePoints", new ToggleCourseGradePoints()); this.gradeTable.addEventListener("editSettings", new EditSettingsAction()); - this.gradeTable.addEventListener("moveAssignmentLeft", new MoveAssignmentLeftAction()); - this.gradeTable.addEventListener("moveAssignmentRight", new MoveAssignmentRightAction()); - this.gradeTable.addEventListener("viewCourseGradeStatistics", new ViewCourseGradeStatisticsAction()); - this.gradeTable.addEventListener("viewCourseGradeBreakdown", new CourseGradeBreakdownAction()); - this.gradeTable.addEventListener("excuseGrade", new ExcuseGradeAction()); + MoveAssignmentAction moveAssignmentLeft = new MoveAssignmentAction(-1); + moveAssignmentLeft.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("moveAssignmentLeft", moveAssignmentLeft); + MoveAssignmentAction moveAssignmentRight = new MoveAssignmentAction(1); + moveAssignmentRight.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("moveAssignmentRight", moveAssignmentRight); + ViewCourseGradeStatisticsAction viewCourseGradeStatistics = new ViewCourseGradeStatisticsAction(); + viewCourseGradeStatistics.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("viewCourseGradeStatistics", viewCourseGradeStatistics); + ExcuseGradeAction excuseGrade = new ExcuseGradeAction(); + excuseGrade.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("excuseGrade", excuseGrade); + EditCourseGradeCommentAction editCourseGradeComment = new EditCourseGradeCommentAction(); + editCourseGradeComment.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("editCourseGradeComment", editCourseGradeComment); + ViewRubricPreviewAction previewRubric = new ViewRubricPreviewAction(); + previewRubric.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("previewRubric", previewRubric); + QuickEntryAction quickEntry = new QuickEntryAction(); + quickEntry.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("quickEntry", quickEntry); + CourseGradeBreakdownAction viewCourseGradeBreakdown = new CourseGradeBreakdownAction(); + viewCourseGradeBreakdown.setCurrentGradebookAndSite(gradebookUid, siteId); + this.gradeTable.addEventListener("viewCourseGradeBreakdown", viewCourseGradeBreakdown); this.tableArea.add(this.gradeTable); @@ -358,14 +432,16 @@ public void onClick(final AjaxRequestTarget target) { model.put("settings", settings); window.setTitle(getString("sortgradeitems.heading")); - window.setContent(new SortGradeItemsPanel(window.getContentId(), Model.ofMap(model), window)); + SortGradeItemsPanel sgip = new SortGradeItemsPanel(window.getContentId(), Model.ofMap(model), window); + sgip.setCurrentGradebookAndSite(gradebookUid, siteId); + window.setContent(sgip); window.setComponentToReturnFocusTo(this); window.show(target); } @Override public boolean isVisible() { - return (GradebookPage.this.businessService.isUserAbleToEditAssessments()); + return (GradebookPage.this.businessService.isUserAbleToEditAssessments(siteId)); } }; toolbarColumnTools.add(sortGradeItemsToolbarItem); @@ -376,10 +452,9 @@ public boolean isVisible() { public void onClick(final AjaxRequestTarget target) { final GbModalWindow window = GradebookPage.this.getBulkEditItemsWindow(); - final String siteId = GradebookPage.this.businessService.getCurrentSiteId(); - window.setTitle(getString("bulkedit.heading")); - BulkEditItemsPanel panel = new BulkEditItemsPanel(window.getContentId(), Model.of(siteId), window); + BulkEditItemsPanel panel = new BulkEditItemsPanel(window.getContentId(), window); + panel.setCurrentGradebookAndSite(gradebookUid, siteId); window.setContent(panel.setOutputMarkupId(true)); window.setComponentToReturnFocusTo(this); window.show(target); @@ -388,14 +463,11 @@ public void onClick(final AjaxRequestTarget target) { @Override public boolean isVisible() { - return (GradebookPage.this.businessService.isUserAbleToEditAssessments()); + return (GradebookPage.this.businessService.isUserAbleToEditAssessments(siteId)); } }; toolbarColumnTools.add(bulkEditItemsToolbarItem); - // section and group dropdown - final List groups = this.businessService.getSiteSectionsAndGroups(); - // if only one group, just show the title // otherwise add the 'all groups' option // cater for the case where there is only one group visible to TA but they can see everyone. @@ -433,21 +505,6 @@ public boolean isVisible() { groups.add(0, new GbGroup("allGroups", allGroupsTitle, null, GbGroup.Type.ALL)); } - final DropDownChoice groupFilter = new DropDownChoice<>("groupFilter", new Model<>(), - groups, new ChoiceRenderer() { - private static final long serialVersionUID = 1L; - - @Override - public Object getDisplayValue(final GbGroup g) { - return g.getTitle(); - } - - @Override - public String getIdValue(final GbGroup g, final int index) { - return g.getId(); - } - }); - groupFilter.add(new AjaxFormComponentUpdatingBehavior("change") { @Override protected void onUpdate(final AjaxRequestTarget target) { @@ -468,7 +525,7 @@ protected void onUpdate(final AjaxRequestTarget target) { groupFilter.setNullValid(false); // if only one item, hide the dropdown - groupFilter.setVisible(groups.size() > 1 && this.hasStudents); + groupFilter.setVisible(groups.size() > 1 && gradebookUid.equals(siteId)); final WebMarkupContainer studentFilter = new WebMarkupContainer("studentFilter"); studentFilter.setVisible(this.hasStudents); @@ -477,7 +534,7 @@ protected void onUpdate(final AjaxRequestTarget target) { this.tableArea.add(groupFilter); final Map togglePanelModel = new HashMap<>(); - togglePanelModel.put("assignments", this.businessService.getGradebookAssignments(sortBy)); + togglePanelModel.put("assignments", this.businessService.getGradebookAssignments(gradebookUid, siteId, sortBy)); togglePanelModel.put("settings", settings); togglePanelModel.put("categoriesEnabled", categoriesEnabled); @@ -559,14 +616,14 @@ public GradebookUiSettings getUiSettings() { if (settings == null) { settings = new GradebookUiSettings(); - settings.setCategoriesEnabled(this.businessService.categoriesAreEnabled()); - settings.initializeCategoryColors(this.businessService.getGradebookCategories()); + settings.setCategoriesEnabled(this.businessService.categoriesAreEnabled(gradebookUid, siteId)); + settings.initializeCategoryColors(this.businessService.getGradebookCategories(gradebookUid, siteId)); settings.setCategoryColor(getString(GradebookPage.UNCATEGORISED), GradebookUiSettings.generateRandomRGBColorString(null)); setUiSettings(settings); } // See if the user has a database-persisted preference for Group by Category - String userGbUiCatPref = this.businessService.getUserGbPreference("GROUP_BY_CAT"); + String userGbUiCatPref = this.getUserGbPreference("GROUP_BY_CAT"); if (StringUtils.isNotBlank(userGbUiCatPref)) { settings.setGroupedByCategory(Boolean.parseBoolean(userGbUiCatPref)); } @@ -583,7 +640,7 @@ public void setUiSettings(final GradebookUiSettings settings, final boolean pers // Save the setting to PreferencesService (database) if (persistToUserPrefs) { - this.businessService.setUserGbPreference("GROUP_BY_CAT", settings.isGroupedByCategory() + ""); + this.setUserGbPreference("GROUP_BY_CAT", settings.isGroupedByCategory() + ""); } } @@ -661,13 +718,15 @@ public void onSubmit(final AjaxRequestTarget target) { final GbModalWindow window = getAddOrEditGradeItemWindow(); window.setTitle(getString("heading.addgradeitem")); window.setComponentToReturnFocusTo(this); - window.setContent(new AddOrEditGradeItemPanel(window.getContentId(), window, null)); + AddOrEditGradeItemPanel aegip = new AddOrEditGradeItemPanel(window.getContentId(), window, null); + aegip.setCurrentGradebookAndSite(gradebookUid, siteId); + window.setContent(aegip); window.show(target); } @Override public boolean isVisible() { - return businessService.isUserAbleToEditAssessments() && GradebookPage.this.hasGradebookItems; + return businessService.isUserAbleToEditAssessments(siteId) && GradebookPage.this.hasGradebookItems; } } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/ImportExportPage.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/ImportExportPage.java index 85bb03a0e31b..43829716cf73 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/ImportExportPage.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/ImportExportPage.java @@ -38,6 +38,9 @@ public class ImportExportPage extends BasePage { public WebMarkupContainer container; + private String gradebookUid; + private String siteId; + // Confirmation page displays both SUCCESS and ERROR messages. // GbFeedbackPanels are styled with a single uniform background colour to represent a single 'error level' state. // Since multiple 'error level' states are present, it looks best separated as two different panels @@ -56,9 +59,14 @@ public ImportExportPage() { disableLink(this.importExportPageLink); + gradebookUid = getCurrentGradebookUid(); + siteId = getCurrentSiteId(); + container = new WebMarkupContainer("gradebookImportExportContainer"); container.setOutputMarkupId(true); - container.add(new GradeImportUploadStep("wizard")); + GradeImportUploadStep gius = new GradeImportUploadStep("wizard"); + gius.setCurrentGradebookAndSite(gradebookUid, siteId); + container.add(gius); add(container); // hide BasePage's feedback panel and use the error/nonError filtered feedback panels diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/PermissionsPage.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/PermissionsPage.java index c09f83b1ed0d..594fa37a0834 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/PermissionsPage.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/PermissionsPage.java @@ -69,11 +69,17 @@ public class PermissionsPage extends BasePage { private final String ALL_GROUPS = "-1"; private final Long ALL_CATEGORIES = (long) -1; + private String gradebookUid; + private String siteId; + public PermissionsPage() { defaultRoleChecksForInstructorOnlyPage(); disableLink(this.permissionsPageLink); + + gradebookUid = getCurrentGradebookUid(); + siteId = getCurrentSiteId(); } @Override @@ -85,7 +91,7 @@ public void onInitialize() { final String taUuid = params.get("selected").toOptionalString(); // get the list of TAs - final List teachingAssistants = this.businessService.getTeachingAssistants(); + final List teachingAssistants = this.businessService.getTeachingAssistants(gradebookUid, siteId); teachingAssistants.sort(Comparator.nullsLast(GbUser::compareTo)); // get the TA GbUser for selected (if provided) @@ -99,9 +105,9 @@ public void onInitialize() { } // get list of categories - final List categories = this.businessService.getGradebookCategories(); + final List categories = this.businessService.getGradebookCategories(gradebookUid, siteId); - final boolean categoriesEnabled = this.businessService.categoriesAreEnabled(); + final boolean categoriesEnabled = this.businessService.categoriesAreEnabled(gradebookUid, siteId); // add the default 'all' category categories.add(0, new CategoryDefinition(this.ALL_CATEGORIES, getString("categories.all"))); @@ -113,7 +119,7 @@ public void onInitialize() { // get list of groups // note that for the permissions we need to use the group references not the ids - final List groups = this.businessService.getSiteSectionsAndGroups(); + final List groups = this.businessService.getSiteSectionsAndGroups(gradebookUid, siteId); // add the default 'all' group groups.add(0, new GbGroup(this.ALL_GROUPS, getString("groups.all"), this.ALL_GROUPS, GbGroup.Type.ALL)); @@ -194,7 +200,7 @@ protected void onUpdate(final AjaxRequestTarget target) { // If we have chosen a user, get the permissions // Need to parse the permission list to process the view_course_grade permission if (this.taSelected != null) { - final List permissions = this.businessService.getPermissionsForUser(this.taSelected.getUserUuid()); + final List permissions = this.businessService.getPermissionsForUser(this.taSelected.getUserUuid(), gradebookUid, siteId); final Iterator iter = permissions.iterator(); while (iter.hasNext()) { @@ -269,7 +275,7 @@ public void onSubmit() { // remove any dupes - we also present a message if dupes were removed final List distinctPermissions = permissions.stream().distinct().collect(Collectors.toList()); - PermissionsPage.this.businessService.updatePermissionsForUser(PermissionsPage.this.taSelected.getUserUuid(), + PermissionsPage.this.businessService.updatePermissionsForUser(gradebookUid, taSelected.getUserUuid(), distinctPermissions); getSession().success(getString("permissionspage.update.success")); @@ -312,7 +318,7 @@ public boolean isVisible() { @Override public void onSubmit() { String userUUID = PermissionsPage.this.taSelected.getUserUuid(); - businessService.clearPermissionsForUser(userUUID); + businessService.clearPermissionsForUser(gradebookUid, userUUID); getSession().success(getString("permissionspage.update.success")); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/QuickEntryPage.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/QuickEntryPage.java index 32533f2ff933..61230006befc 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/QuickEntryPage.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/QuickEntryPage.java @@ -45,17 +45,24 @@ public class QuickEntryPage extends BasePage { private ModalWindow bulkComment; private boolean noErrors = true; + private String gradebookUid; + private String siteId; + public QuickEntryPage() { disableLink(this.quickEntryPageLink); + + gradebookUid = getCurrentGradebookUid(); + siteId = getCurrentSiteId(); } @Override public void onInitialize() { super.onInitialize(); - Integer gradeType = this.businessService.getGradebookSettings().getGradeType(); + Integer gradeType = this.businessService.getGradebookSettings(gradebookUid, siteId).getGradeType(); + SortType sortBy = SortType.SORT_BY_NAME; - final List assignments = this.businessService.getGradebookAssignments(sortBy); + final List assignments = this.businessService.getGradebookAssignments(gradebookUid, siteId, sortBy); final DropDownChoice itempicker = new DropDownChoice("itempicker", new Model(),assignments, new ChoiceRenderer(){ private static final long serialVersionUID = 1L; @Override @@ -80,7 +87,7 @@ protected void onUpdate(final AjaxRequestTarget target) { setResponsePage(QuickEntryPage.class, pageParameters); // refresh this page with the selected item } }); - final List groups = this.businessService.getSiteSectionsAndGroups(); + final List groups = this.businessService.getSiteSectionsAndGroups(gradebookUid, siteId); final DropDownChoice groupFilter = new DropDownChoice("groupicker", new Model(), groups, new ChoiceRenderer() { private static final long serialVersionUID = 1L; @Override @@ -140,8 +147,8 @@ public void onSubmit(){ } if(noErrors){ //if still no errors, second loop to start saving things for(QuickEntryRowModel row: allgrades){ - String oldGrade = businessService.getGradeForStudentForItem(row.getStudentid(),itemId).getGrade(); - GradeSaveResponse succeeded = businessService.saveGrade(itemId,row.getStudentid(),oldGrade,row.getGrade(),row.getComment()); + String oldGrade = businessService.getGradeForStudentForItem(gradebookUid, siteId, row.getStudentid(),itemId).getGrade(); + GradeSaveResponse succeeded = businessService.saveGrade(gradebookUid, siteId, itemId,row.getStudentid(),oldGrade,row.getGrade(),row.getComment()); if(succeeded == GradeSaveResponse.ERROR || succeeded == GradeSaveResponse.CONCURRENT_EDIT){ getSession().error(MessageFormat.format(getString("quickentry.error"),row.getName())); row.setHasError(true); @@ -151,7 +158,7 @@ public void onSubmit(){ row.setHasError(false); } if(row.commentChanged()){ //in case a changed comment is with an unchanged/blank grade - boolean commentSucceeded = businessService.updateAssignmentGradeComment(itemId,row.getStudentid(),row.getComment()); + boolean commentSucceeded = businessService.updateAssignmentGradeComment(gradebookUid, siteId, itemId,row.getStudentid(),row.getComment()); if(!commentSucceeded){ getSession().error(MessageFormat.format(getString("quickentry.error"),row.getName())); row.setHasError(true); @@ -161,7 +168,7 @@ public void onSubmit(){ row.setHasError(false); } } - GradeSaveResponse succeededExcuse = businessService.saveExcuse(itemId,row.getStudentid(),row.isExcused()); + GradeSaveResponse succeededExcuse = businessService.saveExcuse(gradebookUid, siteId, itemId,row.getStudentid(),row.isExcused()); if(succeededExcuse == GradeSaveResponse.ERROR){ getSession().error(MessageFormat.format(getString("quickentry.error"),row.getName())); row.setHasError(true); @@ -210,10 +217,9 @@ public void onSubmit(){ form.add(new Label("itemdetails", itemdetails)); // The getUsers call will both sort and remove orphaned/invalid users - final List gradableUserIds = this.businessService.getGradeableUsers(); + final List gradableUserIds = this.businessService.getGradeableUsers(gradebookUid, siteId, null); final List gradableUsers = this.businessService.getUsers(gradableUserIds); - Map> groupContainer = this.businessService.getGroupMemberships(); - + Map> groupContainer = this.businessService.getGroupMemberships(gradebookUid, siteId); List rows = new ArrayList<>(); int totalstudents = 0; @@ -222,12 +228,12 @@ public void onSubmit(){ final String uid = userNow.getId(); QuickEntryRowModel rowNow = new QuickEntryRowModel(); totalstudents++; - if(!params.get("groupNow").isNull() && !groupContainer.get("/site/" + this.businessService.getCurrentSiteId() + "/group/"+params.get("groupNow").toString()).contains(uid)){ + if(!params.get("groupNow").isNull() && !groupContainer.get("/site/" + getCurrentSiteId() + "/group/"+params.get("groupNow").toString()).contains(uid)){ continue; } studentsnow++; rowNow.setName(userNow.getLastName() + ", " + userNow.getFirstName() + " (" + userNow.getDisplayId() + ')'); - String commentNow = this.businessService.getAssignmentGradeComment(this.assignmentNow.getId(),uid); + String commentNow = this.businessService.getAssignmentGradeComment(gradebookUid, this.assignmentNow.getId(),uid); if(commentNow != null){ rowNow.setComment(commentNow); rowNow.setOriginalComment(commentNow); @@ -237,9 +243,10 @@ public void onSubmit(){ // this field, we need to set it to null rowNow.setOriginalComment(null); } - String gradeNow = this.businessService.getGradeForStudentForItem(uid,this.assignmentNow.getId()).getGrade(); + + String gradeNow = this.businessService.getGradeForStudentForItem(gradebookUid, siteId, uid, this.assignmentNow.getId()).getGrade(); rowNow.setGrade(StringUtils.defaultIfBlank(gradeNow, null)); - rowNow.setExcused(!Objects.equals(this.businessService.getAssignmentExcuse(this.assignmentNow.getId(), uid), "0")); + rowNow.setExcused(!Objects.equals(this.businessService.getAssignmentExcuse(gradebookUid, this.assignmentNow.getId(),uid), "0")); rowNow.setLocked(this.assignmentNow.getExternallyMaintained()); rowNow.setMaxGrade(this.assignmentNow.getPoints()); rowNow.setStudentid(uid); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/SettingsPage.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/SettingsPage.java index 4861be3743af..374611152a2a 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/SettingsPage.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/SettingsPage.java @@ -68,12 +68,18 @@ public class SettingsPage extends BasePage { private SettingsCategoryPanel categoryPanel; private SettingsGradingSchemaPanel gradingSchemaPanel; + private String gradebookUid; + private String siteId; + public SettingsPage() { defaultRoleChecksForInstructorOnlyPage(); disableLink(this.settingsPageLink); setShowGradeEntryToNonAdmins(); + + gradebookUid = getCurrentGradebookUid(); + siteId = getCurrentSiteId(); } public SettingsPage(final boolean gradeEntryExpanded, final boolean gradeReleaseExpanded, final boolean statisticsExpanded, @@ -97,7 +103,7 @@ public void onInitialize() { super.onInitialize(); // get settings data - final GradebookInformation settings = this.businessService.getGradebookSettings(); + final GradebookInformation settings = this.businessService.getGradebookSettings(gradebookUid, siteId); // setup page model final GbSettings gbSettings = new GbSettings(settings); @@ -108,6 +114,7 @@ public void onInitialize() { this.statisticsPanel = new SettingsStatisticsPanel("statisticsPanel", formModel, this.statisticsExpanded); this.categoryPanel = new SettingsCategoryPanel("categoryPanel", formModel, this.categoryExpanded); this.gradingSchemaPanel = new SettingsGradingSchemaPanel("gradingSchemaPanel", formModel, this.gradingSchemaExpanded); + gradingSchemaPanel.setCurrentGradebookAndSite(gradebookUid, siteId); // Hide the panel if not showing to non admins and user is not admin if (!this.showGradeEntryToNonAdmins && !this.businessService.isSuperUser()) { @@ -226,7 +233,7 @@ public void onSubmit(final AjaxRequestTarget target) { // update settings try { - SettingsPage.this.businessService.updateGradebookSettings(model.getGradebookInformation()); + SettingsPage.this.businessService.updateGradebookSettings(gradebookUid, siteId, model.getGradebookInformation()); getSession().success(getString("settingspage.update.success")); } catch (final ConflictingCategoryNameException e) { getSession().error(getString("settingspage.update.failure.categorynameconflict")); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/StudentPage.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/StudentPage.java index 16a1a82df2a3..b3849d82b81a 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/StudentPage.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/pages/StudentPage.java @@ -42,22 +42,30 @@ public class StudentPage extends BasePage { private static final long serialVersionUID = 1L; + private String gradebookUid; + private String siteId; + public StudentPage() { if (role == GbRole.NONE) { sendToAccessDeniedPage(getString("error.role")); } - final User u = this.businessService.getCurrentUser(); + gradebookUid = getCurrentGradebookUid(); + siteId = getCurrentSiteId(); + + final User u = getCurrentUser(); final Map userData = new HashMap<>(); userData.put("studentUuid", u.getId()); userData.put("groupedByCategoryByDefault", true); add(new Label("heading", new StringResourceModel("heading.studentpage").setParameters(u.getDisplayName()))); - add(new StudentGradeSummaryGradesPanel("summary", Model.ofMap(userData))); + StudentGradeSummaryGradesPanel sgsgp = new StudentGradeSummaryGradesPanel("summary", Model.ofMap(userData)); + sgsgp.setCurrentGradebookAndSite(gradebookUid, siteId); + add(sgsgp); - EventHelper.postStudentViewEvent(this.businessService.getGradebook(), u.getId()); + EventHelper.postStudentViewEvent(this.businessService.getGradebook(gradebookUid, siteId), u.getId()); } @Override diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanel.java index dcd80d1a5205..d9aae6d75355 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanel.java @@ -73,13 +73,18 @@ public AddOrEditGradeItemPanel(final String id, final GbModalWindow window, fina } else { this.mode = UiMode.ADD; } + } + + @Override + public void onInitialize() { + super.onInitialize(); // setup the backing object Assignment assignment; if (this.mode == UiMode.EDIT) { final Long assignmentId = this.model.getObject(); - assignment = this.businessService.getAssignment(assignmentId); + assignment = this.businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); // TODO if we are in edit mode and don't have an assignment, need to error here @@ -89,7 +94,7 @@ public AddOrEditGradeItemPanel(final String id, final GbModalWindow window, fina // Default released to true assignment.setReleased(true); // If no categories, then default counted to true - final Gradebook gradebook = this.businessService.getGradebook(); + final Gradebook gradebook = this.businessService.getGradebook(currentGradebookUid, currentSiteId); assignment.setCounted(Objects.equals(GradingConstants.CATEGORY_TYPE_NO_CATEGORY, gradebook.getCategoryType())); } @@ -138,7 +143,9 @@ public boolean isVisible() { form.add(createAnother); // add the common components - form.add(new AddOrEditGradeItemPanelContent("subComponents", formModel, this.mode)); + AddOrEditGradeItemPanelContent aegipc = new AddOrEditGradeItemPanelContent("subComponents", formModel, this.mode); + aegipc.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + form.add(aegipc); // feedback panel form.add(new GbFeedbackPanel("addGradeFeedback")); @@ -180,7 +187,7 @@ private void createGradeItem(final AjaxRequestTarget target, final Form form, // 1. if category selected and drop/keep highest/lowest selected for that category, // ensure points match the already established maximum for the category. if (assignment.getCategoryId() != null) { - final List categories = AddOrEditGradeItemPanel.this.businessService.getGradebookCategories(); + final List categories = AddOrEditGradeItemPanel.this.businessService.getGradebookCategories(currentGradebookUid, currentSiteId); final CategoryDefinition category = categories .stream() .filter(c -> (c.getId().equals(assignment.getCategoryId())) @@ -225,10 +232,10 @@ private void createGradeItem(final AjaxRequestTarget target, final Form form, try { if (AddOrEditGradeItemPanel.this.mode == UiMode.EDIT) { assignmentId = assignment.getId(); - AddOrEditGradeItemPanel.this.businessService.updateAssignment(assignment); + AddOrEditGradeItemPanel.this.businessService.updateAssignment(currentGradebookUid, currentSiteId, assignment); } else { - assignmentId = AddOrEditGradeItemPanel.this.businessService.addAssignment(assignment); + assignmentId = AddOrEditGradeItemPanel.this.businessService.addAssignment(currentGradebookUid, currentSiteId, assignment); } Map rubricParams = getRubricParameters(""); if (!rubricParams.isEmpty()) { @@ -267,6 +274,7 @@ private void createGradeItem(final AjaxRequestTarget target, final Form form, if (createAnother) { final Component newFormPanel = new AddOrEditGradeItemPanel(this.window.getContentId(), this.window, null); + ((AddOrEditGradeItemPanel)newFormPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); AddOrEditGradeItemPanel.this.replaceWith(newFormPanel); this.window.setAssignmentToReturnFocusTo(String.valueOf(assignmentId)); this.window.clearWindowClosedCallbacks(); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanelContent.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanelContent.java index d8ecc73adaf9..4fe97d7850af 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanelContent.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AddOrEditGradeItemPanelContent.java @@ -77,18 +77,24 @@ public class AddOrEditGradeItemPanelContent extends BasePanel { private Double existingPoints = null; private boolean scaleGradesTriggered = false; private WebMarkupContainer scaleGradesContainer; + private final Model assignmentModel; public AddOrEditGradeItemPanelContent(final String id, final Model assignmentModel, final UiMode mode) { super(id, assignmentModel); + this.assignmentModel = assignmentModel; + } - final Gradebook gradebook = this.businessService.getGradebook(); + @Override + public void onInitialize() { + super.onInitialize(); + final Gradebook gradebook = this.businessService.getGradebook(currentGradebookUid, currentSiteId); final Integer gradingType = gradebook.getGradeType(); final Assignment assignment = assignmentModel.getObject(); this.categoriesEnabled = !Objects.equals(GradingConstants.CATEGORY_TYPE_NO_CATEGORY, gradebook.getCategoryType()); // get existing points. Will be null for a new assignment - this.existingPoints = assignmentModel.getObject().getPoints(); + this.existingPoints = assignment.getPoints(); // title final TextField title = new TextField("title", @@ -194,7 +200,7 @@ public boolean isEnabled() { final Map categoryMap = new LinkedHashMap<>(); if (this.categoriesEnabled) { - categories.addAll(this.businessService.getGradebookCategories()); + categories.addAll(this.businessService.getGradebookCategories(currentGradebookUid, currentSiteId)); for (final CategoryDefinition category : categories) { categoryMap.put(category.getId(), category); @@ -303,7 +309,7 @@ protected void onUpdate(final AjaxRequestTarget target) { // counted this.counted = new CheckBox("counted", new PropertyModel(assignmentModel, "counted")); this.counted.setOutputMarkupId(true); - if (this.businessService.categoriesAreEnabled()) { + if (this.businessService.categoriesAreEnabled(currentGradebookUid, currentSiteId)) { this.counted.setEnabled(assignment.getCategoryId() != null); if (assignment.getCategoryId() == null) { this.counted.setModelObject(false); @@ -333,7 +339,7 @@ protected void onUpdate(final AjaxRequestTarget target) { } target.add(extraCredit); - if (AddOrEditGradeItemPanelContent.this.businessService.categoriesAreEnabled()) { + if (AddOrEditGradeItemPanelContent.this.businessService.categoriesAreEnabled(currentGradebookUid, currentSiteId)) { if (category == null) { AddOrEditGradeItemPanelContent.this.counted.setEnabled(false); AddOrEditGradeItemPanelContent.this.counted.setModelObject(false); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AssignmentStatisticsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AssignmentStatisticsPanel.java index 53c655d69cb0..fc394602566b 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AssignmentStatisticsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/AssignmentStatisticsPanel.java @@ -46,12 +46,13 @@ public void onInitialize() { final Long assignmentId = ((Model) getDefaultModel()).getObject(); - final Assignment assignment = this.businessService.getAssignment(assignmentId.longValue()); + final Assignment assignment = this.businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId.longValue()); AssignmentStatisticsPanel.this.window.setTitle( new StringResourceModel("label.statistics.title.assignment").setParameters(assignment.getName()).getString()); final AssignmentGradeChart chart = new AssignmentGradeChart("gradingSchemaChart", assignmentId, null); + chart.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); add(chart); final AssignmentStatistics stats = new AssignmentStatistics("stats", getData(assignment)); @@ -76,7 +77,10 @@ public void onClick(final AjaxRequestTarget target) { */ private IModel> getData(final Assignment assignment) { final Map data = new HashMap<>(); - data.put("gradeInfo", this.businessService.buildGradeMatrix(Arrays.asList(assignment))); + data.put("gradeInfo", this.businessService.buildGradeMatrix(currentGradebookUid, currentSiteId, + Arrays.asList(assignment), + businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null), + null)); data.put("assignmentId", assignment.getId()); return Model.ofMap(data); } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BasePanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BasePanel.java index d0953bbb7a92..2d015d466544 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BasePanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BasePanel.java @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Properties; import org.apache.wicket.RestartResponseException; import org.apache.wicket.markup.html.panel.Panel; @@ -32,12 +33,15 @@ import org.sakaiproject.gradebookng.business.GbRole; import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; import org.sakaiproject.gradebookng.business.exception.GbAccessDeniedException; -import org.sakaiproject.gradebookng.business.util.MessageHelper; import org.sakaiproject.gradebookng.tool.pages.AccessDeniedPage; import org.sakaiproject.grading.api.GradebookInformation; +import org.sakaiproject.grading.api.MessageHelper; import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.rubrics.api.RubricsConstants; import org.sakaiproject.rubrics.api.RubricsService; +import org.sakaiproject.tool.api.Placement; +import org.sakaiproject.tool.api.ToolManager; +import org.sakaiproject.util.ResourceLoader; /** * Panel extension to abstract away some common functionality that many GBNG panels share. Classes extending {@link BasePanel} do not need @@ -62,12 +66,20 @@ public abstract class BasePanel extends Panel { @SpringBean(name = "org.sakaiproject.component.api.ServerConfigurationService") protected ServerConfigurationService serverConfigService; + @SpringBean(name = "org.sakaiproject.tool.api.ToolManager") + protected ToolManager toolManager; + protected static final String SAK_PROP_SHOW_COURSE_GRADE_STUDENT = "gradebookng.showDisplayCourseGradeToStudent"; protected static final Boolean SAK_PROP_SHOW_COURSE_GRADE_STUDENT_DEFAULT = Boolean.TRUE; protected static final String SAK_PROP_ALLOW_COMPARE_GRADES = "gradebookng.allowStudentsToCompareGradesWithClassmates"; protected static final Boolean SAK_PROP_ALLOW_COMPARE_GRADES_DEFAULT = Boolean.FALSE; + protected String currentGradebookUid; + protected String currentSiteId; + + private static ResourceLoader RL = new ResourceLoader(); + public BasePanel(final String id) { super(id); } @@ -85,10 +97,10 @@ protected GbRole getUserRole() { GbRole role; try { - role = this.businessService.getUserRole(); + role = this.businessService.getUserRole(getCurrentSiteId()); } catch (final GbAccessDeniedException e) { final PageParameters params = new PageParameters(); - params.add("message", MessageHelper.getString("error.role")); + params.add("message", MessageHelper.getString("error.role", RL.getLocale())); throw new RestartResponseException(AccessDeniedPage.class, params); } return role; @@ -109,7 +121,11 @@ protected String getCurrentUserId() { * @return */ protected String getCurrentSiteId() { - return this.businessService.getCurrentSiteId(); + try { + return this.toolManager.getCurrentPlacement().getContext(); + } catch (final Exception e) { + return null; + } } /** @@ -118,7 +134,26 @@ protected String getCurrentSiteId() { * @return */ protected Gradebook getGradebook() { - return this.businessService.getGradebook(); + if (currentGradebookUid == null || currentSiteId == null) { + throw new RuntimeException("Error trying to get settings of gradebook with null value"); + } + return this.businessService.getGradebook(currentGradebookUid, currentSiteId); + } + + protected String getCurrentGradebookUid() { + String gradebookUid = getCurrentSiteId(); + Placement placement = toolManager.getCurrentPlacement(); + Properties props = placement.getPlacementConfig(); + if (props.getProperty("gb-group") != null) { + gradebookUid = props.getProperty("gb-group"); + } + + return gradebookUid; + } + + public void setCurrentGradebookAndSite(String gUid, String siteId) { + currentGradebookUid = gUid; + currentSiteId = siteId; } /** @@ -127,7 +162,10 @@ protected Gradebook getGradebook() { * @return */ protected GradebookInformation getSettings() { - return this.businessService.getGradebookSettings(); + if (currentGradebookUid == null || currentSiteId == null) { + throw new RuntimeException("Error trying to get settings of gradebook with null value"); + } + return this.businessService.getGradebookSettings(currentGradebookUid, currentSiteId); } /** diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BulkEditItemsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BulkEditItemsPanel.java index 1e62e74f8d41..cfdca8cde240 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BulkEditItemsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/BulkEditItemsPanel.java @@ -39,6 +39,7 @@ import org.sakaiproject.portal.util.PortalUtils; import org.sakaiproject.grading.api.Assignment; import org.sakaiproject.grading.api.CategoryDefinition; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.wicket.component.SakaiAjaxButton; import lombok.extern.slf4j.Slf4j; @@ -60,8 +61,8 @@ public void clearDeletableItemsList () { this.deletableItemsList.clear(); } - public BulkEditItemsPanel(final String id, final IModel model, final ModalWindow window) { - super(id, model); + public BulkEditItemsPanel(final String id, final ModalWindow window) { + super(id); this.window = window; } @@ -69,9 +70,7 @@ public BulkEditItemsPanel(final String id, final IModel model, final Mod public void onInitialize() { super.onInitialize(); - final String siteId = (String) getDefaultModelObject(); - - final List assignments = this.businessService.getGradebookAssignments(siteId); + final List assignments = this.businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, SortType.SORT_BY_SORTING); final IModel> model = new ListModel<>(assignments); @@ -117,7 +116,7 @@ protected void onUpdate(AjaxRequestTarget target) { // Are there categories in this Gradebook? If so, and this item is not in a category, disabled grade // calculation inclusion. - List categories = businessService.getGradebookCategories(); + List categories = businessService.getGradebookCategories(currentGradebookUid, currentSiteId); if (categories != null && !categories.isEmpty() && StringUtils.isBlank(assignment.getCategoryName())) { include.setEnabled(false); } @@ -166,12 +165,12 @@ public void onSubmit(final AjaxRequestTarget target) { for (final Assignment a : assignments) { log.debug("Bulk edit assignment: {}", a); - BulkEditItemsPanel.this.businessService.updateAssignment(a); + BulkEditItemsPanel.this.businessService.updateAssignment(currentGradebookUid, currentSiteId, a); } List deletableItems = BulkEditItemsPanel.this.getDeletableItemsList(); int deleteCount = deletableItems.size(); for (int count=0; count < deleteCount; count++) { - BulkEditItemsPanel.this.businessService.removeAssignment(deletableItems.get(count)); + BulkEditItemsPanel.this.businessService.removeAssignment(currentGradebookUid, currentSiteId, deletableItems.get(count)); } getSession().success(getString("bulkedit.update.success")); if (deleteCount > 0) { diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeBreakdownPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeBreakdownPanel.java index 6c254fb9cfa5..600e4dbd99f2 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeBreakdownPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeBreakdownPanel.java @@ -24,7 +24,6 @@ import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.StringResourceModel; @@ -50,7 +49,7 @@ /** * Created by David P. Bauer [dbauer1@udayton.edu] on 8/1/17. */ -public class CourseGradeBreakdownPanel extends Panel { +public class CourseGradeBreakdownPanel extends BasePanel { private static final long serialVersionUID = 1L; private final Integer gradeType; @@ -72,9 +71,9 @@ public List getDeletableItemsList () { public CourseGradeBreakdownPanel(final String id, final ModalWindow window) { super(id); this.window = window; - this.weightedCategories = Objects.equals(this.businessService.getGradebookSettings().getCategoryType(), GradingConstants.CATEGORY_TYPE_WEIGHTED_CATEGORY); + this.weightedCategories = Objects.equals(this.businessService.getGradebookSettings(currentGradebookUid, currentSiteId).getCategoryType(), GradingConstants.CATEGORY_TYPE_WEIGHTED_CATEGORY); add(new GbFeedbackPanel("items-feedback")); - this.gradeType = this.businessService.getGradebook().getGradeType(); + this.gradeType = this.businessService.getGradebook(currentGradebookUid, currentSiteId).getGradeType(); } @Override @@ -95,7 +94,7 @@ protected List load() { final ListView itemListView = new ListView<>("items", loadableItemList) { private static final long serialVersionUID = 1L; - int studentCount = businessService.getGradeableUsers().size(); + int studentCount = businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null).size(); @Override protected void populateItem(ListItem item) { @@ -149,7 +148,10 @@ public boolean isVisible() { // We know this is an assignment item.add(new Label("out-of-label", assignment.getPoints())); final List allGrades = new ArrayList<>(); - final List gradeInfo = businessService.buildGradeMatrix(Collections.singletonList(assignment)); + final List gradeInfo = businessService.buildGradeMatrix(currentGradebookUid, currentSiteId, + Collections.singletonList(assignment), + businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null), + null); for (final GbStudentGradeInfo studentGradeInfo : gradeInfo) { final Map studentGrades = studentGradeInfo.getGrades(); final GbGradeInfo grade = studentGrades.get(gbItem.getItemId()); @@ -221,15 +223,18 @@ private int countNumberofGradedAssignments(List grades, long private List getItemsList() { SortType sortBy = SortType.SORT_BY_SORTING; final List itemList = new ArrayList<>(); - if (this.businessService.categoriesAreEnabled()) { + if (this.businessService.categoriesAreEnabled(currentGradebookUid, currentSiteId)) { sortBy = SortType.SORT_BY_CATEGORY; // Returns a sorted list of all categories in the Gradebook - final List categories = this.businessService.getGradebookCategories(); + final List categories = this.businessService.getGradebookCategories(currentGradebookUid, currentSiteId); for (CategoryDefinition categoryDefinition : categories) { Double totalCategoryPoints = 0D; // Get sorted list of assignments for the category. - final List assignmentList = this.businessService.getGradebookAssignmentsForCategory(categoryDefinition.getId(), sortBy); - final List grades = this.businessService.buildGradeMatrix(assignmentList); + final List assignmentList = this.businessService.getGradebookAssignmentsForCategory(currentGradebookUid, currentSiteId, categoryDefinition.getId(), sortBy); + final List grades = this.businessService.buildGradeMatrix(currentGradebookUid, currentSiteId, + assignmentList, + businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null), + null); final List tempList = new ArrayList<>(); int numberToDrop = 0; int numberToKeep = assignmentList.size(); @@ -258,10 +263,13 @@ private List getItemsList() { // Add all assignments in the category itemList.addAll(tempList); } - final List uncategorizedAssignments = this.businessService.getGradebookAssignmentsForCategory(null, sortBy); + final List uncategorizedAssignments = this.businessService.getGradebookAssignmentsForCategory(currentGradebookUid, currentSiteId, null, sortBy); if (uncategorizedAssignments != null && !uncategorizedAssignments.isEmpty()) { final List uncategorizedGbItems = new ArrayList<>(); - final List grades = this.businessService.buildGradeMatrix(uncategorizedAssignments); + final List grades = this.businessService.buildGradeMatrix(currentGradebookUid, currentSiteId, + uncategorizedAssignments, + businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null), + null); for (Assignment assignment : uncategorizedAssignments) { uncategorizedGbItems.add(new GbBreakdownItem(assignment.getId(), null, assignment, null, countNumberofGradedAssignments(grades, assignment.getId()))); } @@ -275,8 +283,11 @@ private List getItemsList() { } } else { // Categories are not enabled so just add all assignments to the list. - final List allAssignments = this.businessService.getGradebookAssignments(sortBy); - final List grades = this.businessService.buildGradeMatrix(allAssignments); + final List allAssignments = this.businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, sortBy); + final List grades = this.businessService.buildGradeMatrix(currentGradebookUid, currentSiteId, + allAssignments, + businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null), + null); for (final Assignment assignment : allAssignments) { itemList.add(new GbBreakdownItem(assignment.getId(), null, assignment, null, countNumberofGradedAssignments(grades, assignment.getId()))); if (assignment.getCounted() && !assignment.getExtraCredit()) { @@ -293,7 +304,7 @@ private String constructAverageLabel(final List allGrades, final Assignm } private String constructCategoryAverageLabel(final CategoryDefinition category) { - final List allAssignmentGrades = businessService.getCategoryAssignmentTotals(category, null); + final List allAssignmentGrades = businessService.getCategoryAssignmentTotals(currentGradebookUid, currentSiteId, category, null); if(allAssignmentGrades.size() > 0){ final double average = businessService.calculateAverage(allAssignmentGrades); return FormatHelper.formatDoubleAsPercentage(100 * (average / 100)); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverrideLogPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverrideLogPanel.java index 87a088b92e1a..1ccedf9e5308 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverrideLogPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverrideLogPanel.java @@ -65,7 +65,7 @@ public void onInitialize() { .setEscapeModelStrings(false); // get the course grade - final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(studentUuid); + final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(currentGradebookUid, currentSiteId, studentUuid); // get the events List gradeLog; diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverridePanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverridePanel.java index f76adb38141f..1ffca224663b 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverridePanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeOverridePanel.java @@ -74,9 +74,9 @@ public void onInitialize() { final Locale currentUserLocale = this.businessService.getUserPreferredLocale(); final GbRole currentUserRole = getUserRole(); final Gradebook gradebook = getGradebook(); - final boolean courseGradeVisible = this.businessService.isCourseGradeVisible(currentUserUuid); + final boolean courseGradeVisible = this.businessService.isCourseGradeVisible(currentGradebookUid, currentSiteId, currentUserUuid); - final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(studentUuid); + final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(currentGradebookUid, currentSiteId, studentUuid); final CourseGradeFormatter courseGradeFormatter = new CourseGradeFormatter( gradebook, currentUserRole, @@ -118,7 +118,7 @@ public void onSubmit(final AjaxRequestTarget target) { // validate the grade entered is a valid one for the selected grading schema // though we allow blank grades so the override is removed // Note: validation is not enforced for final grade mode - final GradebookInformation gbInfo = CourseGradeOverridePanel.this.businessService.getGradebookSettings(); + final GradebookInformation gbInfo = CourseGradeOverridePanel.this.businessService.getGradebookSettings(currentGradebookUid, currentSiteId); if (StringUtils.isNotBlank(newGrade)) { final Map schema = gbInfo.getSelectedGradingScaleBottomPercents(); @@ -140,7 +140,7 @@ public void onSubmit(final AjaxRequestTarget target) { } // save - final boolean success = CourseGradeOverridePanel.this.businessService.updateCourseGrade(studentUuid, newGrade, gradeScale); + final boolean success = CourseGradeOverridePanel.this.businessService.updateCourseGrade(currentGradebookUid, currentSiteId, studentUuid, newGrade, gradeScale); if (success) { getSession().success(getString("message.addcoursegradeoverride.success")); @@ -175,7 +175,7 @@ public void onSubmit(final AjaxRequestTarget target) { @Override public void onSubmit(final AjaxRequestTarget target) { - final boolean success = CourseGradeOverridePanel.this.businessService.updateCourseGrade(studentUuid, null, null); + final boolean success = CourseGradeOverridePanel.this.businessService.updateCourseGrade(currentGradebookUid, currentSiteId, studentUuid, null, null); if (success) { getSession().success(getString("message.addcoursegradeoverride.success")); setResponsePage(getPage().getPageClass()); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeStatisticsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeStatisticsPanel.java index a5a119d47ef6..1779d8e0ada1 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeStatisticsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/CourseGradeStatisticsPanel.java @@ -16,6 +16,7 @@ package org.sakaiproject.gradebookng.tool.panels; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -37,8 +38,8 @@ public class CourseGradeStatisticsPanel extends BasePanel { private final ModalWindow window; - public CourseGradeStatisticsPanel(final String id, final IModel model, final ModalWindow window) { - super(id, model); + public CourseGradeStatisticsPanel(final String id, final ModalWindow window) { + super(id); this.window = window; } @@ -47,14 +48,13 @@ public CourseGradeStatisticsPanel(final String id, final IModel model, f public void onInitialize() { super.onInitialize(); - final String siteId = ((Model) getDefaultModel()).getObject(); - CourseGradeStatisticsPanel.this.window.setTitle(new ResourceModel("label.statistics.title.coursegrade")); - final CourseGradeChart chart = new CourseGradeChart("gradingSchemaChart", siteId, null); + final CourseGradeChart chart = new CourseGradeChart("gradingSchemaChart", null); + chart.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); add(chart); - final CourseGradeStatistics stats = new CourseGradeStatistics("stats", getData(siteId)); + final CourseGradeStatistics stats = new CourseGradeStatistics("stats", getData()); add(stats); add(new GbAjaxLink("done") { @@ -70,14 +70,14 @@ public void onClick(final AjaxRequestTarget target) { /** * Get the course grade data for the site and wrap it * - * @param siteId siteId to get data for * @return */ - private IModel> getData(final String siteId) { + private IModel> getData() { final Map data = new HashMap<>(); - data.put("courseGradeMap", this.businessService.getCourseGrades(siteId)); + final List studentUuids = this.businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null); + data.put("courseGradeMap", this.businessService.getCourseGrades(currentGradebookUid, currentSiteId, studentUuids, null)); - final GradebookInformation info = this.businessService.getGradebookSettings(siteId); + final GradebookInformation info = this.businessService.getGradebookSettings(currentGradebookUid, currentSiteId);; data.put("gradingSchemaName", info.getGradeScale()); data.put("bottomPercents", info.getSelectedGradingScaleBottomPercents()); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/DeleteItemPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/DeleteItemPanel.java index 7854d38d77df..a99b69b954be 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/DeleteItemPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/DeleteItemPanel.java @@ -50,7 +50,7 @@ public void onInitialize() { final Form form = new Form<>("form", Model.of(assignmentId)); - final Assignment assignment = DeleteItemPanel.this.businessService.getAssignment(assignmentId); + final Assignment assignment = DeleteItemPanel.this.businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); final String assignmentTitle = assignment.getName(); form.add(new Label("confirmationMessage", new StringResourceModel( "delete.warning").setParameters(assignmentTitle)).setEscapeModelStrings(false)); @@ -61,10 +61,10 @@ public void onInitialize() { public void onSubmit(final AjaxRequestTarget target) { final Long assignmentIdToDelete = form.getModelObject(); - final Assignment assignment = DeleteItemPanel.this.businessService.getAssignment(assignmentIdToDelete); + final Assignment assignment = DeleteItemPanel.this.businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentIdToDelete); final String assignmentTitle = assignment.getName(); - DeleteItemPanel.this.businessService.removeAssignment(assignmentIdToDelete); + DeleteItemPanel.this.businessService.removeAssignment(currentGradebookUid, currentSiteId, assignmentIdToDelete); getSession().success(MessageFormat.format(getString("delete.success"), assignmentTitle)); setResponsePage(GradebookPage.class); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditCourseGradeCommentPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditCourseGradeCommentPanel.java index 2e9c31d7ef4e..ac039873e25f 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditCourseGradeCommentPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditCourseGradeCommentPanel.java @@ -51,7 +51,7 @@ public void onInitialize() { final String studentUuid = (String) modelData.get("studentUuid"); final Long gradebookId = (Long) modelData.get("gradebookId"); // fetch current comment - this.comment = this.businessService.getAssignmentGradeComment(businessService.getCurrentSiteId(), courseGradeId, studentUuid); + this.comment = this.businessService.getAssignmentGradeComment(currentGradebookUid, courseGradeId, studentUuid); // form model final GradeComment gradeComment = new GradeComment(); gradeComment.setGradeComment(this.comment); @@ -64,7 +64,7 @@ public void onInitialize() { @Override public void onSubmit(final AjaxRequestTarget target) { final GradeComment updatedComment = (GradeComment) form.getModelObject(); - final boolean success = EditCourseGradeCommentPanel.this.businessService.updateAssignmentGradeComment(businessService.getCourseGradeId(gradebookId), studentUuid, updatedComment.getGradeComment()); + final boolean success = businessService.updateAssignmentGradeComment(currentGradebookUid, currentSiteId, businessService.getCourseGradeId(gradebookId), studentUuid, updatedComment.getGradeComment()); if (success) { // update member var EditCourseGradeCommentPanel.this.comment = updatedComment.getGradeComment(); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditGradeCommentPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditGradeCommentPanel.java index 281e049d26d9..fc2ae418a75e 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditGradeCommentPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/EditGradeCommentPanel.java @@ -75,7 +75,7 @@ public void onInitialize() { final String studentUuid = (String) modelData.get("studentUuid"); // fetch current comment - this.comment = this.businessService.getAssignmentGradeComment(assignmentId, studentUuid); + this.comment = this.businessService.getAssignmentGradeComment(currentGradebookUid, assignmentId, studentUuid); // form model final GradeComment gradeComment = new GradeComment(); @@ -94,7 +94,7 @@ public void onSubmit(final AjaxRequestTarget target) { final GradeComment updatedComment = (GradeComment) form.getModelObject(); - final boolean success = EditGradeCommentPanel.this.businessService.updateAssignmentGradeComment(assignmentId, studentUuid, + final boolean success = EditGradeCommentPanel.this.businessService.updateAssignmentGradeComment(currentGradebookUid, currentSiteId, assignmentId, studentUuid, updatedComment.getGradeComment()); if (success) { @@ -134,7 +134,7 @@ public void onSubmit(final AjaxRequestTarget target) { // heading // TODO if user/assignment has been deleted since rendering the GradebookPage, handle nulls here gracefully final GbUser user = this.businessService.getUser(studentUuid); - final Assignment assignment = this.businessService.getAssignment(assignmentId); + final Assignment assignment = this.businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); EditGradeCommentPanel.this.window.setTitle( (new StringResourceModel("heading.editcomment") .setParameters(user.getDisplayName(), user.getDisplayId(), assignment.getName())).getString()) diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/GradeSummaryTablePanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/GradeSummaryTablePanel.java index 8595fd46547b..7057cff232f0 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/GradeSummaryTablePanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/GradeSummaryTablePanel.java @@ -266,12 +266,13 @@ protected void populateItem(final ListItem assignmentItem) { public void onClick( final AjaxRequestTarget target) { - assignmentStatsWindow.setContent( - new StudentAssignmentStatisticsPanel( + StudentAssignmentStatisticsPanel sasp = new StudentAssignmentStatisticsPanel( assignmentStatsWindow .getContentId(), Model.of(assignment), - assignmentStatsWindow, rawGrade)); + assignmentStatsWindow, rawGrade); + sasp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + assignmentStatsWindow.setContent(sasp); assignmentStatsWindow.show(target); } @@ -289,13 +290,13 @@ public boolean isVisible() { @Override public void onClick(AjaxRequestTarget target) { assignment.getId(); - compareGradesWindow.setContent( - new StudentCompareGradesPanel( + StudentCompareGradesPanel scgp = new StudentCompareGradesPanel( compareGradesWindow.getContentId(), Model.of(assignment), compareGradesWindow - ) ); + scgp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + compareGradesWindow.setContent(scgp); compareGradesWindow.show(target); } @@ -496,7 +497,7 @@ private void addInstructorAttributeOrHide(WebMarkupContainer sakaiRubricButton, || GradeSummaryTablePanel.this.getUserRole() == GbRole.TA)) { sakaiRubricButton.add(AttributeModifier.append("instructor", true)); } else { - GradeDefinition gradeDefinition = businessService.getGradeForStudentForItem(studentId, assignment.getId()); + GradeDefinition gradeDefinition = businessService.getGradeForStudentForItem(currentGradebookUid, currentSiteId, studentId, assignment.getId()); if (assignment.getExternallyMaintained() && gradeDefinition.getGrade() == null) { sakaiRubricButton.add(AttributeModifier.replace("force-preview", true)); } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/InstructorGradeSummaryGradesPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/InstructorGradeSummaryGradesPanel.java index 364e0a5f6dd7..ddc287a5b78b 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/InstructorGradeSummaryGradesPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/InstructorGradeSummaryGradesPanel.java @@ -57,7 +57,7 @@ public InstructorGradeSummaryGradesPanel(final String id, final IModel assignments = this.businessService.getGradebookAssignmentsForStudent(userId, sortedBy); + final List assignments = this.businessService.getGradebookAssignmentsForStudent(currentGradebookUid, currentSiteId, userId, sortedBy); - final boolean isCourseGradeVisible = this.businessService.isCourseGradeVisible(this.businessService.getCurrentUser().getId()); + final boolean isCourseGradeVisible = this.businessService.isCourseGradeVisible(currentGradebookUid, currentSiteId, this.businessService.getCurrentUser().getId()); final GbRole userRole = gradebookPage.getCurrentRole(); final CourseGradeFormatter courseGradeFormatter = new CourseGradeFormatter( @@ -98,7 +98,7 @@ public void onBeforeRender() { // TODO catch if this is null, the get(0) will throw an exception // TODO also catch the GbException final GbStudentGradeInfo studentGradeInfo = this.businessService - .buildGradeMatrix( + .buildGradeMatrix(currentGradebookUid, currentSiteId, assignments, new ArrayList<>(Arrays.asList(userId)), // needs to support #remove gradebookPage.getUiSettings()) @@ -122,7 +122,7 @@ public void onBeforeRender() { categoryNamesToAssignments.get(categoryName).add(assignment); } - Map categoriesMap = businessService.getGradebookCategories().stream() + Map categoriesMap = businessService.getGradebookCategories(currentGradebookUid, currentSiteId).stream() .collect(Collectors.toMap(cat -> cat.getName(), cat -> cat)); // build the model for table @@ -139,15 +139,17 @@ public void onBeforeRender() { tableModel.put("categoriesMap", categoriesMap); tableModel.put("studentUuid", userId); - addOrReplace(new GradeSummaryTablePanel("gradeSummaryTable", new LoadableDetachableModel>() { + GradeSummaryTablePanel gstp = new GradeSummaryTablePanel("gradeSummaryTable", new LoadableDetachableModel>() { @Override public Map load() { return tableModel; } - })); + }); + gstp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + addOrReplace(gstp); // course grade, via the formatter - final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(userId); + final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(currentGradebookUid, currentSiteId, userId); addOrReplace(new Label("courseGrade", courseGradeFormatter.format(courseGrade)).setEscapeModelStrings(false)); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricGradePanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricGradePanel.java index f6d6f9c895f9..700b9a1939bb 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricGradePanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricGradePanel.java @@ -63,7 +63,7 @@ public void onInitialize() { final GbUser student = businessService.getUser(studentUuid); // Set the JS rubricGradingPoints variable to the current grade, if set. - Map grades = businessService.getGradesForStudent(studentUuid); + Map grades = businessService.getGradesForStudent(currentGradebookUid, currentSiteId, studentUuid); String grade = grades.get(assignmentId).getGrade(); if (grade == null) grade = "0"; Label initPointsScript = new Label("initPointsScript", ""); @@ -78,7 +78,7 @@ public void onInitialize() { final WebMarkupContainer sakaiRubricViewer = new WebMarkupContainer("sakai-rubric-viewer"); // View only rubric component for externally maintained assignments sakaiRubricViewer.add(AttributeModifier.append("id", assignmentId)); sakaiRubricViewer.add(AttributeModifier.append("evaluated-item-owner-id", studentUuid)); - Assignment assignment = businessService.getAssignment(assignmentId); + Assignment assignment = businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); sakaiRubricGrading.add(AttributeModifier.append("tool-id", assignment.getExternallyMaintained() ? AssignmentConstants.TOOL_ID : RubricsConstants.RBCS_TOOL_GRADEBOOKNG)); sakaiRubricGrading.setVisible(!assignment.getExternallyMaintained()); sakaiRubricViewer.add(AttributeModifier.append("tool-id", assignment.getExternallyMaintained() ? AssignmentConstants.TOOL_ID : RubricsConstants.RBCS_TOOL_GRADEBOOKNG)); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricPreviewPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricPreviewPanel.java index 36ffc0fcfd54..b9e4d81ccdd0 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricPreviewPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/RubricPreviewPanel.java @@ -61,7 +61,7 @@ public void onInitialize() { final Long assignmentId = (Long) getDefaultModelObject(); final WebMarkupContainer sakaiRubricPreview = new WebMarkupContainer("sakai-rubric-student"); sakaiRubricPreview.add(AttributeModifier.append("site-id", getCurrentSiteId())); - Assignment assignmentNow = businessService.getAssignment(assignmentId); + Assignment assignmentNow = businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); if (assignmentNow != null && assignmentNow.getExternallyMaintained()) { //this is an externally-maintained item from Assignments sakaiRubricPreview.add(AttributeModifier.append("entity-id", extractAssignmentId(assignmentNow.getExternalId()))); //rubric association needs Assignment id, not Gradebook id sakaiRubricPreview.add(AttributeModifier.append("tool-id", AssignmentConstants.TOOL_ID)); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SettingsGradingSchemaPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SettingsGradingSchemaPanel.java index 1f26a26ad693..9d150f129faf 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SettingsGradingSchemaPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SettingsGradingSchemaPanel.java @@ -322,7 +322,8 @@ public boolean isVisible() { }); // chart - this.chart = new CourseGradeChart("gradingSchemaChart", getCurrentSiteId(), null); + this.chart = new CourseGradeChart("gradingSchemaChart", null); + chart.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); settingsGradingSchemaPanel.add(this.chart); } @@ -392,7 +393,7 @@ private List getStudentsWithCourseGradeOverrides() { .map(c -> c.getKey()) .collect(Collectors.toList()); - final List users = this.businessService.getGbUsers(userUuids); + final List users = this.businessService.getGbUsers(currentSiteId, userUuids); users.sort(new FirstNameComparatorGbUser()); return users; @@ -405,8 +406,8 @@ private List getStudentsWithCourseGradeOverrides() { */ private Map getCourseGrades() { - final List studentUuids = this.businessService.getGradeableUsers(); - return this.businessService.getCourseGrades(studentUuids); + final List studentUuids = this.businessService.getGradeableUsers(currentGradebookUid, currentSiteId, null); + return this.businessService.getCourseGrades(currentGradebookUid, currentSiteId, studentUuids, null); } /** diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByCategoryPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByCategoryPanel.java index 254b30ad44c6..7ff8dcf85153 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByCategoryPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByCategoryPanel.java @@ -20,7 +20,6 @@ import org.apache.wicket.markup.html.form.HiddenField; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.spring.injection.annot.SpringBean; @@ -36,7 +35,7 @@ import java.util.Objects; import java.util.stream.Collectors; -public class SortGradeItemsByCategoryPanel extends Panel { +public class SortGradeItemsByCategoryPanel extends BasePanel { private static final long serialVersionUID = 1L; @@ -55,7 +54,7 @@ public void onInitialize() { final GradebookUiSettings settings = (GradebookUiSettings) model.get("settings"); // retrieve all categories, remove empty and ensure they're sorted - final List categories = this.businessService.getGradebookCategories().stream() + final List categories = this.businessService.getGradebookCategories(currentGradebookUid, currentSiteId).stream() .filter(c -> !c.getAssignmentList().isEmpty()).collect(Collectors.toList()); Collections.sort(categories, CategoryDefinition.orderComparator); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByGradeItemPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByGradeItemPanel.java index fdd1a1c492cc..238e6043e102 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByGradeItemPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsByGradeItemPanel.java @@ -20,7 +20,6 @@ import org.apache.wicket.markup.html.form.HiddenField; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; import org.apache.wicket.spring.injection.annot.SpringBean; import org.sakaiproject.gradebookng.business.GradebookNgBusinessService; @@ -29,7 +28,7 @@ import java.util.List; -public class SortGradeItemsByGradeItemPanel extends Panel { +public class SortGradeItemsByGradeItemPanel extends BasePanel { private static final long serialVersionUID = 1L; @@ -44,7 +43,7 @@ public SortGradeItemsByGradeItemPanel(final String id) { public void onInitialize() { super.onInitialize(); - final List assignments = this.businessService.getGradebookAssignments(SortType.SORT_BY_SORTING); + final List assignments = this.businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, SortType.SORT_BY_SORTING); add(new ListView("gradeItemList", assignments) { @Override diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsPanel.java index 0e55b7faf0f0..eb07a24a909c 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/SortGradeItemsPanel.java @@ -43,7 +43,7 @@ import org.sakaiproject.wicket.component.SakaiAjaxButton; @Slf4j -public class SortGradeItemsPanel extends Panel { +public class SortGradeItemsPanel extends BasePanel { private static final long serialVersionUID = 1L; @@ -104,9 +104,9 @@ public void onSubmit(final AjaxRequestTarget target) { Integer order = updates.get(assignmentId); if (byCategory) { - businessService.updateAssignmentCategorizedOrder(assignmentId, order); + businessService.updateAssignmentCategorizedOrder(currentGradebookUid, currentSiteId, assignmentId, order); } else if (byItem) { - businessService.updateAssignmentOrder(assignmentId, order); + businessService.updateAssignmentOrder(currentGradebookUid, currentSiteId, assignmentId, order); } } } catch (IdUnusedException | PermissionException e) { @@ -127,7 +127,7 @@ public void onSubmit(final AjaxRequestTarget target) { for (Long categoryId : catUpdates.keySet()) { Integer order = catUpdates.get(categoryId); - Optional optCategory = businessService.getCategory(categoryId); + Optional optCategory = businessService.getCategory(categoryId, currentSiteId); if (optCategory.isPresent()) { optCategory.get().setCategoryOrder(order); businessService.updateCategory(optCategory.get()); @@ -153,7 +153,9 @@ public void onSubmit(final AjaxRequestTarget target) { tabs.add(new AbstractTab(new Model(getString("sortgradeitems.bycategory"))) { @Override public Panel getPanel(final String panelId) { - return new SortGradeItemsByCategoryPanel(panelId, (IModel>) getDefaultModel()); + SortGradeItemsByCategoryPanel sgibcip = new SortGradeItemsByCategoryPanel(panelId, (IModel>) getDefaultModel()); + sgibcip.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + return sgibcip; } }); @@ -164,7 +166,9 @@ public Panel getPanel(final String panelId) { tabs.add(new AbstractTab(new Model(getString("sortgradeitems.bygradeitem"))) { @Override public Panel getPanel(final String panelId) { - return new SortGradeItemsByGradeItemPanel(panelId); + SortGradeItemsByGradeItemPanel sgibgip = new SortGradeItemsByGradeItemPanel(panelId); + sgibgip.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + return sgibgip; } }); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentAssignmentStatisticsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentAssignmentStatisticsPanel.java index 7739c8ff281e..9ef3e12b33de 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentAssignmentStatisticsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentAssignmentStatisticsPanel.java @@ -51,6 +51,7 @@ public void onInitialize() { final AssignmentGradeChart chart = new AssignmentGradeChart("chart", assignment.getId(), studentGrade); + chart.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); add(chart); add(new GbAjaxLink("done") { diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCompareGradesPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCompareGradesPanel.java index 1b7442ab82d0..e6d9ff6c7d66 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCompareGradesPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCompareGradesPanel.java @@ -35,23 +35,17 @@ public class StudentCompareGradesPanel extends BasePanel { private static final long serialVersionUID = 1L; private final ModalWindow window; - final List data; + private final Assignment assignment; public StudentCompareGradesPanel(final String id, final IModel model, final ModalWindow window) { super(id, model); this.window = window; - this.data = StudentCompareGradesPanel.this.businessService - .buildMatrixForGradeComparison( - model.getObject(), - getGradebook().getGradeType(), - getSettings() - ); + this.assignment = model.getObject(); } @Override public void onInitialize() { super.onInitialize(); - final Assignment assignment = ((Model) getDefaultModel()).getObject(); User currentUser = this.businessService.getCurrentUser(); @@ -59,7 +53,7 @@ public void onInitialize() { new StringResourceModel("comparegrades.modal.title.student.name").setParameters(currentUser.getDisplayName()) ); - Label gradeItemLabel = new Label("gradeItemLabel", assignment.getName()); + Label gradeItemLabel = new Label("gradeItemLabel", this.assignment.getName()); add(gradeItemLabel); boolean isComparingOrDisplayingFullName = getSettings() @@ -95,6 +89,13 @@ public void renderHead(IHeaderResponse response) { super.renderHead(response); Gson gson = new Gson(); + List data = StudentCompareGradesPanel.this.businessService + .buildMatrixForGradeComparison(currentGradebookUid, currentSiteId, + this.assignment, + getGradebook().getGradeType(), + getSettings() + ); + String dataJson = gson.toJson(data); response.render(JavaScriptHeaderItem.forScript("window.GbComparisonData = "+dataJson+";", null)); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCourseGradeStatisticsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCourseGradeStatisticsPanel.java index 3e8156037724..6d44072dd2e8 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCourseGradeStatisticsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentCourseGradeStatisticsPanel.java @@ -17,8 +17,6 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.sakaiproject.gradebookng.tool.chart.CourseGradeChart; import org.sakaiproject.gradebookng.tool.component.GbAjaxLink; @@ -34,9 +32,9 @@ public class StudentCourseGradeStatisticsPanel extends BasePanel { private final ModalWindow window; private final CourseGradeTransferBean studentGrade; - public StudentCourseGradeStatisticsPanel(final String id, final IModel model, final ModalWindow window, + public StudentCourseGradeStatisticsPanel(final String id, final ModalWindow window, final CourseGradeTransferBean courseGrade) { - super(id, model); + super(id); this.window = window; this.studentGrade = courseGrade; } @@ -46,11 +44,10 @@ public StudentCourseGradeStatisticsPanel(final String id, final IModel m public void onInitialize() { super.onInitialize(); - final String siteId = ((Model) getDefaultModel()).getObject(); - StudentCourseGradeStatisticsPanel.this.window.setTitle(new ResourceModel("label.statistics.title.coursegrade")); - final CourseGradeChart chart = new CourseGradeChart("chart", siteId, studentGrade); + final CourseGradeChart chart = new CourseGradeChart("chart", studentGrade); + chart.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); add(chart); add(new GbAjaxLink("done") { diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryGradesPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryGradesPanel.java index 37e659e14a69..6a933438f5f7 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryGradesPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryGradesPanel.java @@ -70,7 +70,7 @@ public StudentGradeSummaryGradesPanel(final String id, final IModel modelData = (Map) getDefaultModelObject(); final boolean groupedByCategoryByDefault = (Boolean) modelData.get("groupedByCategoryByDefault"); @@ -95,7 +95,7 @@ public void onBeforeRender() { final String userId = (String) modelData.get("studentUuid"); final Gradebook gradebook = getGradebook(); - String studentCourseGradeComment = this.businessService.getAssignmentGradeComment(businessService.getCurrentSiteId(), this.businessService.getCourseGradeId(gradebook.getId()), userId); + String studentCourseGradeComment = this.businessService.getAssignmentGradeComment(getCurrentSiteId(), this.businessService.getCourseGradeId(gradebook.getId()), userId); if (StringUtils.isEmpty(studentCourseGradeComment)){ studentCourseGradeComment = " -"; } @@ -108,9 +108,9 @@ public void onBeforeRender() { this.businessService.getShowCalculatedGrade()); // build up table data - final Map grades = this.businessService.getGradesForStudent(userId); + final Map grades = this.businessService.getGradesForStudent(currentGradebookUid, currentSiteId, userId); final SortType sortedBy = this.isGroupedByCategory ? SortType.SORT_BY_CATEGORY : SortType.SORT_BY_SORTING; - final List assignments = this.businessService.getGradebookAssignmentsForStudent(userId, sortedBy); + final List assignments = this.businessService.getGradebookAssignmentsForStudent(currentGradebookUid, currentSiteId, userId, sortedBy); final List categoryNames = new ArrayList<>(); final Map> categoryNamesToAssignments = new HashMap<>(); @@ -147,12 +147,12 @@ public void onBeforeRender() { if (!catItems.isEmpty()) { final Long catId = catItems.get(0).getCategoryId(); if (catId != null) { - this.businessService.getCategoryScoreForStudent(catId, userId, false) // Dont include non-released items in the category calc + this.businessService.getCategoryScoreForStudent(currentGradebookUid, currentSiteId, catId, userId, false) // Dont include non-released items in the category calc .ifPresent(avg -> storeAvgAndMarkIfDropped(avg, catId, categoryAverages, grades)); } } } - categoriesMap = this.businessService.getGradebookCategoriesForStudent(userId).stream() + categoriesMap = this.businessService.getGradebookCategoriesForStudent(currentGradebookUid, currentSiteId, userId).stream() .collect(Collectors.toMap(cat -> cat.getName(), cat -> cat)); } @@ -170,12 +170,14 @@ public void onBeforeRender() { tableModel.put("categoriesMap", categoriesMap); tableModel.put("studentUuid", userId); - addOrReplace(new GradeSummaryTablePanel("gradeSummaryTable", new LoadableDetachableModel>() { + GradeSummaryTablePanel gstp = new GradeSummaryTablePanel("gradeSummaryTable", new LoadableDetachableModel>() { @Override public Map load() { return tableModel; } - }).setVisible(this.isAssignmentsDisplayed && this.someAssignmentsReleased)); + }); + gstp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + addOrReplace(gstp.setVisible(this.isAssignmentsDisplayed && this.someAssignmentsReleased)); // no assignments message final WebMarkupContainer noAssignments = new WebMarkupContainer("noAssignments") { @@ -200,7 +202,7 @@ public boolean isVisible() { addOrReplace(courseGradePanel); // course grade, via the formatter - final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(userId); + final CourseGradeTransferBean courseGrade = this.businessService.getCourseGrade(currentGradebookUid, currentSiteId, userId); courseGradePanel.addOrReplace(new Label("courseGrade", courseGradeFormatter.format(courseGrade)).setEscapeModelStrings(false)); @@ -212,11 +214,9 @@ public boolean isVisible() { @Override public void onClick(final AjaxRequestTarget target) { - statsWindow.setContent(new StudentCourseGradeStatisticsPanel( - statsWindow.getContentId(), - Model.of(StudentGradeSummaryGradesPanel.this - .getCurrentSiteId()), - statsWindow, courseGrade)); + StudentCourseGradeStatisticsPanel scgsp = new StudentCourseGradeStatisticsPanel(statsWindow.getContentId(), statsWindow, courseGrade); + scgsp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + statsWindow.setContent(scgsp); statsWindow.show(target); } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryPanel.java index cf13fbeb7569..25a97dbc179e 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/StudentGradeSummaryPanel.java @@ -79,19 +79,23 @@ public void onClick(final AjaxRequestTarget target) { @Override public Panel getPanel(final String panelId) { - return new InstructorGradeSummaryGradesPanel(panelId, (IModel>) getDefaultModel()); + InstructorGradeSummaryGradesPanel igsgp = new InstructorGradeSummaryGradesPanel(panelId, (IModel>) getDefaultModel()); + igsgp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + return igsgp; } }); // Disable Student View for TAs as they most likely won't have the access // to view the grade data for every student - if (businessService.isUserAbleToEditAssessments()) { + if (businessService.isUserAbleToEditAssessments(currentSiteId)) { tabs.add(new AbstractTab(new Model(getString("label.studentsummary.studentviewtab"))) { private static final long serialVersionUID = 1L; @Override public Panel getPanel(final String panelId) { - return new StudentGradeSummaryGradesPanel(panelId, (IModel>) getDefaultModel()); + StudentGradeSummaryGradesPanel sgsgp = new StudentGradeSummaryGradesPanel(panelId, (IModel>) getDefaultModel()); + sgsgp.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + return sgsgp; } }); } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/UpdateUngradedItemsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/UpdateUngradedItemsPanel.java index de326c0bf68c..22374d8f0e86 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/UpdateUngradedItemsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/UpdateUngradedItemsPanel.java @@ -78,9 +78,9 @@ public void onInitialize() { // unpack model final Long assignmentId = (Long) getDefaultModelObject(); - final Assignment assignment = this.businessService.getAssignment(assignmentId); + final Assignment assignment = this.businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); - final Integer gradeType = this.businessService.getGradebook().getGradeType(); + final Integer gradeType = this.getGradebook().getGradeType(); // form model final GradeOverride override = new GradeOverride(); @@ -99,7 +99,7 @@ public void onSubmit(final AjaxRequestTarget target) { final GradeOverride override = (GradeOverride) form.getModelObject(); - final Assignment assignment = UpdateUngradedItemsPanel.this.businessService.getAssignment(assignmentId); + final Assignment assignment = UpdateUngradedItemsPanel.this.businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); try { if(!NumberUtil.isValidLocaleDouble(override.getGrade())){ @@ -112,8 +112,7 @@ public void onSubmit(final AjaxRequestTarget target) { target.addChildren(form, FeedbackPanel.class); } - final boolean success = UpdateUngradedItemsPanel.this.businessService.updateUngradedItems(assignmentId, override.getGrade(), - group); + final boolean success = businessService.updateUngradedItems(currentGradebookUid, currentSiteId, assignmentId, override.getGrade(), group.getId()); if (success) { UpdateUngradedItemsPanel.this.window.close(target); @@ -162,13 +161,12 @@ public void onSubmit(final AjaxRequestTarget target) { } form.add(hiddenGradePoints); - final List groups = this.businessService.getSiteSectionsAndGroups(); + final List groups = this.businessService.getSiteSectionsAndGroups(currentGradebookUid, currentSiteId); groups.add(0, new GbGroup(null, getString("groups.all"), null, GbGroup.Type.ALL)); if (getUserRole() == GbRole.TA) { - final boolean categoriesEnabled = this.businessService.categoriesAreEnabled(); - final List permissions = this.businessService.getPermissionsForUser( - this.businessService.getCurrentUser().getId()); + final boolean categoriesEnabled = this.businessService.categoriesAreEnabled(currentGradebookUid, currentSiteId); + final List permissions = this.businessService.getPermissionsForUser(getCurrentUserId(), currentGradebookUid, currentSiteId); final List gradableGroupIds = new ArrayList<>(); boolean canGradeAllGroups = false; diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/ZeroUngradedItemsPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/ZeroUngradedItemsPanel.java index f4cb3eb57ec4..9a0bafab410b 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/ZeroUngradedItemsPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/ZeroUngradedItemsPanel.java @@ -24,6 +24,7 @@ import org.sakaiproject.gradebookng.tool.component.GbAjaxButton; import org.sakaiproject.gradebookng.tool.pages.GradebookPage; import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.SortType; /** * @@ -54,11 +55,11 @@ public void onInitialize() { public void onSubmit(final AjaxRequestTarget target) { // fetch all assignments - final List assignments = ZeroUngradedItemsPanel.this.businessService.getGradebookAssignments(); + final List assignments = ZeroUngradedItemsPanel.this.businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, SortType.SORT_BY_SORTING); for (final Assignment assignment : assignments) { final long assignmentId = assignment.getId().longValue(); - ZeroUngradedItemsPanel.this.businessService.updateUngradedItems(assignmentId, FormatHelper.formatGradeForDisplay(ZERO_GRADE)); + ZeroUngradedItemsPanel.this.businessService.updateUngradedItems(currentGradebookUid, currentSiteId, assignmentId, FormatHelper.formatGradeForDisplay(ZERO_GRADE), null); } ZeroUngradedItemsPanel.this.window.close(target); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/CreateGradeItemStep.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/CreateGradeItemStep.java index 7e0d15a1d805..db865a23dda4 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/CreateGradeItemStep.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/CreateGradeItemStep.java @@ -37,6 +37,7 @@ import org.sakaiproject.gradebookng.tool.panels.AddOrEditGradeItemPanelContent; import org.sakaiproject.gradebookng.tool.panels.BasePanel; import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.util.api.FormattedText; import lombok.extern.slf4j.Slf4j; @@ -142,7 +143,9 @@ public void onSubmit(final AjaxRequestTarget target) { // wrap the form create panel form.add(new Label("createItemHeader", new StringResourceModel("importExport.createItem.heading").setParameters(step, importWizardModel.getTotalSteps()))); - form.add(new AddOrEditGradeItemPanelContent("subComponents", assignmentModel, UiMode.ADD)); + AddOrEditGradeItemPanelContent aegipc = new AddOrEditGradeItemPanelContent("subComponents", assignmentModel, UiMode.ADD); + aegipc.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + form.add(aegipc); this.previewGradesPanel = new PreviewImportedGradesPanel("previewGradesPanel", this.model); form.add(this.previewGradesPanel); } @@ -160,7 +163,7 @@ private void saveItemAndProceed(boolean forward, final AjaxRequestTarget target, // validate name is unique, first among existing gradebook items, second against new items to be created boolean validated = true; - final List existingAssignments = CreateGradeItemStep.this.businessService.getGradebookAssignments(); + final List existingAssignments = businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, SortType.SORT_BY_SORTING); if (!assignmentNameIsUnique(existingAssignments, newAssignment.getName()) || !assignmentNameIsUnique(newAssignment)) { validated = false; error(getString("error.addgradeitem.title")); @@ -185,9 +188,11 @@ private void saveItemAndProceed(boolean forward, final AjaxRequestTarget target, if (step < importWizardModel.getTotalSteps()) { importWizardModel.setStep(step + 1); newPanel = new CreateGradeItemStep(CreateGradeItemStep.this.panelId, Model.of(importWizardModel)); + ((CreateGradeItemStep)newPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } else { // If not, continue on in the wizard newPanel = new GradeImportConfirmationStep(CreateGradeItemStep.this.panelId, Model.of(importWizardModel)); + ((GradeImportConfirmationStep)newPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } } else // back @@ -195,12 +200,14 @@ private void saveItemAndProceed(boolean forward, final AjaxRequestTarget target, if (step > 1) { importWizardModel.setStep(step - 1); newPanel = new CreateGradeItemStep(CreateGradeItemStep.this.panelId, Model.of(importWizardModel)); + ((CreateGradeItemStep)newPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } else { // Reload everything. Rationale: final step can have partial success and partial failure. If content was imported from // the spreadsheet, the item selection page should reflect this when we return to it ImportGradesHelper.setupImportWizardModelForSelectionStep(page, CreateGradeItemStep.this, importWizardModel, - CreateGradeItemStep.this.businessService, target); + CreateGradeItemStep.this.businessService, target, currentGradebookUid, currentSiteId); newPanel = new GradeItemImportSelectionStep(CreateGradeItemStep.this.panelId, Model.of(importWizardModel)); + ((GradeItemImportSelectionStep)newPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } } diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/ExportPanel.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/ExportPanel.java index 444608fddb14..26f3e48fd9a1 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/ExportPanel.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/ExportPanel.java @@ -124,7 +124,7 @@ protected void onUpdate(final AjaxRequestTarget ajaxRequestTarget) { } }); - final boolean stuNumVisible = businessService.isStudentNumberVisible(); + final boolean stuNumVisible = businessService.isStudentNumberVisible(currentSiteId); add(new AjaxCheckBox("includeStudentNumber", Model.of(this.includeStudentNumber)) { private static final long serialVersionUID = 1L; @@ -181,7 +181,7 @@ protected void onUpdate(final AjaxRequestTarget ajaxRequestTarget) { @Override public boolean isVisible() { // only allow option if categories are not weighted - final Integer categoryType = ExportPanel.this.businessService.getGradebookCategoryType(); + final Integer categoryType = ExportPanel.this.businessService.getGradebookCategoryType(currentGradebookUid, currentSiteId); return !Objects.equals(categoryType, GradingConstants.CATEGORY_TYPE_WEIGHTED_CATEGORY); } }); @@ -205,7 +205,7 @@ protected void onUpdate(final AjaxRequestTarget ajaxRequestTarget) { @Override public boolean isVisible() { - return ExportPanel.this.businessService.categoriesAreEnabled(); + return ExportPanel.this.businessService.categoriesAreEnabled(currentGradebookUid, currentSiteId); } }); add(new AjaxCheckBox("includeCourseGrade", Model.of(this.includeCourseGrade)) { @@ -238,8 +238,12 @@ protected void onUpdate(final AjaxRequestTarget ajaxRequestTarget) { this.group = new GbGroup(null, getString("groups.all"), null, GbGroup.Type.ALL); - final List groups = this.businessService.getSiteSectionsAndGroups(); - groups.add(0, this.group); + final List groups = this.businessService.getSiteSectionsAndGroups(currentGradebookUid, currentSiteId); + if (currentGradebookUid.equals(currentSiteId)) { + groups.add(0, this.group); + } else { // group instance gb, list will have one and only one + this.group = groups.get(0); + } add(new DropDownChoice("groupFilter", Model.of(this.group), groups, new ChoiceRenderer() { private static final long serialVersionUID = 1L; @@ -256,7 +260,7 @@ public String getIdValue(final GbGroup g, final int index) { @Override protected void onUpdate(AjaxRequestTarget target) { GbGroup value = (GbGroup) ((DropDownChoice) getComponent()).getDefaultModelObject(); - if (value == null) { + if (value == null && currentGradebookUid.equals(currentSiteId)) { ExportPanel.this.group = new GbGroup(null, getString("groups.all"), null, GbGroup.Type.ALL); } else { ExportPanel.this.group = (GbGroup) ((DropDownChoice) getComponent()).getDefaultModelObject(); @@ -327,11 +331,11 @@ private File buildFile(final boolean isCustomExport) { // get list of assignments. this allows us to build the columns and then fetch the grades for each student for each assignment from the map SortType sortBy = SortType.SORT_BY_SORTING; - if (this.businessService.categoriesAreEnabled()) { + if (this.businessService.categoriesAreEnabled(currentGradebookUid, currentSiteId)) { sortBy = SortType.SORT_BY_CATEGORY; } - final List assignments = this.businessService.getGradebookAssignments(sortBy); - final List categories = this.businessService.getGradebookCategories(); + final List assignments = this.businessService.getGradebookAssignments(currentGradebookUid, currentSiteId, sortBy); + final List categories = this.businessService.getGradebookCategories(currentGradebookUid, currentSiteId); // no assignments, give a template if (assignments.isEmpty()) { @@ -370,7 +374,7 @@ private File buildFile(final boolean isCustomExport) { // Find the correct category in the ArrayList to extract the points final CategoryDefinition cd = categories.stream().filter(cat -> a1.getCategoryId().equals(cat.getId())).findAny().orElse(null); String catWeightString = ""; - if (cd != null && Objects.equals(this.businessService.getGradebookCategoryType(), GradingConstants.CATEGORY_TYPE_WEIGHTED_CATEGORY)) { + if (cd != null && Objects.equals(this.businessService.getGradebookCategoryType(currentGradebookUid, currentSiteId), GradingConstants.CATEGORY_TYPE_WEIGHTED_CATEGORY)) { if (cd.getWeight() != null) { catWeightString = "(" + FormatHelper.formatDoubleAsPercentage(cd.getWeight() * 100) + ")"; } @@ -409,7 +413,7 @@ private File buildFile(final boolean isCustomExport) { } // get the grade matrix - final List grades = this.businessService.buildGradeMatrixForImportExport(assignments, group); + final List grades = this.businessService.buildGradeMatrixForImportExport(currentGradebookUid, currentSiteId, assignments, group.getId()); // add grades grades.forEach(studentGradeInfo -> { @@ -511,7 +515,7 @@ private File buildFile(final boolean isCustomExport) { private String buildFileName(final boolean customDownload) { final String prefix = getString("importExport.download.filenameprefix"); final String extension = this.exportFormat.toString().toLowerCase(); - final String gradebookName = this.businessService.getGradebook().getName(); + final String gradebookName = this.businessService.getGradebook(currentGradebookUid, currentSiteId).getName(); // File name contains the prefix final List fileNameComponents = new ArrayList<>(); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportConfirmationStep.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportConfirmationStep.java index 43b0422c4e88..316b256b286b 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportConfirmationStep.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportConfirmationStep.java @@ -47,7 +47,6 @@ import org.sakaiproject.gradebookng.business.model.ProcessedGradeItemDetail; import org.sakaiproject.gradebookng.business.util.FormatHelper; import org.sakaiproject.gradebookng.business.util.EventHelper; -import org.sakaiproject.gradebookng.business.util.MessageHelper; import org.sakaiproject.gradebookng.tool.model.ImportWizardModel; import org.sakaiproject.gradebookng.tool.pages.GradebookPage; import org.sakaiproject.gradebookng.tool.pages.ImportExportPage; @@ -57,9 +56,11 @@ import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.ConflictingExternalIdException; import org.sakaiproject.grading.api.GradeDefinition; +import org.sakaiproject.grading.api.MessageHelper; import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.rubrics.api.RubricsConstants; import org.sakaiproject.rubrics.api.beans.RubricTransferBean; +import org.sakaiproject.util.ResourceLoader; /** * Confirmation page for what is going to be imported @@ -72,9 +73,12 @@ public class GradeImportConfirmationStep extends BasePanel { private final String panelId; private final IModel model; - private final String yes = MessageHelper.getString("importExport.confirmation.yes"); - private final String no = MessageHelper.getString("importExport.confirmation.no"); - private final String none = MessageHelper.getString("importExport.confirmation.none"); + @SuppressWarnings("unchecked") + private static ResourceLoader RL = new ResourceLoader(); + + private final String yes = MessageHelper.getString("importExport.confirmation.yes", RL.getLocale()); + private final String no = MessageHelper.getString("importExport.confirmation.no", RL.getLocale()); + private final String none = MessageHelper.getString("importExport.confirmation.none", RL.getLocale()); private boolean errors = false; @@ -84,7 +88,6 @@ public GradeImportConfirmationStep(final String id, final IModel 0) { previousPanel = new CreateGradeItemStep(GradeImportConfirmationStep.this.panelId, Model.of(importWizardModel)); + ((CreateGradeItemStep)previousPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } else { previousPanel = new GradeItemImportSelectionStep(GradeImportConfirmationStep.this.panelId, Model.of(importWizardModel)); + ((GradeItemImportSelectionStep)previousPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } // AJAX the previous panel into place @@ -147,7 +152,6 @@ public void onSubmit(AjaxRequestTarget target) { final Map assignmentMap = new HashMap<>(); final List itemsToSave = new ArrayList<>(); Set errorColumns = new HashSet<>(); - final Gradebook gradebook = businessService.getGradebook(); // Create new GB items Iterator> itAssignments = assignmentsToCreate.entrySet().iterator(); @@ -158,13 +162,13 @@ public void onSubmit(AjaxRequestTarget target) { Long assignmentId = null; try { ProcessedGradeItem pgi = entry.getKey(); - assignmentId = GradeImportConfirmationStep.this.businessService.addAssignment(assignment); + assignmentId = GradeImportConfirmationStep.this.businessService.addAssignment(currentGradebookUid, currentSiteId, assignment); Map rubricParams = pgi.getRubricParameters(); if (!rubricParams.isEmpty()) { rubricsService.saveRubricAssociation(RubricsConstants.RBCS_TOOL_GRADEBOOKNG, assignmentId.toString(), rubricParams); } - success(MessageHelper.getString("notification.addgradeitem.success", assignment.getName())); + success(MessageHelper.getString("notification.addgradeitem.success", RL.getLocale(), assignment.getName())); // set the processedGradeItem's itemId so we can later save scores from the spreadsheet pgi.setItemId(assignmentId); @@ -184,7 +188,7 @@ public void onSubmit(AjaxRequestTarget target) { } catch (final ConflictingAssignmentNameException e) { String title = assignment.getName(); if (!StringUtils.isBlank(title)) { - error(MessageHelper.getString("error.addgradeitem.title.duplicate", title)); + error(MessageHelper.getString("error.addgradeitem.title.duplicate", RL.getLocale(), title)); } else { error(new ResourceModel("error.addgradeitem.title").getObject()); } @@ -208,14 +212,14 @@ public void onSubmit(AjaxRequestTarget target) { final String itemPoints = FormatHelper.formatGradeFromUserLocale(item.getItemPointValue()); final Double points = FormatHelper.validateDouble(itemPoints); - final Assignment assignment = GradeImportConfirmationStep.this.businessService.getAssignment(item.getItemTitle()); + final Assignment assignment = GradeImportConfirmationStep.this.businessService.getAssignment(currentGradebookUid, currentSiteId, item.getItemTitle()); assignment.setPoints(points); try { - GradeImportConfirmationStep.this.businessService.updateAssignment(assignment); + GradeImportConfirmationStep.this.businessService.updateAssignment(currentGradebookUid, currentSiteId, assignment); } catch (final Exception e) { - getSession().error(MessageHelper.getString("importExport.error.pointsmodification", assignment.getName())); + getSession().error(MessageHelper.getString("importExport.error.pointsmodification", RL.getLocale(), assignment.getName())); GradeImportConfirmationStep.this.errors = true; errorColumns.add(item); log.warn("An error occurred updating the assignment", e); @@ -246,7 +250,7 @@ public void onSubmit(AjaxRequestTarget target) { //TODO if assignmentId is still null, there will be a problem // Get the assignment and details - final Assignment assignment = businessService.getAssignment(assignmentId); + final Assignment assignment = businessService.getAssignment(currentGradebookUid, currentSiteId, assignmentId); final List processedGradeItemDetails = processedGradeItem.getProcessedGradeItemDetails(); List gradeDefList = new ArrayList<>(); for (ProcessedGradeItemDetail processedGradeItemDetail : processedGradeItemDetails) { @@ -257,7 +261,7 @@ public void onSubmit(AjaxRequestTarget target) { gradeDefList.add(gradeDef); } - final GradeSaveResponse saveResponse = businessService.saveGradesAndCommentsForImport(gradebook, assignment, gradeDefList); + final GradeSaveResponse saveResponse = businessService.saveGradesAndCommentsForImport(currentGradebookUid, currentSiteId, assignment, gradeDefList); switch (saveResponse) { case OK: break; @@ -377,7 +381,7 @@ protected void populateItem(final ListItem item) { String displayTitle = gradeItem.getItemTitle(); if (gradeItem.getType() == Type.COMMENT) { - displayTitle = MessageHelper.getString("importExport.confirmation.commentsdisplay", gradeItem.getItemTitle()); + displayTitle = MessageHelper.getString("importExport.confirmation.commentsdisplay", RL.getLocale(), gradeItem.getItemTitle()); } item.add(new Label("title", displayTitle)); diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportUploadStep.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportUploadStep.java index a5b0f580ab51..018ce16a3706 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportUploadStep.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeImportUploadStep.java @@ -39,12 +39,13 @@ import org.sakaiproject.gradebookng.business.exception.GbImportExportInvalidFileTypeException; import org.sakaiproject.gradebookng.business.model.ImportedSpreadsheetWrapper; import org.sakaiproject.gradebookng.business.util.ImportGradesHelper; -import org.sakaiproject.gradebookng.business.util.MessageHelper; import org.sakaiproject.gradebookng.tool.model.ImportWizardModel; import org.sakaiproject.gradebookng.tool.pages.GradebookPage; import org.sakaiproject.gradebookng.tool.pages.ImportExportPage; import org.sakaiproject.gradebookng.tool.panels.BasePanel; +import org.sakaiproject.grading.api.MessageHelper; import org.sakaiproject.util.api.FormattedText; +import org.sakaiproject.util.ResourceLoader; /** * Upload/Download page @@ -60,6 +61,9 @@ public class GradeImportUploadStep extends BasePanel { private final String panelId; private final int maxUploadFileSize; + @SuppressWarnings("unchecked") + private static ResourceLoader RL = new ResourceLoader(); + public GradeImportUploadStep(final String id) { super(id); this.panelId = id; @@ -70,7 +74,9 @@ public GradeImportUploadStep(final String id) { public void onInitialize() { super.onInitialize(); - add(new ExportPanel("export")); + ExportPanel ep = new ExportPanel("export"); + ep.setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); + add(ep); add(new UploadForm("form")); } @@ -146,7 +152,7 @@ public void onSubmit(AjaxRequestTarget target) { @Override protected void onFileUploadException(FileUploadException e, Map model) { if (e instanceof FileUploadBase.SizeLimitExceededException) { - error(MessageHelper.getString("importExport.error.fileTooBig", maxUploadFileSize)); + error(MessageHelper.getString("importExport.error.fileTooBig", RL.getLocale(), maxUploadFileSize)); continueButton.setEnabled(false); } } @@ -162,7 +168,7 @@ public void processUploadedFile(AjaxRequestTarget target) { ImportedSpreadsheetWrapper spreadsheetWrapper; try { spreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(upload.getInputStream(), upload.getContentType(), - upload.getClientFileName(), businessService, ComponentManager.get(FormattedText.class).getDecimalSeparator()); + upload.getClientFileName(), businessService, ComponentManager.get(FormattedText.class).getDecimalSeparator(), currentGradebookUid, currentSiteId); } catch (final GbImportExportInvalidFileTypeException | InvalidFormatException e) { log.debug("incorrect type", e); error(getString("importExport.error.incorrecttype")); @@ -177,7 +183,7 @@ public void processUploadedFile(AjaxRequestTarget target) { final ImportWizardModel importWizardModel = new ImportWizardModel(); importWizardModel.setSpreadsheetWrapper(spreadsheetWrapper); - boolean uploadSuccess = ImportGradesHelper.setupImportWizardModelForSelectionStep(page, GradeImportUploadStep.this, importWizardModel, businessService, target); + boolean uploadSuccess = ImportGradesHelper.setupImportWizardModelForSelectionStep(page, GradeImportUploadStep.this, importWizardModel, businessService, target, currentGradebookUid, currentSiteId); // For whatever issues encountered, ImportGradesHelper.setupImportWizardModelForSelectionStep() will have updated the feedbackPanels; just return if (!uploadSuccess) { @@ -185,6 +191,7 @@ public void processUploadedFile(AjaxRequestTarget target) { } final Component newPanel = new GradeItemImportSelectionStep(GradeImportUploadStep.this.panelId, Model.of(importWizardModel)); + ((GradeItemImportSelectionStep)newPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); newPanel.setOutputMarkupId(true); // AJAX the new panel into place diff --git a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeItemImportSelectionStep.java b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeItemImportSelectionStep.java index 32e618f06f01..2e166a86ba03 100644 --- a/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeItemImportSelectionStep.java +++ b/gradebookng/tool/src/java/org/sakaiproject/gradebookng/tool/panels/importExport/GradeItemImportSelectionStep.java @@ -188,6 +188,7 @@ public void onSubmit(AjaxRequestTarget target) { // Create the previous panel final Component previousPanel = new GradeImportUploadStep(GradeItemImportSelectionStep.this.panelId); + ((CreateGradeItemStep)previousPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); previousPanel.setOutputMarkupId(true); // AJAX the previous panel into place @@ -258,8 +259,10 @@ protected void onSubmit(AjaxRequestTarget target) { importWizardModel.setStep(1); importWizardModel.setTotalSteps(itemsToCreate.size()); newPanel = new CreateGradeItemStep(GradeItemImportSelectionStep.this.panelId, Model.of(importWizardModel)); + ((CreateGradeItemStep)newPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } else { newPanel = new GradeImportConfirmationStep(GradeItemImportSelectionStep.this.panelId, Model.of(importWizardModel)); + ((GradeImportConfirmationStep)newPanel).setCurrentGradebookAndSite(currentGradebookUid, currentSiteId); } // AJAX the new panel into place diff --git a/gradebookng/tool/src/test/org/sakaiproject/gradebookng/business/util/TestImportGradesHelper.java b/gradebookng/tool/src/test/org/sakaiproject/gradebookng/business/util/TestImportGradesHelper.java index 964c576ad363..144f026cc044 100644 --- a/gradebookng/tool/src/test/org/sakaiproject/gradebookng/business/util/TestImportGradesHelper.java +++ b/gradebookng/tool/src/test/org/sakaiproject/gradebookng/business/util/TestImportGradesHelper.java @@ -70,7 +70,7 @@ public void openMocks() throws NoSuchFieldException, IllegalAccessException { when(resourceLoader.getLocale()).thenReturn(Locale.getDefault()); Map mockStudents = mockUserMap(); - when(service.getUserEidMap()).thenReturn(mockStudents); + when(service.getUserEidMap(Mockito.anyObject())).thenReturn(mockStudents); } private void setMockResourceLoader(Class clazz, String fieldName) throws NoSuchFieldException, IllegalAccessException { @@ -144,7 +144,7 @@ public void when_headerHasPoundSign_thenImportSucceeds() throws Exception { public void when_textcsv_thenCsvImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.csv")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/csv", "grades_import.csv", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/csv", "grades_import.csv", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -153,7 +153,7 @@ public void when_textcsv_thenCsvImportSucceeds() throws Exception { public void when_textcsv_i18n_thenCsvImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import_i18n.csv")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/csv", "grades_import_i18n.csv", service, ","); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/csv", "grades_import_i18n.csv", service, ",", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -162,7 +162,7 @@ public void when_textcsv_i18n_thenCsvImportSucceeds() throws Exception { public void when_textplain_thenCsvImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.csv")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/plain", "grades_import.csv", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/plain", "grades_import.csv", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -171,7 +171,7 @@ public void when_textplain_thenCsvImportSucceeds() throws Exception { public void when_textcommaseparatedvalues_thenCsvImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.csv")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/comma-separated-values", "grades_import.csv", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "text/comma-separated-values", "grades_import.csv", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -180,7 +180,7 @@ public void when_textcommaseparatedvalues_thenCsvImportSucceeds() throws Excepti public void when_textapplicationcsv_thenCsvImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.csv")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/csv", "grades_import.csv", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/csv", "grades_import.csv", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -191,7 +191,7 @@ public void when_browser_says_applicationvndmsexcel_thenCsvImportSucceeds() thro // Windows machine with MS Office installed is going to send this CSV with an Excel mimetype try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.csv")) { // Windows machine with MS Office installed is going to send this CSV with an Excel mimetype - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/vnd.ms-excel", "grades_import.csv", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/vnd.ms-excel", "grades_import.csv", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -200,7 +200,7 @@ public void when_browser_says_applicationvndmsexcel_thenCsvImportSucceeds() thro public void when_applicationvndmsexcel_thenXlsImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.xls")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/vnd.ms-excel", "grades_import.xls", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/vnd.ms-excel", "grades_import.xls", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -209,7 +209,7 @@ public void when_applicationvndmsexcel_thenXlsImportSucceeds() throws Exception public void when_applicationvndopenxmlformatsofficedocumentspreadsheetmlsheet_thenXlsImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.xls")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "grades_import.xls", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "grades_import.xls", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -218,7 +218,7 @@ public void when_applicationvndopenxmlformatsofficedocumentspreadsheetmlsheet_th public void when_anythingelse_thenImportFails() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import.pdf")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/pdf", "grades_import.pdf", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/pdf", "grades_import.pdf", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -227,7 +227,7 @@ public void when_anythingelse_thenImportFails() throws Exception { public void when_caseSensitiveDupes_thenImportSucceeds() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import_with_case_sensitive_dupes.csv")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/csv", "grades_import_with_case_sensitive_dupes.csv", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/csv", "grades_import_with_case_sensitive_dupes.csv", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); } @@ -235,7 +235,7 @@ public void when_caseSensitiveDupes_thenImportSucceeds() throws Exception { public void when_exactDupes_thenImportFails() throws Exception { final ImportedSpreadsheetWrapper importedSpreadsheetWrapper; try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("grades_import_with_exact_dupes.csv")) { - importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/csv", "grades_import_with_exact_dupes.csv", service); + importedSpreadsheetWrapper = ImportGradesHelper.parseImportedGradeFile(is, "application/csv", "grades_import_with_exact_dupes.csv", service, "", "gUid", "siteId"); } testImport(importedSpreadsheetWrapper); Assert.assertEquals("unexpected duplicate column count", 2, importedSpreadsheetWrapper.getHeadingReport().getDuplicateHeadings().size()); @@ -450,7 +450,7 @@ private ImportedSpreadsheetWrapper mockImportedSpreadsheetData() { row3.setCellMap(cellMap3); rows.add(row3); - importedSpreadsheetWrapper.setRows(rows, service.getUserEidMap()); + importedSpreadsheetWrapper.setRows(rows, service.getUserEidMap(Mockito.anyObject())); return importedSpreadsheetWrapper; } diff --git a/gradebookng/tool/src/webapp/WEB-INF/applicationContext.xml b/gradebookng/tool/src/webapp/WEB-INF/applicationContext.xml index dd11845973e6..7257504cfdc0 100644 --- a/gradebookng/tool/src/webapp/WEB-INF/applicationContext.xml +++ b/gradebookng/tool/src/webapp/WEB-INF/applicationContext.xml @@ -14,7 +14,6 @@ - diff --git a/gradebookng/tool/src/webapp/WEB-INF/tools/sakai.gradebookng.xml b/gradebookng/tool/src/webapp/WEB-INF/tools/sakai.gradebookng.xml index c1c5f2020d71..f7bcbd69321b 100644 --- a/gradebookng/tool/src/webapp/WEB-INF/tools/sakai.gradebookng.xml +++ b/gradebookng/tool/src/webapp/WEB-INF/tools/sakai.gradebookng.xml @@ -12,6 +12,8 @@ --> + + diff --git a/gradebookng/tool/src/webapp/scripts/gradebook-gbgrade-table.js b/gradebookng/tool/src/webapp/scripts/gradebook-gbgrade-table.js index d92beec19cef..ff2907c07fa2 100644 --- a/gradebookng/tool/src/webapp/scripts/gradebook-gbgrade-table.js +++ b/gradebookng/tool/src/webapp/scripts/gradebook-gbgrade-table.js @@ -1314,7 +1314,6 @@ GbGradeTable.renderTable = function (elementId, tableData) { on("click", ".gb-dropdown-menu .gb-view-course-grade-statistics", function() { GbGradeTable.ajax({ action: 'viewCourseGradeStatistics', - siteId: GbGradeTable.container.data("siteid") }); }). on("click", ".gb-dropdown-menu .gb-course-grade-breakdown", function() { @@ -2434,6 +2433,7 @@ GbGradeTable.setupConcurrencyCheck = function() { function performConcurrencyCheck() { GradebookAPI.isAnotherUserEditing( GbGradeTable.container.data("siteid"), + GbGradeTable.container.data("guid"), GbGradeTable.container.data("gradestimestamp"), handleConcurrencyCheck); }; @@ -2635,6 +2635,7 @@ GbGradeTable.setupDragAndDrop = function () { GradebookAPI.updateCategorizedAssignmentOrder( GbGradeTable.container.data("siteid"), + GbGradeTable.container.data("guid"), sourceAssignmentId, sourceModel.categoryId, newIndex, @@ -2647,6 +2648,7 @@ GbGradeTable.setupDragAndDrop = function () { } else { GradebookAPI.updateAssignmentOrder( GbGradeTable.container.data("siteid"), + GbGradeTable.container.data("guid"), sourceAssignmentId, newIndex, handleColumnReorder, @@ -2968,6 +2970,7 @@ GbGradeTable.setupCellMetaDataSummary = function() { setTimeout(function() { GradebookAPI.getComments( GbGradeTable.container.data("siteid"), + GbGradeTable.container.data("guid"), $.data($td[0], "assignmentid"), $.data($td[0], "studentid"), function(comment) { @@ -2984,6 +2987,7 @@ GbGradeTable.setupCellMetaDataSummary = function() { setTimeout(function () { GradebookAPI.getCourseGradeComment( GbGradeTable.container.data("siteid"), + GbGradeTable.container.data("guid"), $.data($td[0], "courseGradeId"), $.data($td[0], "studentid"), $.data($td[0], "gradebookId"), @@ -3584,9 +3588,10 @@ GbGradeTable.saveNewPrediction = function(prediction) { GradebookAPI = {}; -GradebookAPI.isAnotherUserEditing = function(siteId, timestamp, onSuccess, onError) { +GradebookAPI.isAnotherUserEditing = function(siteId, gUid, timestamp, onSuccess, onError) { var endpointURL = "/direct/gbng/isotheruserediting/" + siteId + ".json"; var params = { + gUid: gUid, since: timestamp, auto: true // indicate that the request is automatic, not from a user action }; @@ -3594,20 +3599,22 @@ GradebookAPI.isAnotherUserEditing = function(siteId, timestamp, onSuccess, onErr }; -GradebookAPI.getComments = function(siteId, assignmentId, studentUuid, onSuccess, onError) { +GradebookAPI.getComments = function(siteId, gUid, assignmentId, studentUuid, onSuccess, onError) { var endpointURL = "/direct/gbng/comments"; var params = { siteId: siteId, + gUid: gUid, assignmentId: assignmentId, studentUuid: studentUuid }; GradebookAPI._GET(endpointURL, params, onSuccess, onError); }; -GradebookAPI.getCourseGradeComment = function(siteId, courseGradeId, studentUuid, gradebookId, onSuccess, onError) { +GradebookAPI.getCourseGradeComment = function(siteId, gUid, courseGradeId, studentUuid, gradebookId, onSuccess, onError) { var endpointURL = "/direct/gbng/courseGradeComment"; var params = { siteId: siteId, + gUid: gUid, courseGradeId: courseGradeId, studentUuid: studentUuid, gradebookId: gradebookId @@ -3615,9 +3622,10 @@ GradebookAPI.getCourseGradeComment = function(siteId, courseGradeId, studentUuid GradebookAPI._GET(endpointURL, params, onSuccess, onError); }; -GradebookAPI.updateAssignmentOrder = function(siteId, assignmentId, order, onSuccess, onError, onComplete) { +GradebookAPI.updateAssignmentOrder = function(siteId, gUid, assignmentId, order, onSuccess, onError, onComplete) { GradebookAPI._POST("/direct/gbng/assignment-order", { siteId: siteId, + gUid: gUid, assignmentId: assignmentId, order: order }, @@ -3625,9 +3633,10 @@ GradebookAPI.updateAssignmentOrder = function(siteId, assignmentId, order, onSuc }; -GradebookAPI.updateCategorizedAssignmentOrder = function(siteId, assignmentId, categoryId, order, onSuccess, onError, onComplete) { +GradebookAPI.updateCategorizedAssignmentOrder = function(siteId, gUid, assignmentId, categoryId, order, onSuccess, onError, onComplete) { GradebookAPI._POST("/direct/gbng/categorized-assignment-order", { siteId: siteId, + gUid: gUid, assignmentId: assignmentId, categoryId: categoryId, order: order diff --git a/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/Assignment2Entity.java b/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/Assignment2Entity.java index 0103e8e6bd12..4a504d634960 100644 --- a/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/Assignment2Entity.java +++ b/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/Assignment2Entity.java @@ -520,7 +520,7 @@ public LessonSubmission getSubmission(String userId) { // following will give a security error if assignment not released. I think that's better than // checking myself, as that would require fetchign the assignment definition from the gradebook // A2 doesn't seem to save that. Score is scaled, so need * 10 - Double score = toDouble(gradingService.getAssignmentScore(assignment.context, assignment.gradebookitem, userId)); + Double score = toDouble(gradingService.getAssignmentScore1(assignment.context, assignment.gradebookitem, userId)); if (score != null) { LessonSubmission ret = new LessonSubmission(score); // shouldn't actually need the string value diff --git a/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/ScormEntity.java b/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/ScormEntity.java index eda525d5f740..f00cec10fb85 100644 --- a/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/ScormEntity.java +++ b/lessonbuilder/tool/opt-src/java/org/sakaiproject/lessonbuildertool/service/ScormEntity.java @@ -68,7 +68,6 @@ import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.site.cover.SiteService; -import org.sakaiproject.grading.api.GradingService; import org.sakaiproject.util.FormattedText; import org.sakaiproject.util.Validator; import org.sakaiproject.tool.api.Session; @@ -108,12 +107,6 @@ public void setMessageLocator(MessageLocator m) { messageLocator = m; } - - - static GradingService gradingService = null; - public void setGradingService(GradingService g) { - gradingService = g; - } static ContentPackageDao dao = null; static ScormResourceService scormResourceService = null; diff --git a/lessonbuilder/tool/opt-src/webapp/WEB-INF/opt-applicationContext.xml b/lessonbuilder/tool/opt-src/webapp/WEB-INF/opt-applicationContext.xml index 9533fac4acfc..aff21da19a01 100644 --- a/lessonbuilder/tool/opt-src/webapp/WEB-INF/opt-applicationContext.xml +++ b/lessonbuilder/tool/opt-src/webapp/WEB-INF/opt-applicationContext.xml @@ -36,7 +36,6 @@ destroy-method="destroy"> -
diff --git a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/GradebookIfc.java b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/GradebookIfc.java index 30751c590dab..4afe7be81bfd 100644 --- a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/GradebookIfc.java +++ b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/GradebookIfc.java @@ -7,7 +7,7 @@ * * Copyright (c) 2011 Rutgers, the State University of New Jersey * - * Licensed under the Educational Community License, Version 2.0 (the "License"); + * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * @@ -24,12 +24,17 @@ package org.sakaiproject.lessonbuildertool.service; import java.util.Date; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import lombok.Setter; import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.model.Gradebook; +import org.sakaiproject.lessonbuildertool.api.LessonBuilderConstants; /** * Interface to Gradebook @@ -39,67 +44,73 @@ */ @Slf4j public class GradebookIfc { - private static GradingService gradingService = null; + @Setter private static GradingService gradingService; - public void setGradingService (GradingService s) { - gradingService = s; - } - - public boolean addExternalAssessment(final String gradebookUid, final String externalId, final String externalUrl, + public boolean addExternalAssessment(final List gradebookUids, final String siteId, final String externalId, final String externalUrl, final String title, final double points, final Date dueDate, final String externalServiceDescription) { - try { - gradingService.addExternalAssessment(gradebookUid, externalId, externalUrl, title, points, dueDate, externalServiceDescription, null); - } catch (ConflictingAssignmentNameException cane) { - // already exists - log.warn("ConflictingAssignmentNameException for title {} : {} ", title, cane.getMessage()); - throw cane; - } catch (Exception e) { - log.info("failed add " + e); - return false; + try { + for (String gradebookUid : gradebookUids) { + gradingService.addExternalAssessment(gradebookUid, siteId, externalId, externalUrl, title, points, dueDate, externalServiceDescription, null, null, null, null); + } + } catch (ConflictingAssignmentNameException cane) { + // already exists + log.warn("ConflictingAssignmentNameException for title {} : {} ", title, cane.getMessage()); + throw cane; + } catch (Exception e) { + log.info("failed add " + e); + return false; + } + return true; } - return true; - } - public boolean updateExternalAssessment(final String gradebookUid, final String externalId, final String externalUrl, - final String title, final double points, final Date dueDate) { - try { - gradingService.updateExternalAssessment(gradebookUid, externalId, externalUrl, null, title, points, dueDate); - } catch (Exception e) { - return false; + public boolean updateExternalAssessment(final List gradebookUids, final String externalId, final String externalUrl, + final String title, final double points, final Date dueDate) { + try { + for (String gradebookUid : gradebookUids) { + gradingService.updateExternalAssessment(gradebookUid, externalId, externalUrl, null, title, null, points, dueDate, null); + } + } catch (Exception e) { + return false; + } + return true; } - return true; - } - - public boolean removeExternalAssessment(final String gradebookUid, final String externalId) { - try { - gradingService.removeExternalAssignment(gradebookUid, externalId); - } catch (Exception e) { - log.info("failed remove " + e); - return false; + public boolean removeExternalAssessment(final String gradebookUid, final String externalId) { + try { + gradingService.removeExternalAssignment(null, externalId, LessonBuilderConstants.TOOL_ID); + } catch (Exception e) { + log.info("failed remove " + e); + return false; + } + return true; } - return true; - } - public boolean updateExternalAssessmentScore(final String gradebookUid, final String externalId, + public boolean updateExternalAssessmentScore(final String gradebookUid, final String siteId, final String externalId, final String studentUid, final String points) { - try { - gradingService.updateExternalAssessmentScore(gradebookUid, externalId, studentUid, points); - } catch (Exception e) { - return false; + try { + gradingService.updateExternalAssessmentScore(gradebookUid, siteId, externalId, studentUid, points); + } catch (Exception e) { + return false; + } + return true; } - return true; - } - // map is String studentid to Double points - public boolean updateExternalAssessmentScores(final String gradebookUid, final String externalId, final Map studentUidsToScores) { - - try { - gradingService.updateExternalAssessmentScoresString(gradebookUid, externalId, studentUidsToScores); - } catch (Exception e) { - return false; + public boolean updateExternalAssessmentScores(final String gradebookUid, final String siteId, final String externalId, final Map studentUidsToScores) { + try { + gradingService.updateExternalAssessmentScoresString(gradebookUid, siteId, externalId, studentUidsToScores); + } catch (Exception e) { + return false; + } + return true; } - return true; - } + public boolean isGradebookGroupEnabled(final String siteId) { + return gradingService.isGradebookGroupEnabled(siteId); + } + + public List getGradebookGroupInstances(String siteId) { + return gradingService.getGradebookGroupInstances(siteId).stream() + .map(Gradebook::getUid) + .collect(Collectors.toList()); + } } diff --git a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/LessonBuilderEntityProducer.java b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/LessonBuilderEntityProducer.java index 402374690278..a055a9b27b15 100644 --- a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/LessonBuilderEntityProducer.java +++ b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/LessonBuilderEntityProducer.java @@ -945,6 +945,8 @@ private boolean makePage(Element element, String oldServer, String siteId, Strin item.setAlt(itemElement.getAttribute("objectid")); } + List gradebookUids = Arrays.asList(siteId); + // not currently doing this, although the code has been tested. // The problem is that other tools don't do it. Since much of our group // awareness comes from the other tools, enabling this produces @@ -953,6 +955,10 @@ private boolean makePage(Element element, String oldServer, String siteId, Strin String groupString = mergeGroups(itemElement, "groups", siteGroups, fromSiteId); if (groupString != null) item.setGroups(groupString); + + if (gradebookIfc.isGradebookGroupEnabled(siteId)) { + gradebookUids = gradebookIfc.getGradebookGroupInstances(siteId); + } } NodeList attributes = itemElement.getElementsByTagName("attributes"); @@ -990,7 +996,7 @@ private boolean makePage(Element element, String oldServer, String siteId, Strin } try { - gradebookIfc.addExternalAssessment(siteId, s, null, title, Double.valueOf(itemElement.getAttribute("gradebookPoints")), null, LessonBuilderConstants.TOOL_ID); + gradebookIfc.addExternalAssessment(gradebookUids, siteId, s, null, title, Double.valueOf(itemElement.getAttribute("gradebookPoints")), null, LessonBuilderConstants.TOOL_ID); needupdate = true; item.setGradebookId(s); } catch(ConflictingAssignmentNameException cane){ @@ -1016,7 +1022,7 @@ private boolean makePage(Element element, String oldServer, String siteId, Strin title = title.substring(0, ii+1) + item.getId() + ")"; } try { - gradebookIfc.addExternalAssessment(siteId, s, null, title, Double.valueOf(itemElement.getAttribute("altPoints")), null, LessonBuilderConstants.TOOL_ID); + gradebookIfc.addExternalAssessment(gradebookUids, siteId, s, null, title, Double.valueOf(itemElement.getAttribute("altPoints")), null, LessonBuilderConstants.TOOL_ID); needupdate = true; item.setAltGradebook(s); } catch(ConflictingAssignmentNameException cane){ @@ -1240,7 +1246,7 @@ public String merge(String siteId, Element root, String archivePath, String from simplePageToolDao.quickSaveItem(page); if (StringUtils.isNotEmpty(gradebookPoints)) { try { - gradebookIfc.addExternalAssessment(siteId, "lesson-builder:" + page.getPageId(), null, + gradebookIfc.addExternalAssessment(Arrays.asList(siteId), siteId, "lesson-builder:" + page.getPageId(), null, title, Double.valueOf(gradebookPoints), null, LessonBuilderConstants.TOOL_ID); } catch(ConflictingAssignmentNameException cane){ log.error("merge: ConflictingAssignmentNameException for title {}.", title); diff --git a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/GradingBean.java b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/GradingBean.java index 6e5b3ed3268e..74eadd6d2b90 100644 --- a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/GradingBean.java +++ b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/GradingBean.java @@ -16,6 +16,7 @@ package org.sakaiproject.lessonbuildertool.tool.beans; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; @@ -137,7 +138,13 @@ private boolean gradeComment() { } try { - r = gradebookIfc.updateExternalAssessmentScore(simplePageBean.getCurrentSiteId(), gradebookId, comment.getAuthor(), Double.toString(newpoints)); + List gradebookUids = Arrays.asList(simplePageBean.getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(simplePageBean.getCurrentSiteId())) { + gradebookUids = new ArrayList(simplePageBean.getItemGroups(topItem, null, false)); + } + for (String gradebookUid : gradebookUids) { + r = gradebookIfc.updateExternalAssessmentScore(gradebookUid, simplePageBean.getCurrentSiteId(), gradebookId, comment.getAuthor(), Double.toString(newpoints)); + } }catch(Exception ex) { log.error(ex.getMessage(), ex); } @@ -190,19 +197,26 @@ private boolean gradeStudentPage() { try { String owner = page.getOwner(); String group = page.getGroup(); - if (group == null) - r = gradebookIfc.updateExternalAssessmentScore(simplePageBean.getCurrentSiteId(), pageItem.getGradebookId(), page.getOwner(), Double.toString(newpoints)); - else { - group = "/site/" + simplePageBean.getCurrentSiteId() + "/group/" + group; - AuthzGroup g = ComponentManager.get(AuthzGroupService.class).getAuthzGroup(group); - Set members = g.getMembers(); - // if we have more than one user, in theory some might fail and some succeed. For the - // moment just update the grade - r = true; - for (Member m: members) - gradebookIfc.updateExternalAssessmentScore(simplePageBean.getCurrentSiteId(), pageItem.getGradebookId(), - m.getUserId(), Double.toString(newpoints)); - } + if (group == null) { + List gradebookUids = Arrays.asList(simplePageBean.getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(simplePageBean.getCurrentSiteId())) { + gradebookUids = new ArrayList(simplePageBean.getItemGroups(pageItem, null, false)); + } + for (String gradebookUid : gradebookUids) { + r = gradebookIfc.updateExternalAssessmentScore(gradebookUid, simplePageBean.getCurrentSiteId(), pageItem.getGradebookId(), page.getOwner(), Double.toString(newpoints)); + } + } else { + group = "/site/" + simplePageBean.getCurrentSiteId() + "/group/" + group; + AuthzGroup g = ComponentManager.get(AuthzGroupService.class).getAuthzGroup(group); + Set members = g.getMembers(); + // if we have more than one user, in theory some might fail and some succeed. For the + // moment just update the grade + r = true; + for (Member m: members) { + gradebookIfc.updateExternalAssessmentScore(group, simplePageBean.getCurrentSiteId(), pageItem.getGradebookId(), + m.getUserId(), Double.toString(newpoints)); + } + } }catch(Exception ex) { log.info("Exception updating grade " + ex); } @@ -230,7 +244,13 @@ private boolean gradeQuestion() { return false; } try { - r = gradebookIfc.updateExternalAssessmentScore(simplePageBean.getCurrentSiteId(), questionItem.getGradebookId(), response.getUserId(), Double.toString(newpoints)); + List gradebookUids = Arrays.asList(simplePageBean.getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(simplePageBean.getCurrentSiteId())) { + gradebookUids = new ArrayList(simplePageBean.getItemGroups(questionItem, null, false)); + } + for (String gradebookUid : gradebookUids) { + r = gradebookIfc.updateExternalAssessmentScore(gradebookUid, simplePageBean.getCurrentSiteId(), questionItem.getGradebookId(), response.getUserId(), Double.toString(newpoints)); + } }catch(Exception ex) { log.info("Exception updating grade " + ex); } diff --git a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/SimplePageBean.java b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/SimplePageBean.java index f3274b4f20ed..ef12e3dfb41e 100644 --- a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/SimplePageBean.java +++ b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/tool/beans/SimplePageBean.java @@ -4518,11 +4518,15 @@ public String editTitle() { } // adjust gradebook entry boolean add = false; + List gradebookUids = Arrays.asList(site.getId()); + if (gradebookIfc.isGradebookGroupEnabled(site.getId())) { + gradebookUids = gradebookIfc.getGradebookGroupInstances(site.getId()); + } if (newPoints == null && currentPoints != null) { add = gradebookIfc.removeExternalAssessment(site.getId(), "lesson-builder:" + page.getPageId()); } else if (newPoints != null && currentPoints == null) { try { - add = gradebookIfc.addExternalAssessment(site.getId(), "lesson-builder:" + page.getPageId(), null, + add = gradebookIfc.addExternalAssessment(gradebookUids, site.getId(), "lesson-builder:" + page.getPageId(), null, pageTitle, newPoints, null, LessonBuilderConstants.TOOL_ID); } catch(ConflictingAssignmentNameException cane) { add = false; @@ -4534,7 +4538,7 @@ public String editTitle() { needRecompute = true; } else if (currentPoints != null && (!currentPoints.equals(newPoints) || !pageTitle.equals(page.getTitle()))) { - add = gradebookIfc.updateExternalAssessment(site.getId(), "lesson-builder:" + page.getPageId(), null, + add = gradebookIfc.updateExternalAssessment(gradebookUids, "lesson-builder:" + page.getPageId(), null, pageTitle, newPoints, null); if(!add) { setErrMessage(messageLocator.getMessage("simplepage.no-gradebook")); @@ -5079,21 +5083,40 @@ public SimplePage addPage(String title, Long pageId, boolean copyCurrent, boolea return page; } - // when a gradebook entry is added or point value for page changed, need to - // add or update all student entries for the page - // this only updates grades for users that are complete. Others should have 0 score, which won't change + // when a gradebook entry is added or point value for page changed, need to + // add or update all student entries for the page + // this only updates grades for users that are complete. Others should have 0 score, which won't change public void recomputeGradebookEntries(Long pageId, String newPoints) { - Map userMap = new HashMap<>(); - List items = simplePageToolDao.findPageItemsBySakaiId(Long.toString(pageId)); - if (items == null) - return; - for (SimplePageItem item : items) { - List users = simplePageToolDao.findUserWithCompletePages(item.getId()); - for (String user: users) - userMap.put(user, newPoints); - } - - gradebookIfc.updateExternalAssessmentScores(getCurrentSiteId(), "lesson-builder:" + pageId, userMap); + Map userMap = new HashMap<>(); + List items = simplePageToolDao.findPageItemsBySakaiId(Long.toString(pageId)); + if (items == null) + return; + List gradebookUids = Arrays.asList(getCurrentSiteId()); + Set gbGroups = new HashSet<>(); + for (SimplePageItem item : items) { + List users = simplePageToolDao.findUserWithCompletePages(item.getId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + try { + Collection groupsAux = getItemGroups(item, null, false); + if (groupsAux != null) { + gbGroups.addAll(groupsAux); + } + } catch (Exception e) { + log.error("Error getting groups for item {} : {} ", item.getId(), e.getMessage()); + } + } + + for (String user: users) { + userMap.put(user, newPoints); + } + } + + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId()) && !gbGroups.isEmpty()) { + gradebookUids = new ArrayList<>(gbGroups); + } + for (String gradebookUid : gradebookUids) { + gradebookIfc.updateExternalAssessmentScores(gradebookUid, getCurrentSiteId(), "lesson-builder:" + pageId, userMap); + } } // there's one of these in Validator, but it isn't quite right, because it doesn't look at / @@ -5337,9 +5360,10 @@ public String getCurrentUserId() { // and something changes so it is no longer complete. public void trackComplete(SimplePageItem item, boolean complete ) { SimplePage page = getCurrentPage(); - if (page.getGradebookPoints() != null) - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), "lesson-builder:" + page.getPageId(), getCurrentUserId(), + if (page.getGradebookPoints() != null) { + gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), getCurrentSiteId(), "lesson-builder:" + page.getPageId(), getCurrentUserId(), complete ? Double.toString(page.getGradebookPoints()) : "0.0"); + } } /** @@ -7476,17 +7500,20 @@ public String updateComments() { String gradebookId; boolean add = true; - + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + gradebookUids = Arrays.asList(selectedGroups); + } if(comment.getPageId() >= 0) { pageTitle = getPage(comment.getPageId()).getTitle(); gradebookId = "lesson-builder:comment:" + comment.getId(); if(comment.getGradebookId() != null && !comment.getGradebookPoints().equals(points)) { - add = gradebookIfc.updateExternalAssessment(getCurrentSiteId(), "lesson-builder:comment:" + comment.getId(), null, + add = gradebookIfc.updateExternalAssessment(gradebookUids, "lesson-builder:comment:" + comment.getId(), null, pageTitle + " Comments (item:" + comment.getId() + ")", Integer.valueOf(maxPoints), null); } else { try { - add = gradebookIfc.addExternalAssessment(getCurrentSiteId(), "lesson-builder:comment:" + comment.getId(), null, + add = gradebookIfc.addExternalAssessment(gradebookUids, getCurrentSiteId(), "lesson-builder:comment:" + comment.getId(), null, pageTitle + " Comments (item:" + comment.getId() + ")", Integer.valueOf(maxPoints), null, LessonBuilderConstants.TOOL_ID); } catch(ConflictingAssignmentNameException cane) { add = false; @@ -7541,7 +7568,7 @@ private void regradeComments(SimplePageItem comment) { List comments = simplePageToolDao.findComments(comment.getId()); for(SimplePageComment c : comments) { if(c.getPoints() != null) { - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), comment.getGradebookId(), + gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), getCurrentSiteId(), comment.getGradebookId(), c.getAuthor(), String.valueOf(c.getPoints())); } } @@ -7898,6 +7925,10 @@ public String updateQuestion() { if (!graded || (gradebookTitle != null && gradebookTitle.trim().equals(""))) gradebookTitle = null; + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + gradebookUids = Arrays.asList(selectedGroups); + } if(gradebookTitle != null && (item.getGradebookId() == null || item.getGradebookId().equals(""))) { // Creating new gradebook entry if (itemId != null && itemId < 0) { @@ -7911,7 +7942,7 @@ public String updateQuestion() { } try { - boolean add = gradebookIfc.addExternalAssessment(getCurrentSiteId(), gradebookId, null, title, pointsInt, null, LessonBuilderConstants.TOOL_ID); + boolean add = gradebookIfc.addExternalAssessment(gradebookUids, getCurrentSiteId(), gradebookId, null, title, pointsInt, null, LessonBuilderConstants.TOOL_ID); if(!add) { setErrMessage(messageLocator.getMessage("simplepage.no-gradebook")); }else { @@ -7924,7 +7955,7 @@ public String updateQuestion() { }else if(gradebookTitle != null) { // Updating an old gradebook entry - gradebookIfc.updateExternalAssessment(getCurrentSiteId(), item.getGradebookId(), null, gradebookTitle, pointsInt, null); + gradebookIfc.updateExternalAssessment(gradebookUids, item.getGradebookId(), null, gradebookTitle, pointsInt, null); item.setGradebookTitle(gradebookTitle); }else if(gradebookTitle == null && (item.getGradebookId() != null && !item.getGradebookId().equals(""))) { @@ -8063,7 +8094,7 @@ private boolean gradeQuestionResponse(SimplePageQuestionResponse response) { response.setPoints(gradebookPoints); if(question.getGradebookId() != null && !question.getGradebookId().equals("")) { - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), question.getGradebookId(), + gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), getCurrentSiteId(), question.getGradebookId(), response.getUserId(), String.valueOf(gradebookPoints)); } } @@ -8235,12 +8266,17 @@ public String updateStudent() { if(page.getGradebookId() == null || !page.getGradebookPoints().equals(points) || !page.getGradebookTitle().equals(gradebookTitle)) { boolean add; + + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + gradebookUids = Arrays.asList(selectedGroups); + } if (page.getGradebookId() != null && (!page.getGradebookPoints().equals(points) || !page.getGradebookTitle().equals(gradebookTitle))) { - add = gradebookIfc.updateExternalAssessment(getCurrentSiteId(), "lesson-builder:page:" + page.getId(), null, gradebookTitle, Integer.valueOf(maxPoints), null); + add = gradebookIfc.updateExternalAssessment(gradebookUids, "lesson-builder:page:" + page.getId(), null, gradebookTitle, Integer.valueOf(maxPoints), null); } else { try { - add = gradebookIfc.addExternalAssessment(getCurrentSiteId(), "lesson-builder:page:" + page.getId(), null, gradebookTitle, Integer.valueOf(maxPoints), null, LessonBuilderConstants.TOOL_ID); + add = gradebookIfc.addExternalAssessment(gradebookUids, getCurrentSiteId(), "lesson-builder:page:" + page.getId(), null, gradebookTitle, Integer.valueOf(maxPoints), null, LessonBuilderConstants.TOOL_ID); } catch(ConflictingAssignmentNameException cane) { add = false; setErrMessage(messageLocator.getMessage("simplepage.existing-gradebook")); @@ -8274,13 +8310,17 @@ public String updateStudent() { if(page.getAltGradebook() == null || !page.getAltPoints().equals(points)) { String title = getPage(page.getPageId()).getTitle() + " Student Page Comments (item:" + page.getId() + ")"; - boolean add; + boolean add; + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + gradebookUids = Arrays.asList(selectedGroups); + } if(page.getAltGradebook() != null && !page.getAltPoints().equals(points)) { - add = gradebookIfc.updateExternalAssessment(getCurrentSiteId(), "lesson-builder:page-comment:" + page.getId(), null, + add = gradebookIfc.updateExternalAssessment(gradebookUids, "lesson-builder:page-comment:" + page.getId(), null, title, points, null); } else { try { - add = gradebookIfc.addExternalAssessment(getCurrentSiteId(), "lesson-builder:page-comment:" + page.getId(), null, + add = gradebookIfc.addExternalAssessment(gradebookUids, getCurrentSiteId(), "lesson-builder:page-comment:" + page.getId(), null, title, points, null, LessonBuilderConstants.TOOL_ID); } catch(ConflictingAssignmentNameException cane) { add = false; @@ -8374,7 +8414,17 @@ public String missingStudentSetZero() { owners.add(owner); } for (String userid: owners) { - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), gradebookId, userid, "0.0"); + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + try { + gradebookUids = new ArrayList(getItemGroups(item, null, false)); + } catch (Exception e) { + log.error("Error getting groups for item {} : {}", item.getId(), e.getMessage()); + } + } + for (String gradebookUid : gradebookUids) { + gradebookIfc.updateExternalAssessmentScore(gradebookUid, getCurrentSiteId(), gradebookId, userid, "0.0"); + } } } @@ -8446,7 +8496,17 @@ public String missingCommentsSetZero() { // now zero grade for (String owner: notSubmitted) { - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), gradebookId, owner, "0.0"); + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + try { + gradebookUids = new ArrayList(getItemGroups(commentItem, null, false)); + } catch (Exception e) { + log.error("Error getting groups for item {} : {}", commentItem.getId(), e.getMessage()); + } + } + for (String gradebookUid : gradebookUids) { + gradebookIfc.updateExternalAssessmentScore(gradebookUid, getCurrentSiteId(), gradebookId, owner, "0.0"); + } } return "success"; @@ -8491,7 +8551,17 @@ public String missingAnswersSetZero() { // now zero grade for (String owner: notSubmitted) { - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), gradebookId, owner, "0.0"); + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + try { + gradebookUids = new ArrayList(getItemGroups(questionItem, null, false)); + } catch (Exception e) { + log.error("Error getting groups for item {} : {}", questionItem.getId(), e.getMessage()); + } + } + for (String gradebookUid : gradebookUids) { + gradebookIfc.updateExternalAssessmentScore(gradebookUid, getCurrentSiteId(), gradebookId, owner, "0.0"); + } } return "success"; @@ -8523,10 +8593,19 @@ private void regradeStudentPages(SimplePageItem pageItem) { List pages = simplePageToolDao.findStudentPages(pageItem.getId()); for(SimpleStudentPage c : pages) { if(c.getPoints() != null) { - if( c.getGroup() == null) - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), pageItem.getGradebookId(), - c.getOwner(), String.valueOf(c.getPoints())); - else { + if( c.getGroup() == null) { + List gradebookUids = Arrays.asList(getCurrentSiteId()); + if (gradebookIfc.isGradebookGroupEnabled(getCurrentSiteId())) { + try { + gradebookUids = new ArrayList(getItemGroups(pageItem, null, false)); + } catch (Exception e) { + log.error("Error getting groups for item {} : {}", pageItem.getId(), e.getMessage()); + } + } + for (String gradebookUid : gradebookUids) { + gradebookIfc.updateExternalAssessmentScore(gradebookUid, getCurrentSiteId(), pageItem.getGradebookId(), c.getOwner(), String.valueOf(c.getPoints())); + } + } else { String group = c.getGroup(); if (group != null) group = "/site/" + getCurrentSiteId() + "/group/" + group; @@ -8534,7 +8613,7 @@ private void regradeStudentPages(SimplePageItem pageItem) { AuthzGroup g = authzGroupService.getAuthzGroup(group); Set members = g.getMembers(); for (Member m: members) { - gradebookIfc.updateExternalAssessmentScore(getCurrentSiteId(), pageItem.getGradebookId(), + gradebookIfc.updateExternalAssessmentScore(group, getCurrentSiteId(), pageItem.getGradebookId(), m.getUserId(), String.valueOf(c.getPoints())); } } catch (Exception e) { diff --git a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties index b1540c0c1e7d..b2cd36537b83 100644 --- a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties +++ b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties @@ -356,6 +356,7 @@ cdfm_select_assign = Select a Gradebook item cdfm_comments = Comments: cdfm_notification = Send Notification cdfm_submit_grade = Submit Grade +cdfm_send_info = Send item cdfm_cancel = Cancel cdfm_prev_msg = < Previous Message cdfm_next_msg = Next Message > @@ -1002,3 +1003,7 @@ pvt_read_receipt_email_subject={0} has been read pvt_tags_header=Tags pvt_tags_save=Save Tags pvt_enter_search_tags=Please select tags for search. + +cdfm_gradebook_group_selector_instructions=Please, select only one item from the gradebook for groups selector +cdfm_gradebook_group_selector_error=You have selected more than one item in the gradebook for groups selector +cdfm_gradebook_group_selector_select_button=Select Item diff --git a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_ca.properties b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_ca.properties index a43cc0d62f5c..87267f41056f 100644 --- a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_ca.properties +++ b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_ca.properties @@ -353,6 +353,7 @@ cdfm_select_assign=Seleccioneu un element de qualificaci\u00f3 cdfm_comments=Comentaris\: cdfm_notification=La notificaci\u00f3 ha estat enviada cdfm_submit_grade=Envia la qualificaci\u00f3 +cdfm_send_info = Envia \u00edtem cdfm_cancel=Cancel\u00b7la cdfm_prev_msg=< Missatge anterior cdfm_next_msg=Missatge seg\u00fcent > diff --git a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties index cff7d5c5da1a..569979c09cfc 100644 --- a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties +++ b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties @@ -353,6 +353,7 @@ cdfm_select_assign=Seleccione un \u00edtem de Calificaciones cdfm_comments=Comentarios\: cdfm_notification=Enviar notificaci\u00f3n cdfm_submit_grade=Enviar calificaci\u00f3n +cdfm_send_info = Enviar \u00edtem cdfm_cancel=Cancelar cdfm_prev_msg=< Mensaje anterior cdfm_next_msg=Mensaje siguiente > @@ -996,3 +997,7 @@ pvt_read_receipt_email_subject={0} ha sido le\u00eddo pvt_tags_header=Etiquetas pvt_tags_save=Guardar Etiquetas pvt_enter_search_tags=Introduzca etiquetas de b\u00fasqueda. + +cdfm_gradebook_group_selector_instructions=Por favor, elija s\u00f3lo un elemento en el selector de calificaciones por grupos +cdfm_gradebook_group_selector_error=Has seleccionado m\u00e1s de un elemento en el selector de calificaciones por grupos +cdfm_gradebook_group_selector_select_button=Seleccionar elemento diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java index 959277825175..0a99b8460307 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java @@ -131,8 +131,10 @@ import org.sakaiproject.portal.util.PortalUtils; import org.sakaiproject.grading.api.AssessmentNotFoundException; import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.grading.api.GradeDefinition; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; @@ -674,16 +676,27 @@ public List getForums() { //Code to get the gradebook service from ComponentManager GradingService gradingService = getGradingService(); - - for (Assignment thisAssign : gradingService.getAssignments(toolManager.getCurrentPlacement().getContext())) { - if (!thisAssign.getExternallyMaintained()) { - try { - assignments.add(new SelectItem(Long.toString(thisAssign.getId()), thisAssign.getName())); - } catch (Exception e) { - log.error("DiscussionForumTool - processDfMsgGrd:" + e); + if (gradingService.isGradebookGroupEnabled(toolManager.getCurrentPlacement().getContext())) { + List gradeAssignments = gradingService.getGradebookGroupInstances(toolManager.getCurrentPlacement().getContext()); + for(int i=0; i groupAssignments = gradingService.getAssignments(gradeAssignments.get(i).getId().toString(), toolManager.getCurrentPlacement().getContext(), SortType.SORT_BY_NONE); + for (Assignment assignment: groupAssignments) { + assignments.add(new SelectItem(Long.toString(assignment.getId()), assignment.getName())); + } } - } + } else { + List gradeAssignmentsBeforeFilter = gradingService.getAssignments(toolManager.getCurrentPlacement().getContext(), toolManager.getCurrentPlacement().getContext(), SortType.SORT_BY_NONE); + for (Assignment thisAssign : gradingService.getAssignments(toolManager.getCurrentPlacement().getContext(), toolManager.getCurrentPlacement().getContext(), SortType.SORT_BY_NONE)) { + if (!thisAssign.getExternallyMaintained()) { + try { + assignments.add(new SelectItem(Long.toString(thisAssign.getId()), thisAssign.getName())); + } catch (Exception e) { + log.error("DiscussionForumTool - processDfMsgGrd:" + e); + } + } + } } + } catch (SecurityException se) { log.debug("SecurityException caught while getting assignments.", se); } catch (Exception e1) { @@ -1464,7 +1477,7 @@ private DiscussionForum saveForumSettings(boolean draft) if (!draft && gradeAssign != null) { GradingService gradingService = getGradingService(); String gradebookUid = toolManager.getCurrentPlacement().getContext(); - Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, gradeAssign); + Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, gradebookUid, gradeAssign); Date dueDate = (assignment != null ? assignment.getDueDate() : null); String reference = DiscussionForumService.REFERENCE_ROOT + SEPARATOR + getSiteId() + SEPARATOR + forum.getId(); Optional optTask = taskService.getTask(reference); @@ -1969,7 +1982,7 @@ private String saveTopicSettings(boolean draft) if (!draft) { GradingService gradingService = getGradingService(); String gradebookUid = toolManager.getCurrentPlacement().getContext(); - Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, gradeAssign); + Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, gradebookUid, gradeAssign); Date dueDate = (assignment != null ? assignment.getDueDate() : null); String reference = DiscussionForumService.REFERENCE_ROOT + SEPARATOR + getSiteId() + SEPARATOR + topic.getBaseForum().getId() + TOPIC_REF + topic.getId(); Optional optTask = taskService.getTask(reference); @@ -4489,7 +4502,7 @@ private String processDfMsgGrdHelper(String userId, String msgAssignmentName) { try { if (selAssignmentName != null) { - setUpGradeInformation(gradebookUid, selAssignmentName, userId); + setUpGradeInformation(gradebookUid, toolManager.getCurrentPlacement().getContext(), selAssignmentName, userId);//TODO JUANDAVID pasar el/los gradebookuid que toque } else { // this is the "Select a gradebook item" selection allowedToGradeItem = false; @@ -4519,14 +4532,14 @@ private String processDfMsgGrdHelper(String userId, String msgAssignmentName) { return GRADE_MESSAGE; } - private void setUpGradeInformation(String gradebookUid, String selAssignmentName, String studentId) { + private void setUpGradeInformation(String gradebookUid, String siteId, String selAssignmentName, String studentId) { GradingService gradingService = getGradingService(); if (gradingService == null) return; - Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, selAssignmentName); + Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, siteId, selAssignmentName); // first, check to see if user is authorized to view or grade this item in the gradebook - String function = gradingService.getGradeViewFunctionForUserForStudentForItem(gradebookUid, assignment.getId(), studentId); + String function = gradingService.getGradeViewFunctionForUserForStudentForItem(gradebookUid, siteId, assignment.getId(), studentId); if (function == null) { allowedToGradeItem = false; selGBItemRestricted = true; @@ -4560,7 +4573,7 @@ private void setUpGradeInformation(String gradebookUid, String selAssignmentName gbItemPointsPossible = ((DecimalFormat) numberFormat).format(assignment.getPoints()); } - GradeDefinition gradeDef = gradingService.getGradeDefinitionForStudentForItem(gradebookUid, assignment.getId(), studentId); + GradeDefinition gradeDef = gradingService.getGradeDefinitionForStudentForItem(gradebookUid, siteId, assignment.getId(), studentId); if (gradeDef.getGrade() != null) { String decSeparator = formattedText.getDecimalSeparator(); @@ -5972,6 +5985,7 @@ private void resetGradeInfo() { gbItemComment = null; gradeComment = null; gbItemPointsPossible = null; + currentChange = null; } public String processDfGradeCancel() @@ -5995,16 +6009,25 @@ public String processDfGradeCancelFromDialog() getThreadFromMessage(); return null; } + + public String currentChange; + public void setCurrentChange(String newChange){ + currentChange = newChange; + } + public String getCurrentChange(){ + return currentChange; + } - public String processGradeAssignChange(ValueChangeEvent vce) - { - String changeAssign = (String) vce.getNewValue(); - if (changeAssign == null) + public void processGradeAssignSend() + { + String changeAssign = currentChange; // Set value + if (changeAssign == null || changeAssign.equals("") || changeAssign.split(",").length > 1) { - return null; + setErrorMessage(getResourceBundleString("cdfm_select_assign")); } else - { + { + try { selectedAssign = changeAssign; @@ -6012,29 +6035,44 @@ public String processGradeAssignChange(ValueChangeEvent vce) if(!DEFAULT_GB_ITEM.equalsIgnoreCase(selectedAssign)) { String gradebookUid = toolManager.getCurrentPlacement().getContext(); + if (isGradebookGroupEnabled()) { + boolean exit = false; + List gradebookGroupInstances = getGradingService().getGradebookGroupInstances(gradebookUid); + int i = 0; + while (!exit && i < gradebookGroupInstances.size()) { + Gradebook gradebookGroup = gradebookGroupInstances.get(i); + List groupAssignments = getGradingService().getAssignments(gradebookGroup.getUid().toString(), toolManager.getCurrentPlacement().getContext(), SortType.SORT_BY_NONE); + int z = 0; + while (!exit && z < groupAssignments.size()) { + Assignment assignment = groupAssignments.get(z); + if (assignment.getId().toString().equals(selectedAssign)) { + gradebookUid = gradebookGroup.getUid().toString(); + exit = true; + } + z++; + } + i++; + } + } String studentId; if(selectedMessage == null && selectedGradedUserId != null && !"".equals(selectedGradedUserId)){ studentId = selectedGradedUserId; }else{ studentId = userDirectoryService.getUser(selectedMessage.getMessage().getCreatedBy()).getId(); } - - setUpGradeInformation(gradebookUid, selectedAssign, studentId); + setUpGradeInformation(gradebookUid, toolManager.getCurrentPlacement().getContext(), selectedAssign, studentId); } else { // this is the "Select a gradebook item" option allowedToGradeItem = false; selGBItemRestricted = true; } - - return GRADE_MESSAGE; } catch(Exception e) { - log.error("processGradeAssignChange in DiscussionFOrumTool - " + e); - return null; + log.error("processGradeAssignSend in DiscussionForumTool - " + e); } - } - } + } + } public boolean isNumber(String validateString) { @@ -6171,15 +6209,35 @@ public String processDfGradeSubmit() String studentUid = null; try { + String siteId = toolManager.getCurrentPlacement().getContext(); String gradebookUuid = toolManager.getCurrentPlacement().getContext(); + if (isGradebookGroupEnabled()) { + boolean exit = false; + List gradebookGroupInstances = getGradingService().getGradebookGroupInstances(gradebookUuid); + int i = 0; + while (!exit && i < gradebookGroupInstances.size()) { + Gradebook gradebookGroup = gradebookGroupInstances.get(i); + List groupAssignments = getGradingService().getAssignments(gradebookGroup.getUid().toString(), toolManager.getCurrentPlacement().getContext(), SortType.SORT_BY_NONE); + int z = 0; + while (!exit && z < groupAssignments.size()) { + Assignment assignment = groupAssignments.get(z); + if (assignment.getId().toString().equals(selectedAssign)) { + gradebookUuid = gradebookGroup.getUid().toString(); + exit = true; + } + z++; + } + i++; + } + } if(selectedMessage == null && selectedGradedUserId != null && !"".equals(selectedGradedUserId)){ studentUid = selectedGradedUserId; }else{ studentUid = userDirectoryService.getUser(selectedMessage.getMessage().getCreatedBy()).getId(); } - Long gbItemId = gradingService.getAssignmentByNameOrId(gradebookUuid, selectedAssign).getId(); - gradingService.saveGradeAndCommentForStudent(gradebookUuid, gbItemId, studentUid, gradePoint, gradeComment); + Long gbItemId = gradingService.getAssignmentByNameOrId(gradebookUuid, siteId, selectedAssign).getId(); + gradingService.saveGradeAndCommentForStudent(gradebookUuid, siteId, gbItemId, studentUid, gradePoint, gradeComment); if(selectedMessage != null){ @@ -9494,4 +9552,8 @@ public String getAttachmentReadableSize(final String attachmentSize) { return FileUtils.byteCountToDisplaySize(Long.parseLong(attachmentSize)); } + public boolean isGradebookGroupEnabled() { + return getGradingService().isGradebookGroupEnabled(toolManager.getCurrentPlacement().getContext()); + } + } diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java index b51bb30752f7..78190757a8fa 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java @@ -76,6 +76,7 @@ import org.sakaiproject.grading.api.GradeDefinition; import org.sakaiproject.grading.api.GradingConstants; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.tool.api.ToolManager; @@ -89,6 +90,7 @@ import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; +import org.sakaiproject.grading.api.model.Gradebook; @Slf4j @ManagedBean(name="mfStatisticsBean") @@ -328,6 +330,7 @@ public void setGradebookAssignment( private String buttonUserName; private boolean isFirstParticipant = false; private boolean isLastParticipant = false; + public boolean selectMoreThanOneItem = false; //Comparatibles public static Comparator nameComparatorAsc; @@ -965,6 +968,15 @@ public List getGradeStatisticsForStatsListByTopic() // Determine if something has changed that warrants the cached gradeStatistics to be refreshed // Has the selected gradebook assignment or the selected group changed since the gradeStatistics were cached? boolean refreshCachedStatistics = !StringUtils.equals(m_gradeStatisticsAssign, selectedAssign) || !StringUtils.equals(m_gradeStatisticsGroup, selectedGroup); + + // That if detect if there are more than 1 item and shows the error message + // And the else it is to detect if the user has sent any item after sending more than 1 item + if (selectedAssign.split(",").length > 1) { + setSelectMoreThanOneItem(true); + selectedAssign = DEFAULT_GB_ITEM; + } else if (!selectedAssign.equals(DEFAULT_GB_ITEM)){ + setSelectMoreThanOneItem(false); + } if (!refreshCachedStatistics) { // Are we sorting on a different column? @@ -2712,6 +2724,14 @@ public String getSelectedAllTopicsForumTitle() { public void setSelectedAllTopicsForumTitle(String selectedAllTopicsForumTitle) { this.selectedAllTopicsForumTitle = selectedAllTopicsForumTitle; } + + public boolean getSelectMoreThanOneItem() { + return selectMoreThanOneItem; + } + + public void setSelectMoreThanOneItem(boolean selectMoreThanOneItem) { + this.selectMoreThanOneItem = selectMoreThanOneItem; + } public String getSelectedAllTopicsForumId() { return selectedAllTopicsForumId; @@ -2729,7 +2749,7 @@ public void setSelectedAllTopicsTopicId(String selectedAllTopicsTopicId) { this.selectedAllTopicsTopicId = selectedAllTopicsTopicId; } - protected GradingService getGradingService() { + public GradingService getGradingService() { return (GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); } @@ -2741,18 +2761,27 @@ public void setUpGradebookAssignments(){ //Code to get the gradebook service from ComponentManager GradingService gradingService = getGradingService(); - - List gradeAssignmentsBeforeFilter = gradingService.getAssignments(toolManager.getCurrentPlacement().getContext()); - for(int i=0; i gradeAssignments = gradingService.getGradebookGroupInstances(toolManager.getCurrentPlacement().getContext()); + for(int i=0; i groupAssignments = gradingService.getAssignments(gradeAssignments.get(i).getUid(), toolManager.getCurrentPlacement().getContext(), SortType.SORT_BY_NONE); + for (Assignment assignment: groupAssignments) { + assignments.add(new SelectItem(Long.toString(assignment.getId()), assignment.getName(), assignment.getPoints().toString() + "," + gradeAssignments.get(i).getUid())); + } + } + } else { + List gradeAssignmentsBeforeFilter = gradingService.getAssignments(toolManager.getCurrentPlacement().getContext(), toolManager.getCurrentPlacement().getContext(), SortType.SORT_BY_NONE); + for(int i=0; i ((String)n.getValue()).equals(selectedAssign.split("\",")[0])) + .findFirst().get()) + .getDescription().split("\",")[0]; + } + return null; + } public String processGroupChange(ValueChangeEvent vce) { @@ -2818,7 +2858,7 @@ public void setDefaultSelectedAssign(){ } if (StringUtils.isNotBlank(defaultAssignName)) { try { - Assignment assignment = getGradingService().getAssignmentByNameOrId(toolManager.getCurrentPlacement().getContext(), defaultAssignName); + Assignment assignment = getGradingService().getAssignmentByNameOrId(toolManager.getCurrentPlacement().getContext(), toolManager.getCurrentPlacement().getContext(), defaultAssignName); setDefaultSelectedAssign(assignment.getName()); } catch (Exception ex) { log.warn("MessageForumStatisticsBean - setDefaultSelectedAssign: " + ex); @@ -2859,14 +2899,23 @@ private void setDefaultSelectedAssign(final String assign){ private Map getGradebookAssignment(){ Map returnVal = new HashMap(); - if(!DEFAULT_GB_ITEM.equalsIgnoreCase(selectedAssign)) { String gradebookUid = toolManager.getCurrentPlacement().getContext(); - selAssignName = ((SelectItem)assignments.get((Integer.valueOf(selectedAssign)).intValue())).getLabel(); + String siteId = toolManager.getCurrentPlacement().getContext(); + assignments = getAssignments(); + + SelectItem currentItem = ((SelectItem)assignments.stream() + .filter(n -> ((String) n.getValue()).equals(selectedAssign)) + .findFirst().get()); + selAssignName = currentItem.getLabel(); GradingService gradingService = getGradingService(); if (gradingService == null) return returnVal; + if (gradingService.isGradebookGroupEnabled(siteId)) { + gradebookUid = currentItem.getDescription().split(",")[1]; + } + Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, siteId, selAssignName); Integer gradeEntryType = gradingService.getGradeEntryType(gradebookUid); if (Objects.equals(gradeEntryType, GradingConstants.GRADE_TYPE_LETTER)) { @@ -2883,24 +2932,36 @@ private Map getGradebookAssignment(){ gradeByLetter = false; } - Assignment assignment = gradingService.getAssignmentByNameOrId(gradebookUid, selAssignName); if(assignment != null){ - gbItemPointsPossible = assignment.getPoints().toString(); - + gbItemPointsPossible = assignment.getPoints().toString(); //grab all grades for the id's that the user is able to grade: - Map studentIdFunctionMap = gradingService.getViewableStudentsForItemForCurrentUser(gradebookUid, assignment.getId()); - List grades = gradingService.getGradesForStudentsForItem(gradebookUid, assignment.getId(), new ArrayList(studentIdFunctionMap.keySet())); + String userUid = sessionManager.getCurrentSessionUserId(); + Map studentIdFunctionMap; + studentIdFunctionMap = gradingService.getViewableStudentsForItemForUser(userUid, gradebookUid, siteId, assignment.getId()); + List grades = gradingService.getGradesForStudentsForItem(gradebookUid, gradebookUid, assignment.getId(), new ArrayList(studentIdFunctionMap.keySet())); //add grade values to return map String decSeparator = formattedText.getDecimalSeparator(); - for(GradeDefinition gradeDef : grades){ - String studentUuid = gradeDef.getStudentUid(); + for(GradeDefinition gradeDef : grades) { + String studentUuid = gradeDef.getStudentUid(); DecoratedGradebookAssignment gradeAssignment = new DecoratedGradebookAssignment(); - gradeAssignment.setAllowedToGrade(true); + gradeAssignment.setAllowedToGrade(true); gradeAssignment.setScore(StringUtils.replace(gradeDef.getGrade(), (",".equals(decSeparator)?".":","), decSeparator)); gradeAssignment.setComment(gradeDef.getGradeComment()); gradeAssignment.setName(selAssignName); gradeAssignment.setPointsPossible(gbItemPointsPossible); gradeAssignment.setUserUuid(studentUuid); + if (gradingService.isGradebookGroupEnabled(siteId)) { + try { + User user = userDirectoryService.getUser(gradeDef.getStudentUid()); + Site s = this.siteService.getSite(siteId); + Group g = s.getGroup(currentItem.getDescription().split(",")[1]); + + boolean isFromGroup = (g != null) && (g.getMember(user.getId()) != null); + gradeAssignment.setAllowedToGrade(isFromGroup); + } catch (Exception e) { + e.printStackTrace(); + } + } returnVal.put(studentUuid, gradeAssignment); } //now populate empty data for users who can be graded but don't have a grade yet: @@ -2909,7 +2970,20 @@ private Map getGradebookAssignment(){ if(!returnVal.containsKey(entry.getKey().toString())){ //this user needs to be added a gradeable: DecoratedGradebookAssignment gradeAssignment = new DecoratedGradebookAssignment(); - gradeAssignment.setAllowedToGrade(true); + if (gradingService.isGradebookGroupEnabled(siteId)) { + try { + User user = userDirectoryService.getUser(entry.getKey().toString()); + Site s = this.siteService.getSite(siteId); + Group g = s.getGroup(currentItem.getDescription().split(",")[1]); + + boolean isFromGroup = (g != null) && (g.getMember(user.getId()) != null); + gradeAssignment.setAllowedToGrade(isFromGroup); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + gradeAssignment.setAllowedToGrade(true); + } gradeAssignment.setName(selAssignName); gradeAssignment.setPointsPossible(gbItemPointsPossible); gradeAssignment.setUserUuid(entry.getKey().toString()); @@ -2969,28 +3043,42 @@ public String proccessActionSubmitGrades(){ try { - String selectedAssignName = ((SelectItem)assignments.get((Integer.valueOf(selectedAssign)).intValue())).getLabel(); + String selectedAssignName; + SelectItem currentItem = null; + if (gradingService.isGradebookGroupEnabled(toolManager.getCurrentPlacement().getContext())) { + currentItem = (SelectItem) assignments.stream() + .filter(n -> ((String)n.getValue()).equals(selectedAssign)) + .findFirst().get(); + selectedAssignName = currentItem.getLabel(); + } else { + selectedAssignName = ((SelectItem)assignments.get((Integer.valueOf(selectedAssign)).intValue())).getLabel(); + } String gradebookUuid = toolManager.getCurrentPlacement().getContext(); + String siteId = toolManager.getCurrentPlacement().getContext(); List gradeInfoToSave = new ArrayList(); for (DecoratedCompiledMessageStatistics gradeStatistic : gradeStatistics) { if(gradeStatistic.getGradebookAssignment() != null && gradeStatistic.getGradebookAssignment().isAllowedToGrade()){ //ignore empty grades - if(gradeStatistic.getGradebookAssignment().getScore() != null && - !"".equals(gradeStatistic.getGradebookAssignment().getScore())){ - - GradeDefinition gradeDef = new GradeDefinition(); - gradeDef.setStudentUid(gradeStatistic.getGradebookAssignment().getUserUuid()); - gradeDef.setGrade(gradeStatistic.getGradebookAssignment().getScore()); - gradeDef.setGradeComment(gradeStatistic.getGradebookAssignment().getComment()); - - gradeInfoToSave.add(gradeDef); + if(gradeStatistic.getGradebookAssignment().getScore() != null && + !"".equals(gradeStatistic.getGradebookAssignment().getScore())){ + + GradeDefinition gradeDef = new GradeDefinition(); + // + gradeDef.setStudentUid(gradeStatistic.getGradebookAssignment().getUserUuid()); + gradeDef.setGrade(gradeStatistic.getGradebookAssignment().getScore()); + gradeDef.setGradeComment(gradeStatistic.getGradebookAssignment().getComment()); + + gradeInfoToSave.add(gradeDef); } } } - gradingService.saveGradesAndComments(gradebookUuid, gradingService.getAssignmentByNameOrId(gradebookUuid, selectedAssignName).getId(), gradeInfoToSave); + if (gradingService.isGradebookGroupEnabled(toolManager.getCurrentPlacement().getContext())) { + gradebookUuid = currentItem.getDescription().split(",")[1]; + } + gradingService.saveGradesAndComments(gradebookUuid, gradebookUuid, gradingService.getAssignmentByNameOrId(gradebookUuid, gradebookUuid, selectedAssignName).getId(), gradeInfoToSave); setSuccessMessage(getResourceBundleString(GRADE_SUCCESSFUL)); } @@ -3041,10 +3129,9 @@ private boolean validateGradeInput(){ for (DecoratedCompiledMessageStatistics gradeStatistic : gradeStatistics) { if(gradeStatistic.getGradebookAssignment() != null && gradeStatistic.getGradebookAssignment().isAllowedToGrade()){ //ignore empty grades - if(gradeStatistic.getGradebookAssignment().getScore() != null && - !"".equals(gradeStatistic.getGradebookAssignment().getScore())){ - studentIdToGradeMap.put(gradeStatistic.getGradebookAssignment().getUserUuid(), gradeStatistic.getGradebookAssignment().getScore()); - + if(gradeStatistic.getGradebookAssignment().getScore() != null && + !"".equals(gradeStatistic.getGradebookAssignment().getScore())){ + studentIdToGradeMap.put(gradeStatistic.getGradebookAssignment().getUserUuid(), gradeStatistic.getGradebookAssignment().getScore()); } } } diff --git a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfMsgGrade.jsp b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfMsgGrade.jsp index b045b41d2895..214c3b08c9fe 100644 --- a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfMsgGrade.jsp +++ b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfMsgGrade.jsp @@ -22,6 +22,7 @@ + @@ -66,6 +67,7 @@ } boolean hasAssociatedRubric = forumTool.hasAssociatedRubric(); + boolean isGradebookGroupEnabled = forumTool.isGradebookGroupEnabled(); String entityId = forumTool.getRubricAssociationId(); if (userId == null) userId = forumTool.getUserId(); @@ -96,19 +98,21 @@ @@ -152,9 +156,19 @@ - + <% if (isGradebookGroupEnabled) { %> + + + + <%}%> - <% if (!hasAssociatedRubric) { %> + <% if (!hasAssociatedRubric && !isGradebookGroupEnabled) { %> @@ -219,7 +233,7 @@ <%}%> - + <% if(isDialogBox){ %> diff --git a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/statistics/dfStatisticsListByTopic.jsp b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/statistics/dfStatisticsListByTopic.jsp index 244335b633e9..4b7bec1787d1 100644 --- a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/statistics/dfStatisticsListByTopic.jsp +++ b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/statistics/dfStatisticsListByTopic.jsp @@ -126,7 +126,34 @@ - <%@ include file="/jsp/discussionForum/menu/forumsMenu.jsp" %> @@ -190,6 +219,15 @@ + + + + + + + + + @@ -213,13 +251,30 @@ - - - - - - + + + + + + + + + + + + + + + @@ -377,7 +432,7 @@
- + diff --git a/msgcntr/messageforums-component-impl/src/java/org/sakaiproject/component/app/messageforums/entity/TopicEntityProviderImpl.java b/msgcntr/messageforums-component-impl/src/java/org/sakaiproject/component/app/messageforums/entity/TopicEntityProviderImpl.java index 260df1d93698..1c2082fb9eed 100644 --- a/msgcntr/messageforums-component-impl/src/java/org/sakaiproject/component/app/messageforums/entity/TopicEntityProviderImpl.java +++ b/msgcntr/messageforums-component-impl/src/java/org/sakaiproject/component/app/messageforums/entity/TopicEntityProviderImpl.java @@ -65,6 +65,7 @@ import org.sakaiproject.entitybroker.entityprovider.search.Search; import org.sakaiproject.grading.api.Assignment; import org.sakaiproject.grading.api.GradingService; +import org.sakaiproject.grading.api.SortType; import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.user.api.UserDirectoryService; import org.sakaiproject.util.ResourceLoader; @@ -350,8 +351,8 @@ public List getEntities(EntityReference ref, Search search) { if (siteId != null) { try { GradingService gradingService = (GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); - final Gradebook gradebook = (Gradebook) gradingService.getGradebook(siteId); - List gbItems = gradingService.getAssignments(gradebook.getUid()); + final Gradebook gradebook = (Gradebook) gradingService.getGradebook(siteId, siteId); + List gbItems = gradingService.getAssignments(gradebook.getUid(), siteId, SortType.SORT_BY_NONE); if (gbItems != null) { for (Assignment gbItem : gbItems) { gbItemNameToId.put(gbItem.getName(), gbItem.getId()); diff --git a/plus/impl/src/main/java/org/sakaiproject/plus/impl/PlusServiceImpl.java b/plus/impl/src/main/java/org/sakaiproject/plus/impl/PlusServiceImpl.java index 7125296352b5..0aa04ccfb980 100644 --- a/plus/impl/src/main/java/org/sakaiproject/plus/impl/PlusServiceImpl.java +++ b/plus/impl/src/main/java/org/sakaiproject/plus/impl/PlusServiceImpl.java @@ -1486,7 +1486,7 @@ public void processGradeEvent(Event event) org.sakaiproject.grading.api.Assignment gradebookAssignment; try { - gradebookAssignment = gradingService.getAssignmentByNameOrId(siteId, itemId); + gradebookAssignment = gradingService.getAssignmentByNameOrId(siteId, siteId, itemId); } catch (AssessmentNotFoundException anfe) { log.warn("Can't retrieve gradebook assignment for gradebook {} and item {}, {}", siteId, itemId, anfe.getMessage()); return; diff --git a/plus/provider/src/main/java/org/sakaiproject/plus/ProviderServlet.java b/plus/provider/src/main/java/org/sakaiproject/plus/ProviderServlet.java index 6e6bd5b0ca08..89f75c75f7ad 100644 --- a/plus/provider/src/main/java/org/sakaiproject/plus/ProviderServlet.java +++ b/plus/provider/src/main/java/org/sakaiproject/plus/ProviderServlet.java @@ -1154,7 +1154,7 @@ protected Site findOrCreateSite(Map payload, Tenant tenant) throws LTIException // Lets prime the Gradebook - SAK-49568 try { - Gradebook gb = gradingService.getGradebook(siteId); + Gradebook gb = gradingService.getGradebook(siteId, siteId); log.info("Gradebook site={} gb={}", siteId, gb); } catch (Exception e) { throw new LTIException("launch.site.gradebook", "siteId=" + siteId, e); diff --git a/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/handlers/SiteHandler.java b/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/handlers/SiteHandler.java index b431c640d505..7618a5304353 100644 --- a/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/handlers/SiteHandler.java +++ b/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/handlers/SiteHandler.java @@ -1102,7 +1102,7 @@ public boolean allowBufferContent(HttpServletRequest req, Site site, ToolConfigu ToolManager toolManager = (ToolManager) ComponentManager.get(ToolManager.class.getName()); boolean allowedUser = toolManager.allowTool(site, siteTool); if ( ! allowedUser ) return false; - + if (!PortalSiteHelperImpl.checkGradebookVisibility(siteTool, site)) return false; return true; } diff --git a/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/site/PortalSiteHelperImpl.java b/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/site/PortalSiteHelperImpl.java index 8850dde44cc2..0d0c65a72fba 100644 --- a/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/site/PortalSiteHelperImpl.java +++ b/portal/portal-impl/impl/src/java/org/sakaiproject/portal/charon/site/PortalSiteHelperImpl.java @@ -81,6 +81,7 @@ import org.sakaiproject.portal.api.SiteView; import org.sakaiproject.portal.api.SiteView.View; import org.sakaiproject.portal.util.ToolUtils; +import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SitePage; import org.sakaiproject.site.api.SiteService; @@ -131,6 +132,8 @@ public class PortalSiteHelperImpl implements PortalSiteHelper private static final String OVERVIEW_TOOL_TITLE = "overview"; private static final String SAK_PROP_FORCE_OVERVIEW_TO_TOP = "portal.forceOverviewToTop"; private static final boolean SAK_PROP_FORCE_OVERVIEW_TO_TOP_DEFAULT = false; + private static final String GRADEBOOK_TOOL_ID = "sakai.gradebookng"; + private static final String GRADEBOOK_GROUP_PROPERTY = "gb-group"; private Portal portal; @@ -174,6 +177,14 @@ private static AuthzGroupService getAuthzGroupService() { return (AuthzGroupService) ComponentManager.get(AuthzGroupService.class.getName()); } + private static SecurityService getSecurityService() { + return (SecurityService) ComponentManager.get(SecurityService.class.getName()); + } + + private static UserDirectoryService getUserDirectoryService() { + return (UserDirectoryService) ComponentManager.get(UserDirectoryService.class.getName()); + } + public void setToolManager(ToolManager toolManager) { this.toolManager = toolManager; } @@ -1042,7 +1053,6 @@ else if ("always".equals(showHelpGlobal)) }else{ theMap.put("canManageOverviewHome", false); } - theMap.put("pageNavTools", l); theMap.put("pageNavTools", l); theMap.put("pageMaxIfSingle", serverConfigurationService.getBoolean( @@ -1394,7 +1404,8 @@ protected List getPermittedPagesInOrder(Site site) for (ToolConfiguration tc : p.getTools()) { boolean thisTool = allowTool(site, tc); boolean unHidden = siteUpdate || ! isHidden(tc); - if (thisTool && unHidden) allowPage = true; + boolean checkGradebookVisibility = checkGradebookVisibility(tc, site); + allowPage = thisTool && unHidden && checkGradebookVisibility; } if (allowPage) newPages.add(p); } @@ -1425,6 +1436,17 @@ protected List getPermittedPagesInOrder(Site site) return newPages; } + public static boolean checkGradebookVisibility(ToolConfiguration tc, Site site) { + //1 if tool is not gb or has no property or user is instructor + if (!GRADEBOOK_TOOL_ID.equals(tc.getToolId()) || tc.getPlacementConfig().getProperty(GRADEBOOK_GROUP_PROPERTY) == null || getSecurityService().unlock("section.role.instructor", site.getReference())) { + return true; + } + //2 check user groups match + String gbGroup = tc.getPlacementConfig().getProperty(GRADEBOOK_GROUP_PROPERTY); + List groupIds = site.getGroupsWithMember(getUserDirectoryService().getCurrentUser().getId()).stream().map(Group::getId).collect(Collectors.toList()); + return groupIds.contains(gbGroup); + } + /** * Make sure that we have a proper page selected in the site pageid is * generally the last page used in the site. pageId must be in the site and diff --git a/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java b/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java index 3c81f03cbb90..b4c0d2b1f288 100644 --- a/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java +++ b/rubrics/impl/src/main/java/org/sakaiproject/rubrics/impl/RubricsServiceImpl.java @@ -1471,7 +1471,8 @@ private Optional getAssociatedName(Evaluation evaluation, String siteId) if(association.getToolId().equals(AssignmentConstants.TOOL_ID)){ return Optional.of(assignmentService.getAssignment(association.getItemId()).getTitle()); } else if (association.getToolId().equals(RubricsConstants.RBCS_TOOL_GRADEBOOKNG)){ - return Optional.of(gradingService.getAssignment(siteId,Long.valueOf(association.getItemId())).getName()); + String gradebookUid = gradingService.getGradebookUidByAssignmentById(siteId, Long.valueOf(association.getItemId())); + return Optional.of(gradingService.getAssignment(gradebookUid, siteId, Long.valueOf(association.getItemId())).getName()); } else if (association.getToolId().equals(RubricsConstants.RBCS_TOOL_SAMIGO)){ String[] idParts = association.getItemId().split("\\."); return Optional.of(publishedAssessmentFacadeQueriesAPI.getPublishedAssessment(Long.valueOf(idParts[1])).getTitle()); diff --git a/samigo/samigo-api/src/java/org/sakaiproject/tool/assessment/data/ifc/assessment/AssessmentMetaDataIfc.java b/samigo/samigo-api/src/java/org/sakaiproject/tool/assessment/data/ifc/assessment/AssessmentMetaDataIfc.java index a026d1e73905..8416fb7ba860 100644 --- a/samigo/samigo-api/src/java/org/sakaiproject/tool/assessment/data/ifc/assessment/AssessmentMetaDataIfc.java +++ b/samigo/samigo-api/src/java/org/sakaiproject/tool/assessment/data/ifc/assessment/AssessmentMetaDataIfc.java @@ -38,6 +38,7 @@ public interface AssessmentMetaDataIfc public static final String CALENDAR_DUE_DATE_EVENT_ID = "CALENDAR_DUE_DATE_EVENT_ID"; public static final String TO_GRADEBOOK_ID = "TO_GRADEBOOK_ID"; + public static final String CATEGORY_LIST = "CATEGORY_LIST"; Long getId(); diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AssessmentSettingsMessages_es.properties b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AssessmentSettingsMessages_es.properties index 684ffcc81694..806eaf6e8bec 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AssessmentSettingsMessages_es.properties +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AssessmentSettingsMessages_es.properties @@ -277,6 +277,9 @@ date_error=Por favor, indique la fecha de liberaci\u00f3n de los comentarios. submissions_allowed_error=Por favor, introduzca el n\u00famero de env\u00edos permitidos. Este n\u00famero ha de ser mayor o igual a uno (1). validateURL=Validar la URL has_time_limit=y tiene un l\u00edmite de tiempo de +multi_gradebook.release_to.error=No se pueden crear tareas de sitio al tener calificaciones de grupo. +multi_gradebook.items.error=Los grupos seleccionados deben tener asociado un item del libro de calificaciones. +multi_gradebook.categories.error=Las categorías seleccionadas deben estar asociadas a su grupo correspondiente. # signs for author tool separator=| diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/AssessmentSettingsBean.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/AssessmentSettingsBean.java index 42c681204841..15bf8cb31c97 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/AssessmentSettingsBean.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/AssessmentSettingsBean.java @@ -54,6 +54,8 @@ import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.GradebookInformation; import org.sakaiproject.grading.api.GradingConstants; +import org.sakaiproject.grading.api.SortType; +import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.samigo.util.SamigoConstants; import org.sakaiproject.section.api.SectionAwareness; import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord; @@ -182,6 +184,7 @@ public class AssessmentSettingsBean extends SpringBeanAutowiringSupport implemen private SelectItem[] secureDeliveryModuleSelections; private String secureDeliveryModule; private String secureDeliveryModuleExitPassword; + @Getter @Setter private String currentSiteId; @Setter private SelectItem[] sebConfigModeSelections; @Setter private SelectItem[] booleanSelections; @Getter @Setter private String sebConfigMode; @@ -216,7 +219,10 @@ public class AssessmentSettingsBean extends SpringBeanAutowiringSupport implemen private boolean anonymousGrading; @Setter @Getter private String toDefaultGradebook; @Setter @Getter private String gradebookName; + @Setter private List existingGradebook = new ArrayList<>(); + @Setter @Getter private boolean gradebookEnabled; + private String scoringType; private String bgColor; private String bgImage; @@ -302,6 +308,8 @@ public class AssessmentSettingsBean extends SpringBeanAutowiringSupport implemen private ServerConfigurationService serverConfigurationService; private boolean backgroundColorEnabled = serverConfigurationService.getBoolean(SAMIGO_SETTINGS_BACKGROUNDCOLOR_ENABLED, false); + @Setter private boolean gradebookGroupEnabled = getGradebookGroupEnabled(); + public boolean isBackgroundColorEnabled() { return backgroundColorEnabled; } @@ -489,10 +497,19 @@ public void setAssessment(AssessmentFacade assessment) { if (evaluation.getScoringType()!=null) this.scoringType = evaluation.getScoringType().toString(); - String currentSiteId = AgentFacade.getCurrentSiteId(); + this.currentSiteId = AgentFacade.getCurrentSiteId(); + this.categoriesEnabled = populateCategoryEnabled(); this.categoriesSelectList = populateCategoriesSelectList(); - this.categorySelected = initializeCategorySelected(assessment.getData().getCategoryId()); + + this.gradebookEnabled = populateGradebookEnabled(); + + if (this.gradebookGroupEnabled) { + Object categoryListMetaData = assessment.getAssessmentMetaDataMap().get(AssessmentMetaDataIfc.CATEGORY_LIST); + this.categorySelected = categoryListMetaData != null ? (String) categoryListMetaData : "-1"; + } else { + this.categorySelected = initializeCategorySelected(assessment.getData().getCategoryId()); + } } @@ -539,57 +556,56 @@ else if ( ! secureDeliveryService.isSecureDeliveryModuleAvailable( secureDeliver * @param categoryId * @return */ - private String initializeCategorySelected(Long categoryId) { - - String catSelected = "-1"; - if (categoryId != null) { - String catId; - for (SelectItem catIdAndName : categoriesSelectList) { - catId = catIdAndName.getValue().toString(); - if (catId.equals(categoryId.toString())) { - catSelected = catId; - } - } - } - return catSelected; + private String initializeCategorySelected(Long categoryId) { + if (!this.gradebookGroupEnabled) { + String catSelected = "-1"; + if (categoryId != null) { + String catId; + for (SelectItem catIdAndName : categoriesSelectList) { + catId = catIdAndName.getValue().toString(); + if (catId.equals(categoryId.toString())) { + catSelected = catId; + } + } + } + return catSelected; + } else { + return categoryId != null ? categoryId.toString() : "-1"; } + } - public String getBgColorSelect() - { - return this.bgColorSelect; - } - public void setBgColorSelect(String bgColorSelect) - { - this.bgColorSelect=bgColorSelect; - } + public String getBgColorSelect() { + return this.bgColorSelect; + } - public String getBgImageSelect() - { - return this.bgImageSelect; - } - public void setBgImageSelect(String bgImageSelect) - { - this.bgImageSelect=bgImageSelect; - } + public void setBgColorSelect(String bgColorSelect) { + this.bgColorSelect=bgColorSelect; + } - //Huong adding for outcome error - public String getOutcomeSave() - { - return this.outcomeSave; - } - public void setOutcomeSave(String outcomeSave) - { - this.outcomeSave=outcomeSave; - } - - public String getOutcomePublish() - { - return this.outcomePublish; - } - public void setOutcomePublish(String outcomePublish) - { - this.outcomePublish=outcomePublish; - } + public String getBgImageSelect() { + return this.bgImageSelect; + } + + public void setBgImageSelect(String bgImageSelect) { + this.bgImageSelect=bgImageSelect; + } + + //Huong adding for outcome error + public String getOutcomeSave() { + return this.outcomeSave; + } + + public void setOutcomeSave(String outcomeSave) { + this.outcomeSave=outcomeSave; + } + + public String getOutcomePublish() { + return this.outcomePublish; + } + + public void setOutcomePublish(String outcomePublish) { + this.outcomePublish=outcomePublish; + } // properties from Assessment public Long getAssessmentId() { @@ -658,35 +674,29 @@ public void setAuthors(String authors) { } public String getBgColor() { - if((this.getBgColorSelect()!=null) && (this.getBgColorSelect().equals("1"))) - return this.bgColor; - else - return ""; - + if((this.getBgColorSelect()!=null) && (this.getBgColorSelect().equals("1"))) + return this.bgColor; + else + return ""; } public void setBgColor(String bgColor) { if((this.getBgColorSelect()!=null) && (this.getBgColorSelect().equals("1"))) - this.bgColor = bgColor; + this.bgColor = bgColor; else - this.bgColor=""; - + this.bgColor=""; } - public String getBgImage() { - if((this.getBgImageSelect()!=null) && (this.getBgImageSelect().equals("1"))) - return this.bgImage; - else return ""; - + if((this.getBgImageSelect()!=null) && (this.getBgImageSelect().equals("1"))) + return this.bgImage; + else return ""; } public void setBgImage(String bgImage) { - if((this.getBgImageSelect()!=null) && (this.getBgImageSelect().equals("1"))) - - this.bgImage = bgImage; - else this.bgImage=""; - + if((this.getBgImageSelect()!=null) && (this.getBgImageSelect().equals("1"))) + this.bgImage = bgImage; + else this.bgImage=""; } public boolean getHasQuestions() { @@ -732,14 +742,13 @@ public void setRetractDate(Date retractDate) { public String getReleaseTo() { this.releaseTo=""; - if (targetSelected != null){ - for( String user : targetSelected ) - { - if (!"".equals(releaseTo)) - releaseTo = releaseTo + ", " + user; - else - releaseTo = user; - } + if (targetSelected != null) { + for (String user : targetSelected) { + if (!"".equals(releaseTo)) + releaseTo = releaseTo + ", " + user; + else + releaseTo = user; + } } return this.releaseTo; } @@ -749,7 +758,7 @@ public void setReleaseTo(String releaseTo) { } public Integer getTimeLimit() { - return timedHours*3600 + return timedHours*3600 + timedMinutes*60 + timedSeconds; } @@ -821,11 +830,11 @@ public String getItemNumbering() { public void setItemNumbering(String itemNumbering) { this.itemNumbering = itemNumbering; } - + public String getDisplayScoreDuringAssessments(){ return displayScoreDuringAssessments; } - + public void setDisplayScoreDuringAssessments(String displayScoreDuringAssessments){ this.displayScoreDuringAssessments = displayScoreDuringAssessments; } @@ -933,7 +942,7 @@ public String getFeedbackComponentOption() { public void setFeedbackComponentOption(String feedbackComponentOption) { this.feedbackComponentOption = feedbackComponentOption; } - + public boolean getShowQuestionText() { return showQuestionText; } @@ -1030,17 +1039,20 @@ public void setScoringType(String scoringType) { this.scoringType = scoringType; } - public boolean isHonorPledge() { return honorPledge; } + public boolean isHonorPledge() { + return honorPledge; + } - public void setHonorPledge(boolean honorPledge) { this.honorPledge = honorPledge; } + public void setHonorPledge(boolean honorPledge) { + this.honorPledge = honorPledge; + } - public void setValue(String key, Object value){ + public void setValue(String key, Object value) { this.values.put(key, value); } // retrieve value in valueMap - public Boolean getValue(String key) - { + public Boolean getValue(String key) { Boolean returnValue = Boolean.FALSE; Object o = this.values.get(key); @@ -1048,33 +1060,33 @@ public Boolean getValue(String key) returnValue = Boolean.TRUE; return returnValue; } - + public String getSecureDeliveryModule() { - return secureDeliveryModule; + return secureDeliveryModule; } - + public void setSecureDeliveryModule(String secureDeliveryModule) { - this.secureDeliveryModule = secureDeliveryModule; + this.secureDeliveryModule = secureDeliveryModule; } public String getSecureDeliveryModuleExitPassword() { - return secureDeliveryModuleExitPassword; + return secureDeliveryModuleExitPassword; } public void setSecureDeliveryModuleExitPassword(String secureDeliveryModuleExitPassword) { - this.secureDeliveryModuleExitPassword = secureDeliveryModuleExitPassword; + this.secureDeliveryModuleExitPassword = secureDeliveryModuleExitPassword; } - + public void setSecureDeliveryModuleSelections(SelectItem[] secureDeliveryModuleSelections) { - this.secureDeliveryModuleSelections = secureDeliveryModuleSelections; + this.secureDeliveryModuleSelections = secureDeliveryModuleSelections; } - + public SelectItem[] getSecureDeliveryModuleSelections() { - return secureDeliveryModuleSelections; + return secureDeliveryModuleSelections; } public boolean isSecureDeliveryAvailable() { - return secureDeliveryAvailable; + return secureDeliveryAvailable; } public void setSecureDeliveryAvailable(boolean secureDeliveryAvailable) { @@ -1914,30 +1926,61 @@ public boolean getCategoriesEnabled() { return categoriesEnabled; } - /** - * Populate the categoriesSelectList property with a list of string names - * of the categories in the gradebook - */ - private List populateCategoriesSelectList() { + /** + * Populate the categoriesSelectList property with a list of string names + * of the categories in the gradebook + */ + private List populateCategoriesSelectList() { + if (!this.gradebookGroupEnabled) { List categoryDefinitions; List selectList = new ArrayList<>(); String gradebookUid = toolManager.getCurrentPlacement().getContext(); - categoryDefinitions = gradingService.getCategoryDefinitions(gradebookUid); + categoryDefinitions = gradingService.getCategoryDefinitions(gradebookUid, gradebookUid); selectList.add(new SelectItem("-1", assessmentSettingMessages.getString("gradebook_uncategorized"))); // -1 for a cat id means unassigned for (CategoryDefinition categoryDefinition: categoryDefinitions) { selectList.add(new SelectItem(categoryDefinition.getId().toString(), categoryDefinition.getName())); } - // Also set if categories are enabled based on category type - GradebookInformation gbInfo = gradingService.getGradebookInformation(gradebookUid); - if (gbInfo != null) { - this.categoriesEnabled = !Objects.equals(gbInfo.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY); - } else { - this.categoriesEnabled = false; - } + return selectList; + } else { + return new ArrayList<>(); + } + } + + private boolean populateCategoryEnabled() { + if (!this.gradebookGroupEnabled) { + String gradebookUid = toolManager.getCurrentPlacement().getContext(); + + GradebookInformation gbInfo = gradingService.getGradebookInformation(gradebookUid, gradebookUid); + if (gbInfo != null) { + return !Objects.equals(gbInfo.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY); + } else { + return false; + } + } else { + List gbList = gradingService.getGradebookGroupInstances(AgentFacade.getCurrentSiteId()); + + for (Gradebook gb : gbList){ + GradebookInformation test = gradingService.getGradebookInformation(gb.getUid(), AgentFacade.getCurrentSiteId()); + if (!Objects.equals(test.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY)) { + return true; + } + } + + return false; } + } + + public boolean populateGradebookEnabled() { + if (!this.gradebookGroupEnabled) { + List gradebookItemList = getExistingGradebook(); + return (gradebookItemList != null && !gradebookItemList.isEmpty()) ? true : false; + } else { + return true; + } + } public void setExtendedTimes(List extendedTimes) { this.extendedTimes = extendedTimes; @@ -2123,6 +2166,7 @@ public boolean isRenderInfoMessage() { // This method builds the gradebook assignment selector in the assessment settings. private List populateExistingGradebookItems() { + if (!this.gradebookGroupEnabled) { PublishedAssessmentService publishedAssessmentService = new PublishedAssessmentService(); List target = new ArrayList<>(); @@ -2172,7 +2216,7 @@ private List populateExistingGradebookItems() { } } - List gradebookAssignmentList = gradingService.getAssignments(AgentFacade.getCurrentSiteId()); + List gradebookAssignmentList = gradingService.getAssignments(AgentFacade.getCurrentSiteId(), AgentFacade.getCurrentSiteId(), SortType.SORT_BY_NONE); for (Assignment gradebookAssignment : gradebookAssignmentList) { boolean isExternallyMaintained = gradebookAssignment.getExternallyMaintained(); boolean isDefaultSamigoGradebookAssociation = isExternallyMaintained && StringUtils.equals("sakai.samigo", gradebookAssignment.getExternalAppName()); @@ -2199,6 +2243,9 @@ private List populateExistingGradebookItems() { } return target; + } else { + return new ArrayList(); + } } public List getExistingGradebook() { @@ -2207,5 +2254,10 @@ public List getExistingGradebook() { } return this.existingGradebook; } + + public boolean getGradebookGroupEnabled() { + this.gradebookGroupEnabled = gradingService.isGradebookGroupEnabled(AgentFacade.getCurrentSiteId()); + return this.gradebookGroupEnabled; + } } diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/PublishedAssessmentSettingsBean.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/PublishedAssessmentSettingsBean.java index 88922c93b17d..4a0c19fe308b 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/PublishedAssessmentSettingsBean.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/PublishedAssessmentSettingsBean.java @@ -57,6 +57,8 @@ import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.GradebookInformation; import org.sakaiproject.grading.api.GradingConstants; +import org.sakaiproject.grading.api.SortType; +import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.samigo.util.SamigoConstants; import org.sakaiproject.section.api.SectionAwareness; import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord; @@ -191,6 +193,8 @@ public class PublishedAssessmentSettingsBean extends SpringBeanAutowiringSupport @Getter @Setter private Boolean sebAllowAudioControl; @Getter @Setter private Boolean sebAllowSpellChecking; + @Getter @Setter private String currentSiteId; + // properties of PublishedFeedback private String feedbackDelivery; // immediate, on specific date , no feedback private String feedbackComponentOption; // 2 = select options, 1 = total scores only @@ -210,7 +214,11 @@ public class PublishedAssessmentSettingsBean extends SpringBeanAutowiringSupport private boolean anonymousGrading; @Getter @Setter private String toDefaultGradebook; @Getter @Setter private String gradebookName; + @Setter private List existingGradebook = new ArrayList<>(); + @Setter @Getter private boolean gradebookEnabled; + + private String scoringType; private String bgColor; private String bgImage; @@ -294,6 +302,8 @@ public class PublishedAssessmentSettingsBean extends SpringBeanAutowiringSupport private ServerConfigurationService serverConfigurationService; private boolean backgroundColorEnabled = serverConfigurationService.getBoolean(SAMIGO_SETTINGS_BACKGROUNDCOLOR_ENABLED, false); + @Setter private boolean gradebookGroupEnabled = getGradebookGroupEnabled(); + public boolean isBackgroundColorEnabled() { return backgroundColorEnabled; } @@ -471,10 +481,21 @@ public void setAssessment(PublishedAssessmentFacade assessment) { if (evaluation.getScoringType()!=null) this.scoringType = evaluation.getScoringType().toString(); - String currentSiteId = AgentFacade.getCurrentSiteId(); + this.currentSiteId = AgentFacade.getCurrentSiteId(); + this.categoriesEnabled = populateCategoryEnabled(); this.categoriesSelectList = populateCategoriesSelectList(); - this.categorySelected = getCategoryForAssessmentName(assessment.getTitle()); + + this.gradebookEnabled = populateGradebookEnabled(); + + if (this.gradebookGroupEnabled) { + Object categoryListMetaData = assessment.getAssessmentMetaDataMap().get(AssessmentMetaDataIfc.CATEGORY_LIST); + this.categorySelected = categoryListMetaData != null ? (String) categoryListMetaData : "-1"; + } else { + this.categorySelected = initializeCategorySelected(assessment.getData().getCategoryId()); + } + + //this.categorySelected = getCategoryForAssessmentName(assessment.getTitle()); } @@ -511,7 +532,8 @@ private String getCategoryForAssessmentName(String assessmentName) { Long categoryId = null; String gradebookUid = toolManager.getCurrentPlacement().getContext(); - List gbAssignments = gradingService.getAssignments(gradebookUid); + + List gbAssignments = gradingService.getAssignments(gradebookUid, gradebookUid, SortType.SORT_BY_NONE); for (Assignment assignment : gbAssignments) { if (StringUtils.equals(assessmentName, assignment.getName())) { categoryId = assignment.getCategoryId(); @@ -535,24 +557,55 @@ private String getCategoryForAssessmentName(String assessmentName) { * of the categories in the gradebook */ private List populateCategoriesSelectList() { - List categoryDefinitions; - List selectList = new ArrayList<>(); + if (!this.gradebookGroupEnabled) { + List categoryDefinitions; + List selectList = new ArrayList<>(); - String gradebookUid = toolManager.getCurrentPlacement().getContext(); - categoryDefinitions = gradingService.getCategoryDefinitions(gradebookUid); + String gradebookUid = toolManager.getCurrentPlacement().getContext(); + categoryDefinitions = gradingService.getCategoryDefinitions(gradebookUid, gradebookUid); + + selectList.add(new SelectItem("-1", assessmentSettingMessages.getString("gradebook_uncategorized"))); // -1 for a cat id means unassigned + for (CategoryDefinition categoryDefinition: categoryDefinitions) { + selectList.add(new SelectItem(categoryDefinition.getId().toString(), categoryDefinition.getName())); + } + + return selectList; + } else { + return new ArrayList<>(); + } +} + + private boolean populateCategoryEnabled() { + if (!this.gradebookGroupEnabled) { + String gradebookUid = toolManager.getCurrentPlacement().getContext(); - selectList.add(new SelectItem("-1", assessmentSettingMessages.getString("gradebook_uncategorized"))); // -1 for a cat id means unassigned - for (CategoryDefinition categoryDefinition: categoryDefinitions) { - selectList.add(new SelectItem(categoryDefinition.getId().toString(), categoryDefinition.getName())); + GradebookInformation gbInfo = gradingService.getGradebookInformation(gradebookUid, gradebookUid); + if (gbInfo != null) { + return !Objects.equals(gbInfo.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY); + } else { + return false; + } + } else { + List gbList = gradingService.getGradebookGroupInstances(AgentFacade.getCurrentSiteId()); + + for (Gradebook gb : gbList){ + GradebookInformation test = gradingService.getGradebookInformation(gb.getUid(), AgentFacade.getCurrentSiteId()); + if (!Objects.equals(test.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY)) { + return true; + } + } + + return false; } - // Also set if categories are enabled based on category type - GradebookInformation gbInfo = gradingService.getGradebookInformation(gradebookUid); - if (gbInfo != null) { - this.categoriesEnabled = !Objects.equals(gbInfo.getCategoryType(), GradingConstants.CATEGORY_TYPE_NO_CATEGORY); + } + + public boolean populateGradebookEnabled() { + if (!this.gradebookGroupEnabled) { + List gradebookItemList = getExistingGradebook(); + return (gradebookItemList != null && !gradebookItemList.isEmpty()) ? true : false; } else { - this.categoriesEnabled = false; + return true; } - return selectList; } public void setCategoriesEnabled(boolean categoriesEnabled) { @@ -1723,6 +1776,31 @@ public String getBlockDivs() { return blockDivs; } + /** + * Returns the saved category id if it's there. Otherwise returns + * "-1". This is needed to choose which select item is selected + * when the authorSettings page loads. + * @param categoryId + * @return + */ + private String initializeCategorySelected(Long categoryId) { + if (!this.gradebookGroupEnabled) { + String catSelected = "-1"; + if (categoryId != null) { + String catId; + for (SelectItem catIdAndName : categoriesSelectList) { + catId = catIdAndName.getValue().toString(); + if (catId.equals(categoryId.toString())) { + catSelected = catId; + } + } + } + return catSelected; + } else { + return categoryId != null ? categoryId.toString() : "-1"; + } + } + public String getBgColorSelect() { return this.bgColorSelect; @@ -1989,7 +2067,7 @@ public List getExistingGradebook() { // This method builds the gradebook assignment selector in the assessment settings. private List populateExistingGradebookItems() { - + if (!this.gradebookGroupEnabled) { PublishedAssessmentService publishedAssessmentService = new PublishedAssessmentService(); List target = new ArrayList<>(); try { @@ -2036,7 +2114,7 @@ private List populateExistingGradebookItems() { } } - List gradebookAssignmentList = gradingService.getAssignments(AgentFacade.getCurrentSiteId()); + List gradebookAssignmentList = gradingService.getAssignments(AgentFacade.getCurrentSiteId(), AgentFacade.getCurrentSiteId(), SortType.SORT_BY_NONE); for (Assignment gradebookAssignment : gradebookAssignmentList) { boolean isExternallyMaintained = gradebookAssignment.getExternallyMaintained(); boolean isDefaultSamigoGradebookAssociation = isExternallyMaintained && StringUtils.equals("sakai.samigo", gradebookAssignment.getExternalAppName()); @@ -2061,6 +2139,15 @@ private List populateExistingGradebookItems() { } return target; + + } else { + return new ArrayList(); + } + } + + public boolean getGradebookGroupEnabled() { + this.gradebookGroupEnabled = gradingService.isGradebookGroupEnabled(AgentFacade.getCurrentSiteId()); + return this.gradebookGroupEnabled; } } diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/RestoreAssessmentsBean.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/RestoreAssessmentsBean.java index e1c453d4c464..61c5f81f3a29 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/RestoreAssessmentsBean.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/RestoreAssessmentsBean.java @@ -32,9 +32,13 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; @@ -43,6 +47,7 @@ import lombok.NoArgsConstructor; import org.sakaiproject.component.cover.ComponentManager; +import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.samigo.api.SamigoAvailableNotificationService; import org.sakaiproject.samigo.api.SamigoReferenceReckoner; import org.sakaiproject.spring.SpringBeanLocator; @@ -147,12 +152,20 @@ private void updateGB(Long id) { evaluation = new PublishedEvaluationModel(); evaluation.setAssessmentBase(assessment.getData()); } + if (evaluation.getToGradeBook() != null && evaluation.getToGradeBook().equals(EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString())) { + PublishedAssessmentData data = (PublishedAssessmentData) assessment.getData(); String ref = SamigoReferenceReckoner.reckoner().site(AgentFacade.getCurrentSiteId()).subtype("p") .id(assessment.getPublishedAssessmentId().toString()).reckon().getReference(); + data.setReference(ref); - gbsHelper.addToGradebook(data, data.getCategoryId(), g); + + Map groupMap = assessment.getReleaseToGroups(); + List selectedGroups = groupMap.keySet().stream().collect(Collectors.toList()); + + gbsHelper.buildItemToGradebook(data, selectedGroups, g); + } } catch (Exception e1) { log.warn("RestoreAssessmentsBean - Exception thrown in updateGB():" + e1.getMessage()); diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/PublishAssessmentListener.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/PublishAssessmentListener.java index c06493158960..eaf5363f61cd 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/PublishAssessmentListener.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/PublishAssessmentListener.java @@ -252,7 +252,6 @@ private void publishOne(AuthorBean author, AssessmentFacade assessment, Assessme } private void publish(AssessmentFacade assessment, AssessmentSettingsBean assessmentSettings) { - PublishedAssessmentService publishedAssessmentService = new PublishedAssessmentService(); PublishedAssessmentFacade pub = null; boolean sendEmailNotification = false; diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettings.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettings.java index 35509f5542a7..6363a0a6dcc2 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettings.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettings.java @@ -22,6 +22,7 @@ package org.sakaiproject.tool.assessment.ui.listener.author; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -34,7 +35,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; - +import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.event.cover.EventTrackingService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.samigo.util.SamigoConstants; @@ -91,7 +92,6 @@ public AssessmentFacade save(AssessmentSettingsBean assessmentSettings, boolean assessment.setTitle(TextFormat.convertPlaintextToFormattedTextNoHighUnicode(assessmentSettings.getTitle())); assessment.setDescription(assessmentSettings.getDescription()); assessment.updateAssessmentMetaData(AssessmentMetaDataIfc.AUTHORS, TextFormat.convertPlaintextToFormattedTextNoHighUnicode(assessmentSettings.getAuthors())); - // #2 - set AssessmentAccessControl AssessmentAccessControl control = (AssessmentAccessControl)assessment.getAssessmentAccessControl(); if (control == null){ @@ -294,16 +294,11 @@ public AssessmentFacade save(AssessmentSettingsBean assessmentSettings, boolean evaluation.setToGradeBook(Integer.toString(EvaluationModelIfc.NOT_TO_GRADEBOOK)); } } - + if (assessmentSettings.getScoringType()!=null) evaluation.setScoringType(new Integer(assessmentSettings.getScoringType())); - assessment.setEvaluationModel(evaluation); - // Add category unless unassigned (-1) is selected or defaulted. CategoryId comes - // from the web page as a string representation of a the long cat id. - if (!StringUtils.equals(assessmentSettings.getCategorySelected(), "-1")) { - assessment.setCategoryId(Long.parseLong((assessmentSettings.getCategorySelected()))); - } + assessment.setEvaluationModel(evaluation); // h. update ValueMap: it contains value for teh checkboxes in // authorSettings.jsp for: hasAvailableDate, hasDueDate, @@ -313,10 +308,33 @@ public AssessmentFacade save(AssessmentSettingsBean assessmentSettings, boolean Map h = assessmentSettings.getValueMap(); updateMetaWithValueMap(assessment, h); + org.sakaiproject.grading.api.GradingService gradingService = + (org.sakaiproject.grading.api.GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); + + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(AgentFacade.getCurrentSiteId()); + + // TODO: https://github.com/sakaiproject/sakai/commit/e9635ea4ec2cf05c07662d7c8e7bd29a1946560d#diff-c3555f437c75f6d93d735ae9[…]e2faf2004ed0b2a13dd0f5e6417089 if (EvaluationModelIfc.TO_SELECTED_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { assessment.updateAssessmentToGradebookNameMetaData(assessmentSettings.getGradebookName()); - } else { - assessment.updateAssessmentToGradebookNameMetaData(""); + + if (isGradebookGroupEnabled) { + assessment.updateAssessmentMetaData(AssessmentMetaDataIfc.CATEGORY_LIST, "-1"); + } else { + assessment.setCategoryId(1L); + } + } else if (EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { + if (isGradebookGroupEnabled) { + assessment.updateAssessmentMetaData(AssessmentMetaDataIfc.CATEGORY_LIST, assessmentSettings.getCategorySelected()); + } else { + // Add category unless unassigned (-1) is selected or defaulted. CategoryId comes + // from the web page as a string representation of a the long cat id. + if (!StringUtils.equals(assessmentSettings.getCategorySelected(), "-1") && !StringUtils.isEmpty(assessmentSettings.getCategorySelected())) { + List categoryList = Arrays.asList(assessmentSettings.getCategorySelected().split(",")); + assessment.setCategoryId(Long.parseLong((categoryList.get(0)))); + } + } + + assessment.updateAssessmentToGradebookNameMetaData(""); } ExtendedTimeFacade extendedTimeFacade = PersistenceService.getInstance().getExtendedTimeFacade(); diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettingsListener.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettingsListener.java index cba761f9706e..6a384d9479d8 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettingsListener.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SaveAssessmentSettingsListener.java @@ -22,6 +22,7 @@ package org.sakaiproject.tool.assessment.ui.listener.author; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; @@ -35,11 +36,13 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.sakaiproject.component.cover.ComponentManager; +import org.sakaiproject.grading.api.GradingService; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.assessment.api.SamigoApiFactory; import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentAccessControl; import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentAccessControlIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.EvaluationModelIfc; +import org.sakaiproject.tool.assessment.facade.AgentFacade; import org.sakaiproject.tool.assessment.facade.AssessmentFacade; import org.sakaiproject.tool.assessment.services.assessment.AssessmentService; import org.sakaiproject.tool.assessment.shared.api.assessment.SecureDeliveryServiceAPI; @@ -63,6 +66,8 @@ public class SaveAssessmentSettingsListener implements ActionListener { + + private GradingService gradingService; //private static final GradebookServiceHelper gbsHelper = IntegrationContextFactory.getInstance().getGradebookServiceHelper(); //private static final boolean integrated = IntegrationContextFactory.getInstance().isIntegrated(); @@ -76,8 +81,9 @@ public void processAction(ActionEvent ae) throws AbortProcessingException AssessmentSettingsBean assessmentSettings = (AssessmentSettingsBean) ContextUtil. lookupBean("assessmentSettings"); + boolean error=false; - String assessmentId=String.valueOf(assessmentSettings.getAssessmentId()); + String assessmentId=String.valueOf(assessmentSettings.getAssessmentId()); AssessmentService assessmentService = new AssessmentService(); SaveAssessmentSettings s = new SaveAssessmentSettings(); String assessmentName = TextFormat.convertPlaintextToFormattedTextNoHighUnicode(assessmentSettings.getTitle()); @@ -145,8 +151,20 @@ public void processAction(ActionEvent ae) throws AbortProcessingException } } + GradingService gradingService = (GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); + + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(AgentFacade.getCurrentSiteId()); + boolean isReleaseToSelectedGroups = assessmentSettings.getReleaseTo().equals(AssessmentAccessControl.RELEASE_TO_SELECTED_GROUPS); + + if (isGradebookGroupEnabled && !isReleaseToSelectedGroups) { + error = true; + + String categoriesInGroups = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","multi_gradebook.release_to.error"); + context.addMessage(null,new FacesMessage(categoriesInGroups)); + } + if (assessmentSettings.getReleaseTo().equals(AssessmentAccessControl.RELEASE_TO_SELECTED_GROUPS)) { - String[] groupsAuthorized = assessmentSettings.getGroupsAuthorizedToSave(); //getGroupsAuthorized(); + String[] groupsAuthorized = assessmentSettings.getGroupsAuthorizedToSave(); //getGroupsAuthorized(); if (groupsAuthorized == null || groupsAuthorized.length == 0) { String releaseGroupError = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.GeneralMessages","choose_one_group"); context.addMessage(null,new FacesMessage(releaseGroupError)); @@ -154,6 +172,44 @@ public void processAction(ActionEvent ae) throws AbortProcessingException assessmentSettings.setNoGroupSelectedError(true); } else { + List groupList = Arrays.asList(groupsAuthorized); + + String siteId = assessmentSettings.getCurrentSiteId(); + String defaultToGradebook = assessmentSettings.getToDefaultGradebook(); + + if (defaultToGradebook != null && isGradebookGroupEnabled) { + if (defaultToGradebook.equals(EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString())) { + String categorySelected = assessmentSettings.getCategorySelected(); + + if (categorySelected != null && !categorySelected.isBlank() && !categorySelected.equals("-1")) { + List selectedCategories = Arrays.asList(categorySelected.split(",")); + + boolean areCategoriesInGroups = + gradingService.checkMultiSelectorList(siteId, groupList != null ? groupList : new ArrayList<>(), selectedCategories, true); + + if (!areCategoriesInGroups) { + error = true; + String categoriesInGroups = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","multi_gradebook.categories.error"); + + context.addMessage(null,new FacesMessage(categoriesInGroups)); + } + } + } else if (defaultToGradebook.equals(EvaluationModelIfc.TO_SELECTED_GRADEBOOK.toString())) { + String gradebookName = assessmentSettings.getGradebookName(); + List gradebookList = Arrays.asList(gradebookName.split(",")); + + boolean areItemsInGroups = + gradingService.checkMultiSelectorList(siteId, groupList != null ? groupList : new ArrayList<>(), gradebookList, false); + + if (!areItemsInGroups) { + error = true; + String itemsInGroups = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","multi_gradebook.items.error"); + + context.addMessage(null,new FacesMessage(itemsInGroups)); + } + } + } + assessmentSettings.setNoGroupSelectedError(false); } } diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SavePublishedSettingsListener.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SavePublishedSettingsListener.java index 4e6fb2c44919..afbfbb858393 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SavePublishedSettingsListener.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/author/SavePublishedSettingsListener.java @@ -21,13 +21,18 @@ package org.sakaiproject.tool.assessment.ui.listener.author; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.ListIterator; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import java.security.KeyStore.Entry; import java.time.Instant; import javax.faces.application.FacesMessage; @@ -38,6 +43,8 @@ import javax.faces.model.SelectItem; import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.text.StringEscapeUtils; @@ -45,6 +52,10 @@ import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.event.api.EventTrackingService; +import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.CategoryDefinition; +import org.sakaiproject.grading.api.model.Gradebook; +import org.sakaiproject.grading.api.model.GradebookAssignment; import org.sakaiproject.samigo.api.SamigoAvailableNotificationService; import org.sakaiproject.samigo.api.SamigoReferenceReckoner; import org.sakaiproject.samigo.util.SamigoConstants; @@ -58,6 +69,7 @@ import org.sakaiproject.tool.assessment.business.entity.SebConfig.ConfigMode; import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentAccessControl; import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentFeedback; +import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentMetaData; import org.sakaiproject.tool.assessment.data.dao.assessment.EvaluationModel; import org.sakaiproject.tool.assessment.data.dao.assessment.ExtendedTime; import org.sakaiproject.tool.assessment.data.dao.assessment.PublishedAccessControl; @@ -144,6 +156,7 @@ public void processAction(ActionEvent ae) throws AbortProcessingException List existingGradebook = assessmentSettings.getExistingGradebook(); ToolSession currentToolSession = SessionManager.getCurrentToolSession(); + for (SelectItem item : existingGradebook) { if (!item.getLabel().contains(assessmentSettings.getTitle()) && item.getLabel().split("\\(").length > 1 && @@ -168,16 +181,19 @@ public void processAction(ActionEvent ae) throws AbortProcessingException boolean isTitleChanged = isTitleChanged(assessmentSettings, assessment); boolean isScoringTypeChanged = isScoringTypeChanged(assessmentSettings, assessment); + + PublishedAssessmentFacade originalAssessment = (PublishedAssessmentFacade) SerializationUtils.clone(assessment); + SaveAssessmentSettings saveAssessmentSettings = new SaveAssessmentSettings(); setPublishedSettings(assessmentSettings, assessment, retractNow, saveAssessmentSettings); - + boolean gbError = checkScore(assessmentSettings, assessment, context); if (gbError){ assessmentSettings.setOutcome("editPublishedAssessmentSettings"); return; } - boolean gbUpdated = updateGB(assessmentSettings, assessment, isTitleChanged, isScoringTypeChanged, context); + boolean gbUpdated = updateGB(assessmentSettings, assessment, originalAssessment, isTitleChanged, isScoringTypeChanged, context); if (!gbUpdated){ assessmentSettings.setOutcome("editPublishedAssessmentSettings"); return; @@ -190,7 +206,7 @@ public void processAction(ActionEvent ae) throws AbortProcessingException assessment.setLastModifiedBy(AgentFacade.getAgentString()); assessment.setLastModifiedDate(new Date()); assessmentService.saveAssessment(assessment); - + // jj. save assessment first, then deal with ip assessmentService.saveAssessment(assessment); assessmentService.deleteAllSecuredIP(assessment); @@ -592,6 +608,59 @@ public boolean checkPublishedSettings(PublishedAssessmentService assessmentServi } } + org.sakaiproject.grading.api.GradingService gradingService = + (org.sakaiproject.grading.api.GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); + + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(AgentFacade.getCurrentSiteId()); + boolean isReleaseToSelectedGroups = assessmentSettings.getReleaseTo().equals(AssessmentAccessControl.RELEASE_TO_SELECTED_GROUPS); + + if (isGradebookGroupEnabled && !isReleaseToSelectedGroups) { + error = true; + + String categoriesInGroups = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","multi_gradebook.release_to.error"); + context.addMessage(null,new FacesMessage(categoriesInGroups)); + } + + String[] groupsAuthorized = assessmentSettings.getGroupsAuthorized(); + + List groupList = Arrays.asList(groupsAuthorized); + + String siteId = assessmentSettings.getCurrentSiteId(); + String defaultToGradebook = assessmentSettings.getToDefaultGradebook(); + + if (defaultToGradebook != null && isGradebookGroupEnabled) { + if (defaultToGradebook.equals(EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString())) { + String categorySelected = assessmentSettings.getCategorySelected(); + + if (categorySelected != null && !categorySelected.isBlank() && !categorySelected.equals("-1")) { + List selectedCategories = Arrays.asList(categorySelected.split(",")); + + boolean areCategoriesInGroups = + gradingService.checkMultiSelectorList(siteId, groupList != null ? groupList : new ArrayList<>(), selectedCategories, true); + + if (!areCategoriesInGroups) { + error = true; + String categoriesInGroups = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","multi_gradebook.categories.error"); + + context.addMessage(null,new FacesMessage(categoriesInGroups)); + } + } + } else if (defaultToGradebook.equals(EvaluationModelIfc.TO_SELECTED_GRADEBOOK.toString())) { + String gradebookName = assessmentSettings.getGradebookName(); + List gradebookList = Arrays.asList(gradebookName.split(",")); + + boolean areItemsInGroups = + gradingService.checkMultiSelectorList(siteId, groupList != null ? groupList : new ArrayList<>(), gradebookList, false); + + if (!areItemsInGroups) { + error = true; + String itemsInGroups = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","multi_gradebook.items.error"); + + context.addMessage(null,new FacesMessage(itemsInGroups)); + } + } + } + return error; } @@ -618,7 +687,7 @@ private boolean isScoringTypeChanged(PublishedAssessmentSettingsBean assessmentS } return true; } - + private void setPublishedSettings(PublishedAssessmentSettingsBean assessmentSettings, PublishedAssessmentFacade assessment, boolean retractNow, SaveAssessmentSettings saveAssessmentSettings) { // Title is set in isTitleChanged() assessment.setDescription(assessmentSettings.getDescription()); @@ -827,12 +896,6 @@ else if ("".equals(assessmentSettings.getRetractDateString())) { } assessment.setEvaluationModel(evaluation); - // Add category unless unassigned (-1) is selected or defaulted. CategoryId comes - // from the web page as a string representation of a the long cat id. - if (!StringUtils.equals(assessmentSettings.getCategorySelected(), "-1")) { - assessment.setCategoryId(Long.parseLong((assessmentSettings.getCategorySelected()))); - } - // update ValueMap: it contains value for thh checkboxes in // publishedSettings.jsp for: hasAvailableDate, hasDueDate, // hasRetractDate, hasAnonymous, hasAuthenticatedUser, hasIpAddress, @@ -841,10 +904,38 @@ else if ("".equals(assessmentSettings.getRetractDateString())) { HashMap h = assessmentSettings.getValueMap(); saveAssessmentSettings.updateMetaWithValueMap(assessment, h); + org.sakaiproject.grading.api.GradingService gradingService = + (org.sakaiproject.grading.api.GradingService) ComponentManager.get("org.sakaiproject.grading.api.GradingService"); + + boolean isGradebookGroupEnabled = gradingService.isGradebookGroupEnabled(AgentFacade.getCurrentSiteId()); + + // Add category unless unassigned (-1) is selected or defaulted. CategoryId comes + // from the web page as a string representation of a the long cat id. if (EvaluationModelIfc.TO_SELECTED_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { assessment.updateAssessmentToGradebookNameMetaData(assessmentSettings.getGradebookName()); - } else { - assessment.updateAssessmentToGradebookNameMetaData(""); + + if (isGradebookGroupEnabled) { + assessment.updateAssessmentMetaData(AssessmentMetaDataIfc.CATEGORY_LIST, "-1"); + } else { + assessment.setCategoryId(null); + } + } else if (EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { + if (isGradebookGroupEnabled) { + assessment.updateAssessmentMetaData(AssessmentMetaDataIfc.CATEGORY_LIST, assessmentSettings.getCategorySelected()); + } else { + // Add category unless unassigned (-1) is selected or defaulted. CategoryId comes + // from the web page as a string representation of a the long cat id. + if (!StringUtils.equals(assessmentSettings.getCategorySelected(), "-1") && !StringUtils.isEmpty(assessmentSettings.getCategorySelected())) { + List categoryList = Arrays.asList(assessmentSettings.getCategorySelected().split(",")); + assessment.getData().setCategoryId(Long.parseLong((categoryList.get(0)))); + assessment.setCategoryId(Long.parseLong((categoryList.get(0)))); + } else { + assessment.getData().setCategoryId(null); + assessment.setCategoryId(null); + } + } + + assessment.updateAssessmentToGradebookNameMetaData(""); } ExtendedTimeFacade extendedTimeFacade = PersistenceService.getInstance().getExtendedTimeFacade(); @@ -877,16 +968,17 @@ public boolean checkScore(PublishedAssessmentSettingsBean assessmentSettings, Pu return gbError; } - public boolean updateGB(PublishedAssessmentSettingsBean assessmentSettings, PublishedAssessmentFacade assessment, boolean isTitleChanged, boolean isScoringTypeChanged, FacesContext context) { + public boolean updateGB(PublishedAssessmentSettingsBean assessmentSettings, PublishedAssessmentFacade assessment, PublishedAssessmentFacade originalAssessment, + boolean isTitleChanged, boolean isScoringTypeChanged, FacesContext context) { //#3 - add or remove external assessment to gradebook // a. if Gradebook does not exists, do nothing, 'cos setting should have been hidden // b. if Gradebook exists, just call addExternal and removeExternal and swallow any exception. The // exception are indication that the assessment is already in the Gradebook or there is nothing // to remove. - org.sakaiproject.grading.api.GradingService gradingService = null; + org.sakaiproject.grading.api.GradingService gradingServiceApi = null; if (integrated) { - gradingService = (org.sakaiproject.grading.api.GradingService) SpringBeanLocator.getInstance().getBean("org.sakaiproject.grading.api.GradingService"); + gradingServiceApi = (org.sakaiproject.grading.api.GradingService) SpringBeanLocator.getInstance().getBean("org.sakaiproject.grading.api.GradingService"); } PublishedEvaluationModel evaluation = (PublishedEvaluationModel) assessment.getEvaluationModel(); @@ -896,148 +988,158 @@ public boolean updateGB(PublishedAssessmentSettingsBean assessmentSettings, Publ evaluation.setAssessmentBase(assessment.getData()); } - String assessmentName; - boolean gbItemExists = false; - - try { - assessmentName = TextFormat.convertPlaintextToFormattedTextNoHighUnicode(assessmentSettings.getTitle().trim()); - gbItemExists = gbsHelper.isAssignmentDefined(assessmentName, gradingService); - if (EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString().equals(assessmentSettings.getToDefaultGradebook()) && gbItemExists && isTitleChanged){ - String gbConflict_error = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages", "gbConflict_error"); - context.addMessage(null, new FacesMessage(gbConflict_error)); - return false; - } - } catch(Exception e) { - log.warn("external assessment in GB has the same title:"+e.getMessage()); - } - evaluation.setToGradeBook(assessmentSettings.getToDefaultGradebook()); // If the assessment is retracted for edit, we don't sync with gradebook (only until it is republished) if (AssessmentBaseIfc.RETRACT_FOR_EDIT_STATUS.equals(assessment.getStatus())) { return true; } - Integer scoringType = evaluation.getScoringType(); - if (evaluation.getToGradeBook()!=null && - !evaluation.getToGradeBook().equals(EvaluationModelIfc.NOT_TO_GRADEBOOK.toString())) { - // Can't trust the old assessment category id because the instructor could have changed inside Gradebook directly! - Long externalCategoryId = gbsHelper.getExternalAssessmentCategoryId(GradebookFacade.getGradebookUId(), assessment.getPublishedAssessmentId().toString(), gradingService); - long currentCategoryId = externalCategoryId != null ? externalCategoryId : -1; - long newCategoryId = NumberUtils.toLong(assessmentSettings.getCategorySelected(), -1); - boolean isCategoryChanged = (currentCategoryId > 0 || newCategoryId > 0) && currentCategoryId != newCategoryId; + String toGradebook = evaluation.getToGradeBook(); + boolean isGradebookGroupEnabled = gradingServiceApi.isGradebookGroupEnabled(AgentFacade.getCurrentSiteId()); + if (toGradebook != null && + !toGradebook.equals(EvaluationModelIfc.NOT_TO_GRADEBOOK.toString())) { boolean existingItemHasBeenRemoved = false; - // Because GB use title instead of id, we remove and re-add to GB if title changes. - try { - log.debug("before gbsHelper.removeGradebook(), isTitleChanged={}, isScoringTypeChanged={}, isCategoryChanged={}", isTitleChanged, isScoringTypeChanged, newCategoryId); - gbsHelper.removeExternalAssessment(GradebookFacade.getGradebookUId(), assessment.getPublishedAssessmentId().toString(), gradingService); - gbItemExists = false; - // This variable is only true then the assessment has been removed! - existingItemHasBeenRemoved = true; - } catch (Exception e1) { - // Should be the external assessment doesn't exist in GB. So we quiet swallow the exception. Please check the log for the actual error. - log.info("Exception thrown in updateGB():" + e1.getMessage()); - } + if (EvaluationModelIfc.TO_SELECTED_GRADEBOOK.toString().equals(toGradebook)) { + /* SINCE THIS IS CASE 3, THE ITEMS ASSOCIATED WITH THIS EXAM ARE GENERATED IN THE GRADEBOOK + SO WE MUST ALWAYS DELETE ANY ITEM THAT IS ASSOCIATED WITH THE PUBLISHED EXAM ID + THIS IS BECAUSE ITEMS CAN BE CREATED IN EXAMS, BUT ONLY IF WE ARE IN CASE 2, SO + THESE ITEMS FROM CASE 2 WILL BE DELETED */ + try { + gbsHelper.removeExternalAssessment(GradebookFacade.getGradebookUId(), assessment.getPublishedAssessmentId().toString(), gradingServiceApi); + // This variable is only true then the assessment has been removed! + existingItemHasBeenRemoved = true; + } catch (Exception e1) { + // Should be the external assessment doesn't exist in GB. So we quiet swallow the exception. Please check the log for the actual error. + log.info("Exception thrown in updateGB():" + e1.getMessage()); + } - // The Current item has been removed successfully means we switched from option 2 to option 3, losing the option 2 item from the gradebook. - if (existingItemHasBeenRemoved && EvaluationModelIfc.TO_SELECTED_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { - // The previous gradebook assigned to this assessment - Long gradebookItemId = Long.valueOf(assessment.getAssessmentToGradebookNameMetaData()); - if (gradebookItemId.equals(assessment.getPublishedAssessmentId())) { - String gbNotExistsError = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages", "gbNotExistsError"); - context.addMessage(null, new FacesMessage(gbNotExistsError)); - return false; - } - } + if (existingItemHasBeenRemoved) { + String gradebookItemString = assessment.getAssessmentToGradebookNameMetaData(); + List gradebookItemList = new ArrayList<>(); - if (gbItemExists && - !(isTitleChanged || isScoringTypeChanged || isCategoryChanged) && - EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { - - try { - gbsHelper.updateGradebook(assessment, gradingService); - } catch (Exception e) { - String gbConflict_error = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","gbConflict_error"); - context.addMessage(null, new FacesMessage(gbConflict_error)); - evaluation.setToGradeBook("0"); - log.warn("Exception thrown in updateGB():" + e.getMessage()); - return false; - } - } else { + if (gradebookItemString != null && !gradebookItemString.isBlank()) { + gradebookItemList = Arrays.asList(gradebookItemString.split(",")); + } else { + String gbNotExistsError = "No se pueden crear exámenes sin ningún item asociado"; + context.addMessage(null, new FacesMessage(gbNotExistsError)); + return false; + } - try { - log.debug("before gbsHelper.addToGradebook()"); + if (gradebookItemList.contains(assessment.getPublishedAssessmentId().toString())) { + String gbNotExistsError = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages", "gbNotExistsError"); + context.addMessage(null, new FacesMessage(gbNotExistsError)); + return false; + } + } - Long newCategory = null; - if (!StringUtils.equals(assessmentSettings.getCategorySelected(), "-1")) { - newCategory = Long.valueOf(assessmentSettings.getCategorySelected()); - } + gbsHelper.manageScoresToNewGradebook(new GradingService(), gradingServiceApi, assessment, evaluation); + } else if (EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { + Object categorySelected = null; + Object oldCategorySelected = null; - if (EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { - PublishedAssessmentData data = (PublishedAssessmentData) assessment.getData(); - Site site = SiteService.getSite(ToolManager.getCurrentPlacement().getContext()); - String ref = SamigoReferenceReckoner.reckoner().site(site.getId()).subtype("p").id(assessment.getPublishedAssessmentId().toString()).reckon().getReference(); - data.setReference(ref); - gbsHelper.addToGradebook(data, newCategory, gradingService); - } + if (isGradebookGroupEnabled) { + categorySelected = assessment.getAssessmentMetaDataMap().get(AssessmentMetaDataIfc.CATEGORY_LIST); + oldCategorySelected = originalAssessment.getAssessmentMetaDataMap().get(AssessmentMetaDataIfc.CATEGORY_LIST); + } else { + categorySelected = assessment.getCategoryId(); + oldCategorySelected = originalAssessment.getData() != null ? originalAssessment.getData().getCategoryId() : ""; + } - // any score to copy over? get all the assessmentGradingData and copy over - GradingService samigoGradingService = new GradingService(); + String categoryString = categorySelected != null ? categorySelected.toString() : "-1"; + categoryString = !categoryString.equals("-1") ? categoryString : ""; - // need to decide what to tell gradebook - List list; + String oldCategoryString = oldCategorySelected != null ? oldCategorySelected.toString() : "-1"; + oldCategoryString = !oldCategoryString.equals("-1") ? oldCategoryString : ""; - if (EvaluationModelIfc.HIGHEST_SCORE.equals(scoringType)) { - list = samigoGradingService.getHighestSubmittedOrGradedAssessmentGradingList(assessment.getPublishedAssessmentId()); - } - else { - list = samigoGradingService.getLastSubmittedOrGradedAssessmentGradingList(assessment.getPublishedAssessmentId()); - } + Map oldGradebookCategoryMap = new HashMap<>(); + Map newGradebookCategoryMap = new HashMap<>(); - log.debug("list size = {}", list.size()); - for (int i=0; i < list.size(); i++) { - try { - AssessmentGradingData ag = (AssessmentGradingData)list.get(i); - log.debug("ag.scores " + ag.getTotalAutoScore()); - // Send the average score if average was selected for multiple submissions - if (scoringType.equals(EvaluationModelIfc.AVERAGE_SCORE)) { - // status = 5: there is no submission but grader update something in the score page - if(ag.getStatus() ==5) { - ag.setFinalScore(ag.getFinalScore()); - } else { - Double averageScore = PersistenceService.getInstance().getAssessmentGradingFacadeQueries(). - getAverageSubmittedAssessmentGrading(assessment.getPublishedAssessmentId(), ag.getAgentId()); - ag.setFinalScore(averageScore); - } - } - - if (EvaluationModelIfc.TO_DEFAULT_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { - gbsHelper.updateExternalAssessmentScore(ag, gradingService); - gbsHelper.updateExternalAssessmentComment(ag.getPublishedAssessmentId(), ag.getAgentId() , ag.getComments(), gradingService); - } - - - String gradebookItemIdString = assessment.getAssessmentToGradebookNameMetaData(); - if (EvaluationModelIfc.TO_SELECTED_GRADEBOOK.toString().equals(evaluation.getToGradeBook())) { - Long gradebookItemId = Long.valueOf(gradebookItemIdString); - gbsHelper.updateExternalAssessmentScore(ag, gradingService, gradebookItemId); - } - - } - catch (Exception e) { - log.warn("Exception occues in " + i + "th record. Message:" + e.getMessage()); - } - } - } - catch(Exception e){ - log.warn("oh well, must have been added already:"+e.getMessage()); - } - } - } else { //remove + Map updateGradebookCategoryMap = new HashMap<>(); + Map createGradebookCategoryMap = new HashMap<>(); + + if (isGradebookGroupEnabled) { + /* FIRST, WE WILL NEED TO CREATE TWO MAPS, ONE FOR THE OLD ONES AND ANOTHER FOR THE NEW ONES, + WHICH CONTAIN THE CATEGORY IDS AND THE GRADEBOOK UID. THIS IS BECAUSE WE WILL + LATER NEED TO CHECK IF THE CATEGORY IN EACH GRADEBOOK ASSOCIATED WITH THE EXAM HAS BEEN CHANGED */ + oldGradebookCategoryMap = gradingServiceApi.buildCategoryGradebookMap(Arrays.asList(assessmentSettings.getGroupsAuthorized()), oldCategoryString, AgentFacade.getCurrentSiteId()); + newGradebookCategoryMap = gradingServiceApi.buildCategoryGradebookMap(Arrays.asList(assessmentSettings.getGroupsAuthorized()), categoryString, AgentFacade.getCurrentSiteId()); + + for (Map.Entry entry : newGradebookCategoryMap.entrySet()) { + String oldCategoryId = oldGradebookCategoryMap.get(entry.getKey()); + + boolean isExternalAssignmentDefined = gradingServiceApi.isExternalAssignmentDefined(entry.getKey(), + assessment.getPublishedAssessmentId().toString()); + + /* IF: HERE WE WILL NEED TO CHECK IF THE ITEM EXISTS IN THE GRADEBOOK AND, IF THE CATEGORY HAS CHANGED, + WE WILL PUT IT IN THE MAP OF ITEMS THAT NEED TO BE UPDATED + ELSE: HERE WE WILL NEED TO CHECK IF THE ITEM EXISTS IN THE GRADEBOOK, IF NOT, WE WILL PUT IT + IN THE MAP OF ITEMS THAT NEED TO BE CREATED */ + if (isExternalAssignmentDefined && !entry.getValue().equals(oldCategoryId)) { + updateGradebookCategoryMap.put(entry.getKey(), entry.getValue()); + } else if (!isExternalAssignmentDefined) { + createGradebookCategoryMap.put(entry.getKey(), entry.getValue()); + } + } + } else { + // IN THIS CASE, SINCE IT'S NOT A MULTI-GRADEBOOK, WE ONLY NEED THE PREVIOUS CATEGORY AND THE NEW ONE + Long newCategoryId = assessment.getCategoryId() != null ? assessment.getCategoryId() : -1L ; + boolean isExternalAssignmentDefined = gradingServiceApi.isExternalAssignmentDefined( + AgentFacade.getCurrentSiteId(), + assessment.getPublishedAssessmentId().toString()); + + if (isExternalAssignmentDefined && !newCategoryId.toString().equals(oldCategoryString)) { + updateGradebookCategoryMap.put(AgentFacade.getCurrentSiteId(), newCategoryId.toString()); + } else if (!isExternalAssignmentDefined) { + createGradebookCategoryMap.put(AgentFacade.getCurrentSiteId(), newCategoryId.toString()); + } + } + + if (createGradebookCategoryMap != null && createGradebookCategoryMap.size() >= 1) { + for (Map.Entry entry : createGradebookCategoryMap.entrySet()) { + try { + PublishedAssessmentData data = (PublishedAssessmentData) assessment.getData(); + Site site = SiteService.getSite(ToolManager.getCurrentPlacement().getContext()); + String ref = SamigoReferenceReckoner.reckoner().site(site.getId()).subtype("p").id(assessment.getPublishedAssessmentId().toString()).reckon().getReference(); + data.setReference(ref); + + gbsHelper.addToGradebook(entry.getKey(), data, !entry.getValue().equals("-1") ? Long.parseLong(entry.getValue()) : null, gradingServiceApi); + } catch(Exception e){ + log.warn("oh well, must have been added already:"+e.getMessage()); + } + } + + gbsHelper.manageScoresToNewGradebook(new GradingService(), gradingServiceApi, assessment, evaluation); + } + + /* WE WILL NEED TO UPDATE THE ITEMS FROM CASE 2 IF THE TITLE, SCORE, OR ANY OF THE CATEGORIES + HAVE CHANGED (IN CASE OF MULTI GRADEBOOK) */ + if (isTitleChanged || isScoringTypeChanged || updateGradebookCategoryMap.size() >= 1) { + List gradebookUidList = new ArrayList<>(); + + if (isGradebookGroupEnabled) { + gradebookUidList = assessmentSettings.getGroupsAuthorized() != null ? + Arrays.asList(assessmentSettings.getGroupsAuthorized()) : new ArrayList<>(); + } else { + gradebookUidList.add(AgentFacade.getCurrentSiteId()); + } + + try { + gbsHelper.updateGradebook(assessment, isGradebookGroupEnabled, gradebookUidList, updateGradebookCategoryMap, gradingServiceApi); + } catch (Exception e) { + String gbConflict_error = ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AssessmentSettingsMessages","gbConflict_error"); + context.addMessage(null, new FacesMessage(gbConflict_error)); + evaluation.setToGradeBook("0"); + log.warn("Exception thrown in updateGB():" + e.getMessage()); + return false; + } + } + } + } else { try { - gbsHelper.removeExternalAssessment(GradebookFacade.getGradebookUId(), assessment.getPublishedAssessmentId().toString(), gradingService); + gbsHelper.removeExternalAssessment(GradebookFacade.getGradebookUId(), assessment.getPublishedAssessmentId().toString(), gradingServiceApi); } catch(Exception e){ log.warn("No external assessment to remove: {}", e.getMessage()); } diff --git a/samigo/samigo-app/src/webapp/js/authoring.js b/samigo/samigo-app/src/webapp/js/authoring.js index 438f4e1dd22f..51ae9a6fa290 100644 --- a/samigo/samigo-app/src/webapp/js/authoring.js +++ b/samigo/samigo-app/src/webapp/js/authoring.js @@ -822,16 +822,26 @@ if (typeof MathJax != 'undefined') { } function toggleCategories(checkbox) { - // Toggle categories selector. If categories are disabled it won't exist - // so check first. - var categoryDiv = $('#assessmentSettingsAction\\:toGradebookCategory'); - if (categoryDiv.length) { - if ($(checkbox).val() === '1') { - categoryDiv.fadeIn(); - } else { - categoryDiv.fadeOut(); - } + // Toggle categories selector. If categories are disabled it won't exist + // so check first. + var categoryDiv = $('#assessmentSettingsAction\\:toGradebookCategory'); + var selectedGradebook = $('#assessmentSettingsAction\\:toGradebookSelected'); + + if (categoryDiv != undefined && categoryDiv.length) { + if ($(checkbox).val() === '1') { + categoryDiv.fadeIn(); + } else { + categoryDiv.fadeOut(); + } + } + + if (selectedGradebook != undefined && selectedGradebook.length) { + if ($(checkbox).val() === '3') { + selectedGradebook.fadeIn(); + } else { + selectedGradebook.fadeOut(); } + } } function expandAccordion(iframId){ diff --git a/samigo/samigo-app/src/webapp/jsf/author/authorSettings.jsp b/samigo/samigo-app/src/webapp/jsf/author/authorSettings.jsp index 915eb329a644..7b86dd7f2318 100644 --- a/samigo/samigo-app/src/webapp/jsf/author/authorSettings.jsp +++ b/samigo/samigo-app/src/webapp/jsf/author/authorSettings.jsp @@ -43,6 +43,16 @@ + + + + + + + ") #header_append("") #header_append("") +#header_append("") #chef_start() diff --git a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-addRemoveFeatureConfirm.vm b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-addRemoveFeatureConfirm.vm index 52def68be085..1f557dbe952a 100644 --- a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-addRemoveFeatureConfirm.vm +++ b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-addRemoveFeatureConfirm.vm @@ -46,9 +46,6 @@ #set($found=true) #end #end - #if(!$found && $!extraSelectedToolList.contains($newTool)) - #set($found=true) - #end ## if no added tools found then #if (!$found) diff --git a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-importSitesMigrate.vm b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-importSitesMigrate.vm index 20def04a2289..24abe10f760f 100644 --- a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-importSitesMigrate.vm +++ b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-importSitesMigrate.vm @@ -11,6 +11,9 @@ #if ($addMissingTools)

$tlang.getString("import.newtool")

#end +

+ $tlang.getString("import.gradebook") +

$tlang.getString("sitinfimp.choose")

@@ -147,4 +150,23 @@

+ diff --git a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-modifyENW.vm b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-modifyENW.vm index 41b07dd170a0..0f0ec098992d 100644 --- a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-modifyENW.vm +++ b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-modifyENW.vm @@ -49,6 +49,7 @@

$tlang.getString("multipleTools.custom1")

+ #set ($multiGb = false) #foreach($toolId in $!toolRegistrationSelectedList) ## set up a hidden input field for every selected tool except for Email Archive, and other multiple instance of tools #if ($toolId != "sakai.mailbox" && !$!multipleToolIdSet.contains($toolId)) @@ -94,7 +95,7 @@ #if($oldSelectedTools.contains($toolId)) #set($toolExist=true) #end - #if(!$toolExist && $!multipleToolIdTitleMap.containsKey($toolId)) + #if(!$toolExist && $!multipleToolIdTitleMap.containsKey($toolId) && $toolId != "sakai.gradebookng") #set($originToolId = false) #foreach ($tId in $!multipleToolIdSet) #if ($toolId!=$!homeToolId && $toolId.indexOf($tId) != -1) @@ -155,6 +156,9 @@ #end #end #end + #elseif(!$toolExist && $!multipleToolIdTitleMap.containsKey($toolId) && $toolId == "sakai.gradebookng") + #set ($multiGb = true) + #end ## and update the oldOriginalToolId #set($oldOriginToolId = $originToolId) @@ -175,7 +179,11 @@ #end #end - + + #if ($multiGb) + #parse("vm/sitesetup/gradebook_group.vm") + #end + diff --git a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-siteInfo-list.vm b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-siteInfo-list.vm index 1e591127f91e..9c756f2e2398 100644 --- a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-siteInfo-list.vm +++ b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/chef_site-siteInfo-list.vm @@ -274,6 +274,16 @@ #end + #if ($isGradebookGroupEnabledForSite) + + + $tlang.getString("sinfo.gradebookgroupvnav.name") + + + $tlang.getString("sinfo.gradebookgroupvnav.enabled") + + + #end #if ($siteJoinable && $allowUnjoin) diff --git a/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/gradebook_group.vm b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/gradebook_group.vm new file mode 100644 index 000000000000..b129fa73d09c --- /dev/null +++ b/site-manage/site-manage-tool/tool/src/webapp/vm/sitesetup/gradebook_group.vm @@ -0,0 +1,75 @@ + + +

$tlang.getString("sinfo.gradebookgroupvnav.name")

+ +## Radio Option 1: One gradebook instance for the site +
+ +
+ +## Radio Option 2: Gradebook instances for selected Groups +#set($disableGroupAssignment = !$!groupsList) +
+ +
+ +#if(!$disableGroupAssignment && $value_gb == $value_gbGroups) + #set( $listDisplay = "block" ) +#else + #set( $listDisplay = "none" ) +#end + +## Message Area 1 +
+#if( !$!groupsList ) +
$tlang.getString("sinfo.gradebookgroupvnav.noGroupsPresent")
+#end +
+ +## Groups multiselect, visible when Option 2 is chosen +
+
+ + +
+
diff --git a/vuecomponents/bundle/src/main/bundle/gb-selector.properties b/vuecomponents/bundle/src/main/bundle/gb-selector.properties new file mode 100644 index 000000000000..07ccc5feb12d --- /dev/null +++ b/vuecomponents/bundle/src/main/bundle/gb-selector.properties @@ -0,0 +1,7 @@ +groups=Groups +search_filter=Select one or more elements +no_options=No items for this site +no_results=No gradebook items found. Consider changing the search query. +select=Press enter to select this item +selected=Selected +deselect=Deselect diff --git a/vuecomponents/bundle/src/main/bundle/gb-selector_es.properties b/vuecomponents/bundle/src/main/bundle/gb-selector_es.properties new file mode 100644 index 000000000000..12850041837a --- /dev/null +++ b/vuecomponents/bundle/src/main/bundle/gb-selector_es.properties @@ -0,0 +1,7 @@ +groups=Grupos +search_filter=Seleccione uno o más elementos +no_options=No hay ítems para el sitio +no_results=No se han encontrado resultados para la búsqueda actual +select=Pulsar Enter para seleccionar ítem +selected=Seleccionado +deselect=Deseleccionar diff --git a/vuecomponents/docs/i18n.md b/vuecomponents/docs/i18n.md index 817308ba8ef0..743c1666a04b 100644 --- a/vuecomponents/docs/i18n.md +++ b/vuecomponents/docs/i18n.md @@ -6,6 +6,8 @@ You can easily internationalize your vue component with the i18n mixin. First, create a properties file with all the strings you need for your component. After building `vuecomponents/bundle` you should restart your tomcat if it was running, because the properties are loaded on tomcat startup. +Also the first time you might need to execute "sessionStorage.clear()" in the browser's console for changes to take effect. + Ideally set the same name for the properties file, as you name your component (`avatar.vue` => `avatar.propeties`). ## Use the i18n mixin diff --git a/vuecomponents/tool/src/main/frontend/src/components-api/gb-selector-input-sync.js b/vuecomponents/tool/src/main/frontend/src/components-api/gb-selector-input-sync.js new file mode 100644 index 000000000000..cc4a77fe7bc5 --- /dev/null +++ b/vuecomponents/tool/src/main/frontend/src/components-api/gb-selector-input-sync.js @@ -0,0 +1,33 @@ +// Applies the selected value of an gb-selector instance to an html input once it changes +// The function registered globally if there is a gb-selector component but can also be imported +// Optionally a callback function that receives the gb ids as through the first parameter +// Returns the initial gb ids that are selected +export default function syncGbSelectorInput(gbSelectorId, inputId, callbackFn) { + const input = document.getElementById(inputId); + const gbSelector = document.getElementById(gbSelectorId); + if (input && gbSelector) { + gbSelector.addEventListener("change", (event) => { + const gbs = event.detail?.[0]; + if (gbs) { + // Ids of the gbs separated by comma + const gbIds = gbs.map(gb => gb.id); + input.value = gbIds.join(","); + // Call callback function if present + callbackFn?.(gbIds); + } + }); + } else { + if (!gbSelector) { + console.error(`GB selector with id ${gbSelectorId} not found`); + } + + if (!input) { + console.error(`Input with id ${inputId} not found`); + } + } + + // Return the gbIds of the inputs initial value + return input?.value?.split(",").filter(gbId => gbId != "") ?? null; +} + +window.syncGbSelectorInput = syncGbSelectorInput; diff --git a/vuecomponents/tool/src/main/frontend/src/components/multi-gradebook.vue b/vuecomponents/tool/src/main/frontend/src/components/multi-gradebook.vue new file mode 100644 index 000000000000..cc9f5d5fc029 --- /dev/null +++ b/vuecomponents/tool/src/main/frontend/src/components/multi-gradebook.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookItemRestBean.java b/webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookItemRestBean.java new file mode 100644 index 000000000000..1f83b982c377 --- /dev/null +++ b/webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookItemRestBean.java @@ -0,0 +1,15 @@ +package org.sakaiproject.webapi.beans; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class GradebookItemRestBean { + + private String id; + + private String name; + + private boolean disabled; +} diff --git a/webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookRestBean.java b/webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookRestBean.java new file mode 100644 index 000000000000..202d3ff29c0b --- /dev/null +++ b/webapi/src/main/java/org/sakaiproject/webapi/beans/GradebookRestBean.java @@ -0,0 +1,18 @@ +package org.sakaiproject.webapi.beans; + +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class GradebookRestBean { + + private String uid; + + private String name; + + private List items; + +} diff --git a/webapi/src/main/java/org/sakaiproject/webapi/controllers/GradesController.java b/webapi/src/main/java/org/sakaiproject/webapi/controllers/GradesController.java index cf5ae34ba462..9573585a1159 100644 --- a/webapi/src/main/java/org/sakaiproject/webapi/controllers/GradesController.java +++ b/webapi/src/main/java/org/sakaiproject/webapi/controllers/GradesController.java @@ -15,16 +15,28 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.sakaiproject.assignment.api.AssignmentServiceConstants; import org.sakaiproject.authz.api.Role; +import org.sakaiproject.authz.api.SecurityService; import org.sakaiproject.entity.api.Entity; import org.sakaiproject.entity.api.EntityManager; +import org.sakaiproject.exception.IdUnusedException; +import org.sakaiproject.grading.api.Assignment; +import org.sakaiproject.grading.api.CategoryDefinition; import org.sakaiproject.grading.api.GradeDefinition; import org.sakaiproject.grading.api.GradingConstants; +import org.sakaiproject.grading.api.SortType; +import org.sakaiproject.grading.api.model.Gradebook; import org.sakaiproject.portal.api.PortalService; +import org.sakaiproject.site.api.Group; +import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.tool.api.Session; import org.sakaiproject.user.api.UserNotDefinedException; +import org.sakaiproject.user.api.UserDirectoryService; +import org.sakaiproject.webapi.beans.GradebookItemRestBean; +import org.sakaiproject.webapi.beans.GradebookRestBean; import org.sakaiproject.webapi.beans.GradeRestBean; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; @@ -54,10 +66,16 @@ public class GradesController extends AbstractSakaiApiController { @Resource private SiteService siteService; + @Resource + private SecurityService securityService; + + @Resource + private UserDirectoryService userDirectoryService; + private final Function> gradeDataSupplierForSite = (siteId) -> { - List assignments = gradingService.getViewableAssignmentsForCurrentUser(siteId); - List assignmentIds = assignments.stream().map(org.sakaiproject.grading.api.Assignment::getId).collect(Collectors.toList()); + List assignments = gradingService.getViewableAssignmentsForCurrentUser(siteId, siteId, SortType.SORT_BY_NONE); + List assignmentIds = assignments.stream().map(Assignment::getId).collect(Collectors.toList()); // no need to continue if the site doesn't have gradebook items if (assignmentIds.isEmpty()) return Collections.emptyList(); @@ -76,11 +94,11 @@ public class GradesController extends AbstractSakaiApiController { .collect(Collectors.toList()) : List.of(userId); - Map> gradeDefinitions = gradingService.getGradesWithoutCommentsForStudentsForItems(siteId, assignmentIds, userIds); + Map> gradeDefinitions = gradingService.getGradesWithoutCommentsForStudentsForItems(siteId, siteId, assignmentIds, userIds); List beans = new ArrayList<>(); // collect information for each gradebook item - for (org.sakaiproject.grading.api.Assignment a : assignments) { + for (Assignment a : assignments) { GradeRestBean bean = new GradeRestBean(a); bean.setSiteTitle(site.getTitle()); bean.setSiteRole(role.getId()); @@ -125,8 +143,11 @@ public class GradesController extends AbstractSakaiApiController { url = entityManager.getUrl(a.getReference(), Entity.UrlType.PORTAL).orElse(""); } if (StringUtils.isBlank(url)) { - ToolConfiguration tc = site.getToolForCommonId("sakai.gradebookng"); - url = tc != null ? "/portal/directtool/" + tc.getId() : ""; + Collection gbs = site.getTools("sakai.gradebookng"); + for (ToolConfiguration tc : gbs) { + url = tc != null ? "/portal/directtool/" + tc.getId() : ""; + break; + } } bean.setUrl(url); @@ -154,4 +175,106 @@ public List getSiteGrades(@PathVariable String siteId) throws Use return gradeDataSupplierForSite.apply(siteId); } + @GetMapping(value = {"/sites/{siteId}/items/{appName}", "/sites/{siteId}/items/{appName}/{userId}"}, produces = MediaType.APPLICATION_JSON_VALUE) + public List getSiteItems(@PathVariable String siteId, @PathVariable String appName, @PathVariable Optional userId) throws UserNotDefinedException { + checkSakaiSession(); + + List gbWithItems = new ArrayList<>(); + String user = userDirectoryService.getCurrentUser().getId(); + if (userId.isPresent()) { + user = userId.get(); + } + + Map gradebookGroupMap = returnFoundGradebooks(siteId, user); + + for (Map.Entry entry : gradebookGroupMap.entrySet()) { + List gbItems = new ArrayList<>(); + + String gbUid = entry.getKey(); + String groupTitle = entry.getValue(); + + List gradebookAssignments = gradingService.getAssignments(gbUid, siteId, SortType.SORT_BY_NONE); + + for (Assignment gAssignment : gradebookAssignments) { + if (!gAssignment.getExternallyMaintained() || gAssignment.getExternallyMaintained() && gAssignment.getExternalAppName().equals(appName)) { + // gradebook item has been associated or not + String gaId = gAssignment.getId().toString(); + // gradebook assignment label + String label = gAssignment.getName(); + + GradebookItemRestBean itemDto = new GradebookItemRestBean(gaId, label, false); + gbItems.add(itemDto); + } + } + + GradebookRestBean gbDto = new GradebookRestBean(gbUid, groupTitle, gbItems); + gbWithItems.add(gbDto); + + } + + return gbWithItems; + } + + @GetMapping(value = "/sites/{siteId}/categories", produces = MediaType.APPLICATION_JSON_VALUE) + public List getGroupCategoriesList(@PathVariable String siteId) throws UserNotDefinedException { + checkSakaiSession(); + + List gbWithItems = new ArrayList<>(); + + Map gradebookGroupMap = returnFoundGradebooks(siteId, userDirectoryService.getCurrentUser().getId()); + + for (Map.Entry entry : gradebookGroupMap.entrySet()) { + List gbItems = new ArrayList<>(); + + String gbUid = entry.getKey(); + String groupTitle = entry.getValue(); + + if (gradingService.isCategoriesEnabled(gbUid)) { + List categoryDefinitionList = gradingService.getCategoryDefinitions(gbUid, siteId); + + for (CategoryDefinition category : categoryDefinitionList) { + Long categoryId = category.getId(); + String categoryName = category.getName(); + + gbItems.add(new GradebookItemRestBean(categoryId.toString(), categoryName, false)); + } + } + + gbWithItems.add(new GradebookRestBean(gbUid, groupTitle, gbItems)); + } + + return gbWithItems; + } + + private Map returnFoundGradebooks(String siteId, String userId) { + try { + List gradebookList = gradingService.getGradebookGroupInstances(siteId); + Map gradebookGroupMap = new HashMap<>(); + + Site site = siteService.getSite(siteId); + Collection groupList = site.getGroups(); + + // a specific user id is sent in some cases like forums + boolean isInstructor = userId.equals(userDirectoryService.getCurrentUser().getId()) && (securityService.isSuperUser() || securityService.unlock("section.role.instructor", site.getReference())); + List groupIds = site.getGroupsWithMember(userId).stream().map(Group::getId).collect(Collectors.toList()); + + gradebookList.forEach(gradebook -> { + String gradebookUid = gradebook.getUid(); + + Optional opGroup = groupList.stream() + .filter(group -> group.getId().equals(gradebookUid)) + .findFirst(); + + if(opGroup.isPresent() && (isInstructor || groupIds.contains(opGroup.get().getId()))) { + gradebookGroupMap.put(gradebookUid, opGroup.get().getTitle()); + } + }); + + return gradebookGroupMap; + } catch (IdUnusedException e) { + log.error("Error while trying to get gradebooks for site {} : {}", siteId, e.getMessage()); + return new HashMap<>(); + } + } + } diff --git a/webapi/src/main/java/org/sakaiproject/webapi/controllers/LessonsController.java b/webapi/src/main/java/org/sakaiproject/webapi/controllers/LessonsController.java index 39e1e23d4467..eb4cc63d8993 100644 --- a/webapi/src/main/java/org/sakaiproject/webapi/controllers/LessonsController.java +++ b/webapi/src/main/java/org/sakaiproject/webapi/controllers/LessonsController.java @@ -120,7 +120,7 @@ public ResponseEntity deleteLessonItems(@PathVariable String siteId, @Pa List.of(Optional.ofNullable(item.getGradebookId()), Optional.ofNullable(item.getAltGradebook())).stream() .flatMap(Optional::stream) .forEach(gradebookExternalId -> { - gradingService.removeExternalAssignment(gradebookExternalId, gradebookExternalId); + gradingService.removeExternalAssignment(null, gradebookExternalId, LessonBuilderConstants.TOOL_ID); }); boolean deleted = false; diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-submission-messager/src/SakaiSubmissionMessager.js b/webcomponents/tool/src/main/frontend/packages/sakai-submission-messager/src/SakaiSubmissionMessager.js index e0bd21b601fe..861ae3b7ccfc 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-submission-messager/src/SakaiSubmissionMessager.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-submission-messager/src/SakaiSubmissionMessager.js @@ -21,6 +21,8 @@ export class SakaiSubmissionMessager extends SakaiElement { recipientsToCheck: Array, sending: Boolean, i18n: Object, + gUid: { attribute: "gradebook-id", type: String }, + showGroups: Boolean }; constructor() { @@ -33,6 +35,15 @@ export class SakaiSubmissionMessager extends SakaiElement { this.group = `/site/${portal.siteId}`; this.reset(); this.loadTranslations("submission-messager").then(t => this.i18n = t); + this.showGroups = true; + } + + firstUpdated() { + // S2U-26 + if (portal.siteId !== this.gUid) { + this.group = `/site/${portal.siteId}/group/${this.gUid}`; + this.showGroups = false; + } } shouldUpdate() { @@ -68,14 +79,16 @@ export class SakaiSubmissionMessager extends SakaiElement {
- ${this.i18n.select_group} - - + ${this.showGroups ? html` + ${this.i18n.select_group} + + + ` : ""}
${this.recipientsToCheck.length > 0 ? html` @@ -134,6 +147,7 @@ export class SakaiSubmissionMessager extends SakaiElement { this.minScore = ""; this.maxScore = ""; this.validationError = ""; + this.showGroups = ""; } getFormData() { @@ -147,6 +161,7 @@ export class SakaiSubmissionMessager extends SakaiElement { formData.set("subject", this.subject); formData.set("body", this.body); formData.set("assignmentId", this.assignmentId); + formData.set("gUid", this.gUid); return formData; } diff --git a/webservices/cxf/src/java/org/sakaiproject/webservices/Assignments.java b/webservices/cxf/src/java/org/sakaiproject/webservices/Assignments.java index cd6973227fc8..1c2b5a8dff0f 100644 --- a/webservices/cxf/src/java/org/sakaiproject/webservices/Assignments.java +++ b/webservices/cxf/src/java/org/sakaiproject/webservices/Assignments.java @@ -18,9 +18,11 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.Instant; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; @@ -51,6 +53,7 @@ import org.sakaiproject.grading.api.AssignmentHasIllegalPointsException; import org.sakaiproject.grading.api.ConflictingAssignmentNameException; import org.sakaiproject.grading.api.ConflictingExternalIdException; +import org.sakaiproject.grading.api.model.GradebookAssignment; import org.sakaiproject.tool.api.Session; import org.sakaiproject.user.api.User; import org.sakaiproject.util.Xml; @@ -230,7 +233,7 @@ public String setAssignmentGradeCommentforUser( return "failure: no permission"; } - log.info("Setting assignment grade/comment for " + userId + " on " + assignmentId + " to " + grade); + log.info("Setting assignment grade/comment for {} on to {}", userId, assignmentId, grade); AssignmentSubmission sub = assignmentService.getSubmission(assignmentId, user); String context = assign.getContext(); @@ -250,9 +253,39 @@ public String setAssignmentGradeCommentforUser( String associateGradebookAssignment = assign.getProperties().get(AssignmentConstants.PROP_ASSIGNMENT_ASSOCIATE_GRADEBOOK_ASSIGNMENT); String sReference = AssignmentReferenceReckoner.reckoner().submission(sub).reckon().getReference(); - // update grade in gradebook - integrateGradebook(aReference, associateGradebookAssignment, null, null, -1, null, sReference, "update", context); - + if (!gradingService.isGradebookGroupEnabled(context)) { + // update grade in gradebook + integrateGradebook(aReference, associateGradebookAssignment, null, null, -1, null, sReference, "update", context, context); + } else { + + List gradebookUids = gradingService.getGradebookGroupInstancesIds(context); + for (String gradebookUid : gradebookUids) { + + // Since there is a possibility that the "associateGradebookAssignment" + // variable is comma-separated, we need to split it into a list. + List itemList = Arrays.asList(associateGradebookAssignment.split(",")); + + for (String item : itemList) { + // We need to check whether it is a reference or a gradebook item ID. + boolean isExternalAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, item); + + if (isExternalAssignmentDefined) { + // In this case, no further actions are required. + integrateGradebook(aReference, item, null, null, -1, null, sReference, "update", gradebookUid, context); + } else { + // In this case, we need to find the item in the list that matches the group being iterated. + Long itemId = Long.parseLong(item); + + GradebookAssignment gradebookAssignment = gradingService.getGradebookAssigment(gradebookUid, itemId); + + if (gradebookAssignment != null && gradebookAssignment.getGradebook() != null && + gradebookAssignment.getGradebook().getUid().equals(gradebookUid)) { + integrateGradebook(aReference, item, null, null, -1, null, sReference, "update", gradebookUid, context); + } + } + } + } + } } catch (Exception e) { @@ -270,6 +303,7 @@ public String setAssignmentGradeCommentforUser( @GET public String createAssignment( @WebParam(name = "sessionId", partName = "sessionId") @QueryParam("sessionId") String sessionId, + @WebParam(name = "gradebookUid", partName = "gradebookUid") @QueryParam("gradebookUid") String gradebookUid, @WebParam(name = "context", partName = "context") @QueryParam("context") String context, @WebParam(name = "title", partName = "title") @QueryParam("title") String title, @WebParam(name = "dueTime", partName = "dueTime") @QueryParam("dueTime") long dueTime, @@ -281,7 +315,10 @@ public String createAssignment( @WebParam(name = "subType", partName = "subType") @QueryParam("subType") int subType) { - log.info("creating assignment in " + context); + if (gradebookUid == null) { + gradebookUid = context; + } + log.info("creating assignment in " + gradebookUid); try { Session s = establishSession(sessionId); Assignment assign = assignmentService.addAssignment(context); @@ -330,7 +367,7 @@ public String createAssignment( //do GB integration String aReference = AssignmentReferenceReckoner.reckoner().assignment(assign).reckon().getReference(); - integrateGradebook(aReference, null, "add", title, maxGradePoints, Date.from(dt), null, null, context); + integrateGradebook(aReference, null, "add", title, maxGradePoints, Date.from(dt), null, null, gradebookUid, context); Calendar c = null; try { @@ -453,7 +490,7 @@ public String shiftAssignmentDates( return "success"; } - // This is a copy of the code in AssignmentAction.java + // This is a (probably outdated) copy of the code in AssignmentToolUtils.java - it would be a good idea to compare it or move it to the service and call it directly - SAK-50340 /** * * @param assignmentRef @@ -464,38 +501,37 @@ public String shiftAssignmentDates( * @param newAssignment_dueTime * @param submissionRef * @param updateRemoveSubmission + * @param gradebookUid * @param context */ - protected void integrateGradebook( String assignmentRef, String associateGradebookAssignment, String addUpdateRemoveAssignment, String newAssignment_title, int newAssignment_maxPoints, Date newAssignment_dueTime, String submissionRef, String updateRemoveSubmission, String context) + protected void integrateGradebook( String assignmentRef, String associateGradebookAssignment, String addUpdateRemoveAssignment, String newAssignment_title, int newAssignment_maxPoints, Date newAssignment_dueTime, String submissionRef, String updateRemoveSubmission, String gradebookUid, String context) { //add or remove external grades to gradebook - // a. if Gradebook does not exists, do nothing, 'cos setting should have been hidden + // a. if Gradebook does not exist, do nothing, 'cos setting should have been hidden // b. if Gradebook exists, just call addExternal and removeExternal and swallow any exception. The // exception are indication that the assessment is already in the Gradebook or there is nothing // to remove. - String gradebookUid = context; String assignmentToolTitle = "Assignments"; boolean isExternalAssignmentDefined=gradingService.isExternalAssignmentDefined(gradebookUid, assignmentRef); boolean isExternalAssociateAssignmentDefined = gradingService.isExternalAssignmentDefined(gradebookUid, associateGradebookAssignment); - boolean isAssignmentDefined = gradingService.isAssignmentDefined(gradebookUid, associateGradebookAssignment); if (addUpdateRemoveAssignment != null) { - if (addUpdateRemoveAssignment.equals("add") || ( addUpdateRemoveAssignment.equals("update") && !gradingService.isAssignmentDefined(gradebookUid, newAssignment_title))) + if (addUpdateRemoveAssignment.equals("add") || ( addUpdateRemoveAssignment.equals("update") && !gradingService.isAssignmentDefined(gradebookUid, context, newAssignment_title))) { // add assignment into gradebook try { // add assignment to gradebook - gradingService.addExternalAssessment(gradebookUid, + gradingService.addExternalAssessment(gradebookUid, context, assignmentRef, null, newAssignment_title, - newAssignment_maxPoints/10, + newAssignment_maxPoints/(double) 10, new Date(newAssignment_dueTime.getTime()), "sakai.assignment.grades", - null); + null, null, null, null); } catch (AssignmentHasIllegalPointsException e) { @@ -511,19 +547,19 @@ protected void integrateGradebook( String assignmentRef, String associateGradebo { String newTitle = titleBase + "-" + attempts; - if(!gradingService.isAssignmentDefined(gradebookUid, newTitle)) + if(!gradingService.isAssignmentDefined(gradebookUid, context, newTitle)) { try { // add assignment to gradebook - gradingService.addExternalAssessment(gradebookUid, + gradingService.addExternalAssessment(gradebookUid, context, assignmentRef, null, newTitle, - newAssignment_maxPoints/10, + newAssignment_maxPoints/(double) 10, new Date(newAssignment_dueTime.getTime()), "sakai.assignment.grades", - null); + null, null, null, null); trying = false; } catch(Exception ee) @@ -596,26 +632,12 @@ protected void integrateGradebook( String assignmentRef, String associateGradebo if (isExternalAssociateAssignmentDefined) { // the associated assignment is externally maintained - gradingService.updateExternalAssessmentScores(gradebookUid, associateGradebookAssignment, m); - } - else if (isAssignmentDefined) - { - // the associated assignment is internal one, update records one by one - submissions = assignmentService.getSubmissions(a).iterator(); - while (submissions.hasNext()) - { - AssignmentSubmission aSubmission = (AssignmentSubmission) submissions.next(); - Set submitters = aSubmission.getSubmitters(); - String submitterId = submitters.stream().filter(AssignmentSubmissionSubmitter::getSubmittee).findFirst().get().getSubmitter(); - String gradeString = StringUtils.trimToNull(aSubmission.getGrade()); - String grade = (gradeString != null && aSubmission.getGradeReleased()) ? displayGrade(gradeString) : null; - gradingService.setAssignmentScoreString(gradebookUid, associateGradebookAssignment, submitterId, grade, assignmentToolTitle); - } + gradingService.updateExternalAssessmentScores(gradebookUid, context, associateGradebookAssignment, m); } } else if (isExternalAssignmentDefined) { - gradingService.updateExternalAssessmentScores(gradebookUid, assignmentRef, m); + gradingService.updateExternalAssessmentScores(gradebookUid, context, assignmentRef, m); } } } @@ -634,19 +656,13 @@ else if (isExternalAssignmentDefined) if (gradingService.isExternalAssignmentDefined(gradebookUid, associateGradebookAssignment)) { // the associated assignment is externally maintained - gradingService.updateExternalAssessmentScore(gradebookUid, associateGradebookAssignment, submitter, + gradingService.updateExternalAssessmentScore(gradebookUid, context, associateGradebookAssignment, submitter, (gradeString != null && aSubmission.getGradeReleased()) ? displayGrade(gradeString) : null); } - else if (gradingService.isAssignmentDefined(gradebookUid, associateGradebookAssignment)) - { - // the associated assignment is internal one, update records - gradingService.setAssignmentScoreString(gradebookUid, associateGradebookAssignment, submitter, - (gradeString != null && aSubmission.getGradeReleased()) ? displayGrade(gradeString) : null, assignmentToolTitle); - } } else { - gradingService.updateExternalAssessmentScore(gradebookUid, assignmentRef, submitter, + gradingService.updateExternalAssessmentScore(gradebookUid, context, assignmentRef, submitter, (gradeString != null && aSubmission.getGradeReleased()) ? displayGrade(gradeString) : null); } } @@ -673,11 +689,7 @@ else if (updateRemoveSubmission.equals("remove")) if (isExternalAssociateAssignmentDefined) { // if the old associated assignment is an external maintained one - gradingService.updateExternalAssessmentScore(gradebookUid, associateGradebookAssignment, submitter, null); - } - else if (isAssignmentDefined) - { - gradingService.setAssignmentScoreString(gradebookUid, associateGradebookAssignment, submitter, null, assignmentToolTitle); + gradingService.updateExternalAssessmentScore(gradebookUid, context, associateGradebookAssignment, submitter, null); } } } @@ -689,7 +701,7 @@ else if (isAssignmentDefined) AssignmentSubmission aSubmission = (AssignmentSubmission) assignmentService.getSubmission(submissionRef); Set submitters = aSubmission.getSubmitters(); String submitter = submitters.stream().filter(AssignmentSubmissionSubmitter::getSubmittee).findFirst().get().getSubmitter(); - gradingService.updateExternalAssessmentScore(gradebookUid, assignmentRef, submitter, null); + gradingService.updateExternalAssessmentScore(gradebookUid, context, assignmentRef, submitter, null); } catch (Exception e) { diff --git a/webservices/cxf/src/java/org/sakaiproject/webservices/SakaiGradebook.java b/webservices/cxf/src/java/org/sakaiproject/webservices/SakaiGradebook.java index 8c563415fe03..f78faa3cce04 100644 --- a/webservices/cxf/src/java/org/sakaiproject/webservices/SakaiGradebook.java +++ b/webservices/cxf/src/java/org/sakaiproject/webservices/SakaiGradebook.java @@ -140,36 +140,38 @@ public String createOrUpdateGradeScale( List siteList = siteService.getSiteIds(SelectionType.NON_USER, null, null, null, SortType.NONE, null); for (String siteId : siteList) { - //If the site has gradebook then we - Gradebook gradebook = gradingService.getGradebook(siteId); - String gradebookUid=gradebook.getUid(); - Long gradebookId=gradebook.getId(); - - if (!isUpdate) { //If it is new then we need to add the scale to every actual gradebook in the list - gradingService.saveGradeMappingToGradebook(scaleUuid, gradebookUid); - log.debug("SakaiGradebook: Adding the new scale " + scaleUuid + " in gradebook: " + gradebook.getUid()); - - }else{ //If it is not new, then update the actual gradebooks with the new values ONLY if updateOld is true - if (updateOld) { - Set gradeMappings = gradingService.getGradebookGradeMappings(gradebookId); - for (Iterator iter2 = gradeMappings.iterator(); iter2.hasNext();) { - GradeMapping gradeMapping = (GradeMapping)iter2.next(); - if (gradeMapping.getGradingScale().getUid().equals(scaleUuid)){ - if (updateOnlyNotCustomized){ //We will only update the ones that teachers have not customized - if (mapsAreEqual(defaultBottomPercentsOld, gradeMapping.getGradeMap())){ - log.debug("SakaiGradebook:They are equals " + gradebook.getUid()); - gradeMapping.setDefaultValues(); + List gradebookUids = Arrays.asList(siteId); + if (gradingService.isGradebookGroupEnabled(siteId)) { + gradebookUids = gradingService.getGradebookGroupInstancesIds(siteId); + } + for (String gradebookUid : gradebookUids) { + Gradebook gradebook = gradingService.getGradebook(gradebookUid, siteId); + Long gradebookId=gradebook.getId(); + + if (!isUpdate) { //If it is new then we need to add the scale to every actual gradebook in the list + gradingService.saveGradeMappingToGradebook(scaleUuid, gradebookUid); + log.debug("SakaiGradebook: Adding the new scale " + scaleUuid + " in gradebook: " + gradebook.getUid()); + }else{ //If it is not new, then update the actual gradebooks with the new values ONLY if updateOld is true + if (updateOld) { + Set gradeMappings = gradingService.getGradebookGradeMappings(gradebookId); + for (Iterator iter2 = gradeMappings.iterator(); iter2.hasNext();) { + GradeMapping gradeMapping = (GradeMapping)iter2.next(); + if (gradeMapping.getGradingScale().getUid().equals(scaleUuid)){ + if (updateOnlyNotCustomized){ //We will only update the ones that teachers have not customized + if (mapsAreEqual(defaultBottomPercentsOld, gradeMapping.getGradeMap())){ + log.debug("SakaiGradebook:They are equals " + gradebook.getUid()); + gradeMapping.setDefaultValues(); + }else{ + log.debug("SakaiGradebook:They are NOT equals " + gradebook.getUid()); + } }else{ - log.debug("SakaiGradebook:They are NOT equals " + gradebook.getUid()); + gradeMapping.setDefaultValues(); } - }else{ - gradeMapping.setDefaultValues(); + log.debug("SakaiGradebook: updating gradeMapping" + gradeMapping.getName()); + gradingService.updateGradeMapping(gradeMapping.getId(),gradeMapping.getGradeMap()); } - log.debug("SakaiGradebook: updating gradeMapping" + gradeMapping.getName()); - gradingService.updateGradeMapping(gradeMapping.getId(),gradeMapping.getGradeMap()); } - } - + } } } }