/** * Returns the <code>SubscriptionContext</code> to use for assessment notification about specified * <code>ICourse</code>.<br> * <br> * <b>PRE CONDITIONS</b> * * <ul> * <li><code>course != null</code> * </ul> * * If <code>ident == null</code>, the subscription context is (created and) returned without * authorization control * * @param ident the identity, if null, no subscription check will be made * @param course * @return the subscription context to use or <code>null</code> if the identity associated to the * request is not allowed to be notified * @see #canSubscribeForAssessmentNotification(Identity, ICourse) */ protected SubscriptionContext getAssessmentSubscriptionContext(Identity ident, ICourse course) { SubscriptionContext sctx = null; if (ident == null || canSubscribeForAssessmentNotification(ident, course)) { // Creates a new SubscriptionContext only if not found into cache Long courseId = course.getResourceableId(); synchronized ( subsContexts) { // o_clusterOK by:ld - no problem to have independent subsContexts caches // for each cluster node sctx = subsContexts.get(courseId); if (sctx == null) { // a subscription context showing to the root node (the course's root // node is started when clicking such a notification) CourseNode cn = course.getRunStructure().getRootNode(); CourseEnvironment ce = course.getCourseEnvironment(); // FIXME:fg:b little problem is that the assessment tool and the course are not "the same" // anymore, that is you can open the same course twice in the // dynamic tabs by a) klicking e.g. via repo, and b via notifications link to the // assementtool sctx = new SubscriptionContext( CourseModule.ORES_COURSE_ASSESSMENT, ce.getCourseResourceableId(), cn.getIdent()); subsContexts.put(courseId, sctx); } } } return sctx; }
private void loadModel(UserRequest ureq) { IdentityEnvironment identityEnv = ureq.getUserSession().getIdentityEnvironment(); List<Binder> currentBinders = portfolioService.searchOwnedBindersFromCourseTemplate(getIdentity()); Set<CurrentBinder> currentSet = new HashSet<>(); for (Binder currentBinder : currentBinders) { Long courseEntryKey = currentBinder.getEntry().getKey(); String nodeIdent = currentBinder.getSubIdent(); currentSet.add(new CurrentBinder(courseEntryKey, nodeIdent)); } List<RepositoryEntry> entries = portfolioService.searchCourseWithBinderTemplates(getIdentity()); List<CourseTemplateRow> rows = new ArrayList<>(entries.size()); for (RepositoryEntry entry : entries) { ICourse course = CourseFactory.loadCourse(entry); UserCourseEnvironment uce = new UserCourseEnvironmentImpl(identityEnv, course.getCourseEnvironment()); uce.getScoreAccounting().evaluateAll(); CourseNode rootNode = uce.getCourseEnvironment().getRunStructure().getRootNode(); loadCourseModel(rootNode, uce, rows, currentSet); } model.setObjects(rows); tableEl.reset(); tableEl.reloadData(); }
private AssessableCourseNode getCourseNode() { ICourse course = CourseFactory.loadCourse(courseRes); CourseNode node = course.getRunStructure().getNode(courseNodeIdent); if (node instanceof AssessableCourseNode) { return (AssessableCourseNode) node; } return null; }
private boolean isCourseCalendarEnabled(ICourse course) { if (course.getCourseConfig().isCalendarEnabled()) { return true; } CourseNode rootNode = course.getRunStructure().getRootNode(); CalCourseNodeVisitor v = new CalCourseNodeVisitor(); new TreeVisitor(v, rootNode, true).visitAll(); return v.isFound(); }
public void event(UserRequest ureq, Controller source, Event event) { if (source == logFileChooserForm) { if (event == Event.DONE_EVENT) { final boolean logAdminChecked = logFileChooserForm.logAdminChecked(); final boolean logUserChecked = logFileChooserForm.logUserChecked(); final boolean logStatisticChecked = logFileChooserForm.logStatChecked(); final Date begin = logFileChooserForm.getBeginDate(); final Date end = logFileChooserForm.getEndDate(); if (end != null) { // shift time from beginning to end of day end.setTime(end.getTime() + 24 * 60 * 60 * 1000); } UserManager um = UserManager.getInstance(); final String charset = um.getUserCharset(ureq.getIdentity()); ICourse course = CourseFactory.loadCourse(ores); final String courseTitle = course.getCourseTitle(); final String targetDir = CourseFactory.getOrCreateDataExportDirectory(ureq.getIdentity(), courseTitle).getPath(); final Long resId = ores.getResourceableId(); final Locale theLocale = ureq.getLocale(); final String email = ureq.getIdentity().getUser().getProperty(UserConstants.EMAIL, ureq.getLocale()); AsyncExportManager.getInstance() .asyncArchiveCourseLogFiles( ureq.getIdentity(), new Runnable() { @Override public void run() { showExportFinished(); } }, resId, targetDir, begin, end, logAdminChecked, logUserChecked, logStatisticChecked, charset, theLocale, email); showExportOngoing(true); } else if (event == Event.DONE_EVENT) { myPanel.setContent(myContent); } } }
private void doInsert(UserRequest ureq, TreePosition tp) { ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId()); int insertPos = tp.getChildpos(); CourseNode selectedNode = getCourseNode(tp.getParentTreeNode()); CourseEditorTreeNode insertParent = course.getEditorTreeModel().getCourseEditorNodeById(selectedNode.getIdent()); // check if insert position is within the to-be-copied tree if (course.getEditorTreeModel().checkIfIsChild(insertParent, moveCopyFrom)) { showError("movecopynode.error.overlap"); fireEvent(ureq, Event.CANCELLED_EVENT); } else if (copy) { // do a copy // copy subtree and save model recursiveCopy( moveCopyFrom, insertParent, insertPos, true, CourseFactory.getCourseEditSession(ores.getResourceableId())); CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_NODE_COPIED, getClass()); fireEvent(ureq, Event.DONE_EVENT); } else { // move only if (insertParent.getIdent().equals(moveCopyFrom.getParent().getIdent())) { // same parent, adjust insertPos if (insertPos > moveCopyFrom.getPosition()) insertPos--; } insertParent.insert(moveCopyFrom, insertPos); moveCopyFrom.setDirty(true); // mark subtree as dirty TreeVisitor tv = new TreeVisitor( new Visitor() { @Override public void visit(INode node) { CourseEditorTreeNode cetn = (CourseEditorTreeNode) node; cetn.setDirty(true); } }, moveCopyFrom, true); tv.visitAll(); CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); showInfo("movecopynode.info.condmoved"); ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_NODE_MOVED, getClass()); fireEvent(ureq, Event.DONE_EVENT); } }
protected void showExportFinished() { ICourse course = CourseFactory.loadCourse(ores); VelocityContainer vcFeedback = createVelocityContainer("courselogs_feedback"); showFileButton = LinkFactory.createButton("showfile", vcFeedback, this); vcFeedback.contextPut("body", translate("course.logs.feedback", course.getCourseTitle())); myPanel.setContent(vcFeedback); // note: polling can't be switched off unfortunatelly // this is due to the fact that the jsandcsscomponent can only modify // certain parts of the page and it would require a full page refresh // to get rid of the poller - and that's not possible currently showInfo("course.logs.finished", course.getCourseTitle()); }
/** * Constructor for the course logs archive controller * * @param ureq * @param wControl * @param course */ public CourseLogsArchiveController( UserRequest ureq, WindowControl wControl, OLATResourceable ores) { super(ureq, wControl); this.ores = ores; this.myPanel = new Panel("myPanel"); myPanel.addListener(this); myContent = createVelocityContainer("start_courselogs"); Identity identity = ureq.getIdentity(); Roles roles = ureq.getUserSession().getRoles(); RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(ores, false); boolean isOLATAdmin = ureq.getUserSession().getRoles().isOLATAdmin(); boolean isOresOwner = RepositoryManager.getInstance().isOwnerOfRepositoryEntry(identity, re); boolean isOresInstitutionalManager = RepositoryManager.getInstance().isInstitutionalRessourceManagerFor(identity, roles, re); boolean aLogV = isOresOwner || isOresInstitutionalManager; boolean uLogV = isOLATAdmin; boolean sLogV = isOresOwner || isOresInstitutionalManager; if (AsyncExportManager.getInstance().asyncArchiveCourseLogOngoingFor(ureq.getIdentity())) { // then show the ongoing feedback showExportOngoing(false); } else if (isOLATAdmin || aLogV || uLogV || sLogV) { myContent.contextPut("hasLogArchiveAccess", true); logFileChooserForm = new LogFileChooserForm(ureq, wControl, isOLATAdmin, aLogV, uLogV, sLogV); listenTo(logFileChooserForm); myContent.put("logfilechooserform", logFileChooserForm.getInitialComponent()); ICourse course = CourseFactory.loadCourse(ores); myContent.contextPut( "body", translate("course.logs.existingarchiveintro", course.getCourseTitle())); showFileButton = LinkFactory.createButton("showfile", myContent, this); File exportDir = CourseFactory.getDataExportDirectory(ureq.getIdentity(), course.getCourseTitle()); boolean exportDirExists = false; if (exportDir != null && exportDir.exists() && exportDir.isDirectory()) { exportDirExists = true; } myContent.contextPut("hascourselogarchive", new Boolean(exportDirExists)); myPanel.setContent(myContent); } else { myContent.contextPut("hasLogArchiveAccess", new Boolean(false)); myPanel.setContent(myContent); } putInitialPanel(myPanel); }
private void sendFeedback(List<BulkAssessmentFeedback> feedbacks) { if (task == null) { log.error("Haven't a task to know creator and modifiers of the task", null); return; } Identity creator = task.getCreator(); String language = creator.getUser().getPreferences().getLanguage(); Locale locale = I18nManager.getInstance().getLocaleOrDefault(language); Translator translator = Util.createPackageTranslator( BulkAssessmentOverviewController.class, locale, Util.createPackageTranslator(AssessmentManager.class, locale)); MailManager mailManager = CoreSpringFactory.getImpl(MailManager.class); TaskExecutorManager taskManager = CoreSpringFactory.getImpl(TaskExecutorManager.class); String feedbackStr = renderFeedback(feedbacks, translator); MailBundle mail = new MailBundle(); mail.setToId(creator); mail.setFrom(WebappHelper.getMailConfig("mailReplyTo")); List<Identity> modifiers = taskManager.getModifiers(task); if (modifiers.size() > 0) { ContactList cc = new ContactList("CC"); cc.addAllIdentites(modifiers); mail.setContactList(cc); } String businessPath = ""; ICourse course = CourseFactory.loadCourse(courseRes); CourseNode node = course.getRunStructure().getNode(courseNodeIdent); String courseTitle = course.getCourseTitle(); String nodeTitle = node.getShortTitle(); String numOfAssessedIds = Integer.toString(datas == null ? 0 : datas.getRowsSize()); String date = Formatter.getInstance(locale).formatDateAndTime(new Date()); mail.setContext(new MailContextImpl(courseRes, courseNodeIdent, businessPath)); String subject = translator.translate("confirmation.mail.subject", new String[] {courseTitle, nodeTitle}); String body = translator.translate( "confirmation.mail.body", new String[] {courseTitle, nodeTitle, feedbackStr, numOfAssessedIds, date}); mail.setContent(subject, body); mailManager.sendMessage(mail); }
/** * @see org.olat.course.nodes.CourseNode#createEditController(org.olat.core.gui.UserRequest, * org.olat.core.gui.control.WindowControl, org.olat.course.ICourse) */ @Override public TabbableController createEditController( UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course, UserCourseEnvironment euce) { updateModuleConfigDefaults(false); CPEditController childTabCntrllr = new CPEditController(this, ureq, wControl, stackPanel, course, euce); CourseNode chosenNode = course .getEditorTreeModel() .getCourseNode(euce.getCourseEditorEnv().getCurrentCourseNodeId()); return new NodeEditController( ureq, wControl, course.getEditorTreeModel(), course, chosenNode, euce, childTabCntrllr); }
public MoveCopySubtreeController( UserRequest ureq, WindowControl wControl, OLATResourceable ores, CourseEditorTreeNode moveCopyFrom, boolean copy) { super(ureq, wControl); this.ores = ores; this.moveCopyFrom = moveCopyFrom; this.copy = copy; ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId()); addLoggingResourceable(LoggingResourceable.wrap(course)); addLoggingResourceable(LoggingResourceable.wrap(moveCopyFrom.getCourseNode())); insertTree = new MenuTree(null, "copy_node_selection", this); insertTree.enableInsertTool(true); insertModel = new InsertTreeModel(course.getEditorTreeModel().getRootNode(), moveCopyFrom); insertTree.setTreeModel(insertModel); VelocityContainer mainVC = createVelocityContainer("moveCopyNode"); selectButton = LinkFactory.createButton("insertAtSelectedTreepos", mainVC, this); selectButton.setCustomEnabledLinkCSS("btn btn-primary"); selectButton.setCustomDisabledLinkCSS("btn btn-default"); selectButton.setEnabled(false); cancelButton = LinkFactory.createButton("cancel", mainVC, this); int numOfNodes = TreeHelper.totalNodeCount(insertModel.getRootNode()); if (numOfNodes > CourseModule.getCourseNodeLimit()) { String msg = getTranslator() .translate( "warning.containsXXXormore.nodes", new String[] { String.valueOf(numOfNodes), String.valueOf(CourseModule.getCourseNodeLimit() + 1) }); Controller tmp = MessageUIFactory.createWarnMessage(ureq, wControl, null, msg); listenTo(tmp); mainVC.put("nodelimitexceededwarning", tmp.getInitialComponent()); } mainVC.put("selection", insertTree); putInitialPanel(mainVC); }
@Override public void cleanupOnDelete(final ICourse course) { // mark the subscription to this node as deleted final SubscriptionContext subsContext = WikiManager.createTechnicalSubscriptionContextForCourse( course.getCourseEnvironment(), this); NotificationsManager.getInstance().delete(subsContext); }
/** * Retrieves the groups where the enrollment happens * * @response.representation.200.qname {http://www.example.com}groupVO * @response.representation.200.mediaType application/xml, application/json * @response.representation.200.doc The groups * @response.representation.200.example {@link * org.olat.restapi.support.vo.Examples#SAMPLE_GROUPVO} * @response.representation.401.doc The roles of the authenticated user are not sufficient * @response.representation.404.doc The course or course node not found * @param nodeId The node's id * @param httpRequest The HTTP request * @return An array of groups */ @GET @Path("{nodeId}/groups") @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Response getGroups( @PathParam("courseId") Long courseId, @PathParam("nodeId") String nodeId, @Context HttpServletRequest httpRequest) { if (!isAuthor(httpRequest)) { return Response.serverError().status(Status.UNAUTHORIZED).build(); } ICourse course = CoursesWebService.loadCourse(courseId); if (course == null) { return Response.serverError().status(Status.NOT_FOUND).build(); } else if (!isAuthorEditor(course, httpRequest)) { return Response.serverError().status(Status.UNAUTHORIZED).build(); } BusinessGroupService bgs = CoreSpringFactory.getImpl(BusinessGroupService.class); CourseNode node = getParentNode(course, nodeId); ModuleConfiguration config = node.getModuleConfiguration(); String groupNames = (String) config.get(ENCourseNode.CONFIG_GROUPNAME); @SuppressWarnings("unchecked") List<Long> groupKeys = (List<Long>) config.get(ENCourseNode.CONFIG_GROUP_IDS); if (groupKeys == null && StringHelper.containsNonWhitespace(groupNames)) { groupKeys = bgs.toGroupKeys( groupNames, course.getCourseEnvironment().getCourseGroupManager().getCourseEntry()); } if (groupKeys == null || groupKeys.isEmpty()) { return Response.ok(new GroupVO[0]).build(); } List<GroupVO> voes = new ArrayList<GroupVO>(); List<BusinessGroup> groups = bgs.loadBusinessGroups(groupKeys); for (BusinessGroup group : groups) { voes.add(get(group)); } GroupVO[] voArr = new GroupVO[voes.size()]; voes.toArray(voArr); return Response.ok(voArr).build(); }
/** * Constructor for tunneling editor controller * * @param config The node module configuration * @param ureq The user request * @param wControl The window controller * @param tuCourseNode The current single page course node * @param course */ public LTIEditController( final ModuleConfiguration config, final UserRequest ureq, final WindowControl wControl, final BasicLTICourseNode ltCourseNode, final ICourse course, final UserCourseEnvironment euce) { super(ureq, wControl); this.config = config; this.courseNode = ltCourseNode; this.editCourseEnv = course.getCourseEnvironment(); myContent = this.createVelocityContainer("edit"); previewButton = LinkFactory.createButtonSmall("command.preview", myContent, this); ltConfigForm = new LTIConfigForm(ureq, wControl, config); listenTo(ltConfigForm); myContent.put("ltConfigForm", ltConfigForm.getInitialComponent()); final CourseGroupManager groupMgr = course.getCourseEnvironment().getCourseGroupManager(); final CourseEditorTreeModel editorModel = course.getEditorTreeModel(); // Accessibility precondition final Condition accessCondition = courseNode.getPreConditionAccess(); accessibilityCondContr = new ConditionEditController( ureq, getWindowControl(), groupMgr, accessCondition, "accessabilityConditionForm", AssessmentHelper.getAssessableNodes(editorModel, ltCourseNode), euce); this.listenTo(accessibilityCondContr); // Enable preview button only if node configuration is valid if (!(ltCourseNode.isConfigValid().isError())) { myContent.contextPut("showPreviewButton", Boolean.TRUE); } else { myContent.contextPut("showPreviewButton", Boolean.FALSE); } }
/** * Utility method.<br> * Build (recursively) the list of all test nodes belonging to the specified <code>ICourse</code>. * <br> * The returned <code>List</code> is empty if course has no AssessableCourseNode. Structure course * node are excluded from the list.<br> * <br> * <b>PRE CONDITIONS</b> * * <ul> * <li><code>course != null</code> * </ul> * * <br> * <b>POST CONDITIONS</b> * * <ul> * <li>The returned list, if not empty, contains ONLY instances of type <code> * AssessableCourseNode</code> * </ul> */ private List<AssessableCourseNode> getCourseTestNodes(ICourse course) { List<AssessableCourseNode> assessableNodes = new ArrayList<AssessableCourseNode>(); Structure courseStruct = course.getRunStructure(); CourseNode rootNode = courseStruct.getRootNode(); getCourseTestNodes(rootNode, assessableNodes); return assessableNodes; }
/** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, * org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ public void event(UserRequest ureq, Component source, Event event) { if (source == showFileButton) { ICourse course = CourseFactory.loadCourse(ores); String personalFolderDir = CourseFactory.getPersonalDirectory(ureq.getIdentity()).getPath(); String targetDir = CourseFactory.getOrCreateDataExportDirectory(ureq.getIdentity(), course.getCourseTitle()) .getPath(); String relPath = ""; if (targetDir.startsWith(personalFolderDir)) { // that should always be the case relPath = targetDir.substring(personalFolderDir.length()).replace("\\", "/"); targetDir = targetDir.substring(0, personalFolderDir.length()); } VFSContainer targetFolder = new LocalFolderImpl(new File(targetDir)); FolderRunController bcrun = new FolderRunController(targetFolder, true, ureq, getWindowControl()); Component folderComponent = bcrun.getInitialComponent(); if (relPath.length() != 0) { if (!relPath.endsWith("/")) { relPath = relPath + "/"; } bcrun.activatePath(ureq, relPath); } String personalFolder = Util.createPackageTranslator(HomeMainController.class, ureq.getLocale(), null) .translate("menu.bc"); removeAsListenerAndDispose(cmc); cmc = new CloseableModalController( getWindowControl(), translate("close"), folderComponent, true, personalFolder); listenTo(cmc); cmc.activate(); } }
private void create(MultipleSelectionElement selection, ICourse course, CourseNode parentNode) { SelectNodeObject node = (SelectNodeObject) selection.getUserObject(); if (selection.isMultiselect() && selection.isSelected(0)) { VFSItem item = node.getItem(); CourseNode newNode = null; if (item instanceof VFSLeaf) { // create node newNode = createCourseNode(item, "sp"); ModuleConfiguration moduleConfig = newNode.getModuleConfiguration(); String path = getRelativePath(item); moduleConfig.set(SPEditController.CONFIG_KEY_FILE, path); moduleConfig.setBooleanEntry(SPEditController.CONFIG_KEY_ALLOW_RELATIVE_LINKS, true); } else if (item instanceof VFSContainer) { // add structure newNode = createCourseNode(item, "st"); } int pos = -1; if (position >= 0 && selectedNode.getCourseNode().getIdent().equals(parentNode.getIdent())) { pos = position++; } if (pos < 0 || pos >= parentNode.getChildCount()) { course.getEditorTreeModel().addCourseNode(newNode, parentNode); } else { course.getEditorTreeModel().insertCourseNodeAt(newNode, parentNode, pos); } if (item instanceof VFSContainer) { parentNode = newNode; } } // recurse for (MultipleSelectionElement childElement : node.getChildren()) { create(childElement, course, parentNode); } }
/** * @see org.olat.course.nodes.CourseNode#createEditController(org.olat.core.gui.UserRequest, * org.olat.core.gui.control.WindowControl, org.olat.course.ICourse) */ @Override public TabbableController createEditController( final UserRequest ureq, final WindowControl wControl, final ICourse course, final UserCourseEnvironment euce) { final MSCourseNodeEditController childTabCntrllr = new MSCourseNodeEditController(ureq, wControl, this, course, euce); final CourseNode chosenNode = course .getEditorTreeModel() .getCourseNode(euce.getCourseEditorEnv().getCurrentCourseNodeId()); return new NodeEditController( ureq, wControl, course.getEditorTreeModel(), course, chosenNode, course.getCourseEnvironment().getCourseGroupManager(), euce, childTabCntrllr); }
public static ProjectBrokerCourseEditorController createCourseEditController( final UserRequest ureq, final WindowControl wControl, final ICourse course, final UserCourseEnvironment euce, final ProjectBrokerCourseNode projectBrokerCourseNode) { return new ProjectBrokerCourseEditorController( ureq, wControl, course, projectBrokerCourseNode, course.getCourseEnvironment().getCourseGroupManager(), euce); }
private void recursiveCopy( CourseEditorTreeNode copyFrom2, CourseEditorTreeNode insertParent, int pos, boolean firstIteration, ICourse course) { // create copy of course node CourseNode copyOfNode = copyFrom2.getCourseNode().createInstanceForCopy(firstIteration, course, getIdentity()); copyNodeId = copyOfNode.getIdent(); // Insert at desired position course.getEditorTreeModel().insertCourseNodeAt(copyOfNode, insertParent.getCourseNode(), pos); CourseEditorTreeNode insertedEditorTreeNode = course.getEditorTreeModel().getCourseEditorNodeById(copyOfNode.getIdent()); for (int i = 0; i < copyFrom2.getChildCount(); i++) { recursiveCopy( course.getEditorTreeModel().getCourseEditorNodeById(copyFrom2.getChildAt(i).getIdent()), insertedEditorTreeNode, i, false, course); } }
/** * Assessment notification rights check.<br> * Tests if an <code>Identity</code> can subscribe for assessment notification for the specified * <code>ICourse</code>.<br> * <br> * <b>PRE CONDITIONS</b> * * <ul> * <li><code>course != null</code> * </ul> * * @param ident the identity to check rights for. Can be <code>null</code> * @param course the course to check rights against * @return if <code>ident == null</code> this method always returns false; otherwise subscriptions * rights are met only by course administrators and course coaches */ private boolean canSubscribeForAssessmentNotification(Identity ident, ICourse course) { if (ident == null) return false; CourseGroupManager grpMan = course.getCourseEnvironment().getCourseGroupManager(); boolean isInstitutionalResourceManager = BaseSecurityManager.getInstance() .isIdentityInSecurityGroup( ident, BaseSecurityManager.getInstance() .findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER)); return isInstitutionalResourceManager || grpMan.isIdentityCourseAdministrator(ident) || grpMan.isIdentityCourseCoach(ident) || grpMan.hasRight(ident, CourseRights.RIGHT_ASSESSMENT); }
/** @return True if all results are the same */ private ModelInfos loadModel() { // load participants, load datas ICourse course = CourseFactory.loadCourse(courseEnv.getCourseResourceableId()); List<Identity> identities = businessGroupService.getMembers(assessedGroup, GroupRoles.participant.name()); Map<Identity, AssessmentEntry> identityToEntryMap = new HashMap<>(); List<AssessmentEntry> entries = course .getCourseEnvironment() .getAssessmentManager() .getAssessmentEntries(assessedGroup, gtaNode); for (AssessmentEntry entry : entries) { identityToEntryMap.put(entry.getIdentity(), entry); } int count = 0; boolean same = true; StringBuilder duplicateWarning = new StringBuilder(); Float scoreRef = null; Boolean passedRef = null; String commentRef = null; List<AssessmentRow> rows = new ArrayList<>(identities.size()); for (Identity identity : identities) { AssessmentEntry entry = identityToEntryMap.get(identity); ScoreEvaluation scoreEval = null; if (withScore || withPassed) { scoreEval = gtaNode.getUserScoreEvaluation(entry); if (scoreEval == null) { scoreEval = ScoreEvaluation.EMPTY_EVALUATION; } } String comment = null; if (withComment && entry != null) { comment = entry.getComment(); } boolean duplicate = duplicateMemberKeys.contains(identity.getKey()); if (duplicate) { if (duplicateWarning.length() > 0) duplicateWarning.append(", "); duplicateWarning.append(StringHelper.escapeHtml(userManager.getUserDisplayName(identity))); } AssessmentRow row = new AssessmentRow(identity, duplicate); rows.add(row); if (withScore) { Float score = scoreEval.getScore(); String pointVal = AssessmentHelper.getRoundedScore(score); TextElement pointEl = uifactory.addTextElement("point" + count, null, 5, pointVal, flc); pointEl.setDisplaySize(5); row.setScoreEl(pointEl); if (count == 0) { scoreRef = score; } else if (!same(scoreRef, score)) { same = false; } } if (withPassed && cutValue == null) { Boolean passed = scoreEval.getPassed(); MultipleSelectionElement passedEl = uifactory.addCheckboxesHorizontal("check" + count, null, flc, onKeys, onValues); if (passed != null && passed.booleanValue()) { passedEl.select(onKeys[0], passed.booleanValue()); } row.setPassedEl(passedEl); if (count == 0) { passedRef = passed; } else if (!same(passedRef, passed)) { same = false; } } if (withComment) { FormLink commentLink = uifactory.addFormLink( "comment-" + CodeHelper.getRAMUniqueID(), "comment", "comment", null, flc, Link.LINK); if (StringHelper.containsNonWhitespace(comment)) { commentLink.setIconLeftCSS("o_icon o_icon_comments"); } else { commentLink.setIconLeftCSS("o_icon o_icon_comments_none"); } commentLink.setUserObject(row); row.setComment(comment); row.setCommentEditLink(commentLink); if (count == 0) { commentRef = comment; } else if (!same(commentRef, comment)) { same = false; } } count++; } model.setObjects(rows); table.reset(); return new ModelInfos(same, scoreRef, passedRef, commentRef, duplicateWarning.toString()); }
@Test public void assignTask_relativeToInitialLaunchDate() { // create a course with 3 members Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("initial-launch-1"); Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("initial-launch-2"); Identity id3 = JunitTestHelper.createAndPersistIdentityAsRndUser("initial-launch-3"); ICourse course = CoursesWebService.createEmptyCourse(null, "initial-launch-dates", "course long name", null); RepositoryEntry re = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); repositoryEntryRelationDao.addRole(id1, re, GroupRoles.participant.name()); repositoryEntryRelationDao.addRole(id2, re, GroupRoles.participant.name()); repositoryEntryRelationDao.addRole(id3, re, GroupRoles.participant.name()); dbInstance.commit(); // create user course infos Long courseResId = course.getCourseEnvironment().getCourseResourceableId(); userCourseInformationsManager.updateUserCourseInformations(re.getOlatResource(), id1); userCourseInformationsManager.updateUserCourseInformations(re.getOlatResource(), id2); userCourseInformationsManager.updateUserCourseInformations(re.getOlatResource(), id3); dbInstance.commit(); // fake the date updateInitialLaunchDate(courseResId, id1, -5, Calendar.DATE); updateInitialLaunchDate(courseResId, id2, -35, Calendar.DATE); updateInitialLaunchDate(courseResId, id3, -75, Calendar.DATE); dbInstance.commitAndCloseSession(); // create a fake node GTACourseNode node = new GTACourseNode(); node.getModuleConfiguration() .setStringValue(GTACourseNode.GTASK_TYPE, GTAType.individual.name()); node.getModuleConfiguration().setBooleanEntry(GTACourseNode.GTASK_RELATIVE_DATES, true); node.getModuleConfiguration().setIntValue(GTACourseNode.GTASK_ASSIGNMENT_DEADLINE_RELATIVE, 40); node.getModuleConfiguration() .setStringValue( GTACourseNode.GTASK_ASSIGNMENT_DEADLINE_RELATIVE_TO, GTARelativeToDates.courseLaunch.name()); // need the task list TaskList tasks = gtaManager.createIfNotExists(re, node); Assert.assertNotNull(tasks); dbInstance.commit(); { // check 3 days ReminderRuleImpl rule = getAssignedTaskRules(3, LaunchUnit.day); List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); Assert.assertEquals(1, all.size()); Assert.assertTrue(all.contains(id3)); } { // check 5 days ReminderRuleImpl rule = getAssignedTaskRules(5, LaunchUnit.day); List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); Assert.assertEquals(2, all.size()); Assert.assertTrue(all.contains(id2)); Assert.assertTrue(all.contains(id3)); } { // check 1 week ReminderRuleImpl rule = getAssignedTaskRules(1, LaunchUnit.week); List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); Assert.assertEquals(2, all.size()); Assert.assertTrue(all.contains(id2)); Assert.assertTrue(all.contains(id3)); } { // check 1 month ReminderRuleImpl rule = getAssignedTaskRules(1, LaunchUnit.month); List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); Assert.assertEquals(2, all.size()); Assert.assertTrue(all.contains(id2)); Assert.assertTrue(all.contains(id3)); } { // check 2 month ReminderRuleImpl rule = getAssignedTaskRules(2, LaunchUnit.month); List<Identity> all = assignTaskRuleSPI.evaluateRule(re, node, rule); Assert.assertEquals(3, all.size()); Assert.assertTrue(all.contains(id1)); Assert.assertTrue(all.contains(id2)); Assert.assertTrue(all.contains(id3)); } }
private void doProcess(List<BulkAssessmentFeedback> feedbacks) { final DB dbInstance = DBFactory.getInstance(); final BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class); final Identity coachIdentity = securityManager.loadIdentityByKey(coachedIdentity); final ICourse course = CourseFactory.loadCourse(courseRes); final AssessableCourseNode courseNode = getCourseNode(); final Roles studentRoles = new Roles(false, false, false, false, false, false, false, false); final boolean hasUserComment = courseNode.hasCommentConfigured(); final boolean hasScore = courseNode.hasScoreConfigured(); final boolean hasPassed = courseNode.hasPassedConfigured(); final boolean hasReturnFiles = (StringHelper.containsNonWhitespace(datas.getReturnFiles()) && (courseNode instanceof TACourseNode || courseNode instanceof GTACourseNode)); if (hasReturnFiles) { try { OlatRootFileImpl returnFilesZipped = new OlatRootFileImpl(datas.getReturnFiles(), null); String tmp = FolderConfig.getCanonicalTmpDir(); unzipped = new File(tmp, UUID.randomUUID().toString() + File.separatorChar); unzipped.mkdirs(); ZipUtil.unzip(returnFilesZipped.getBasefile(), unzipped); } catch (Exception e) { log.error("Cannot unzip the return files during bulk assessment", e); } } Float min = null; Float max = null; Float cut = null; if (hasScore) { min = courseNode.getMinScoreConfiguration(); max = courseNode.getMaxScoreConfiguration(); } if (hasPassed) { cut = courseNode.getCutValueConfiguration(); } int count = 0; List<BulkAssessmentRow> rows = datas.getRows(); for (BulkAssessmentRow row : rows) { Long identityKey = row.getIdentityKey(); if (identityKey == null) { feedbacks.add(new BulkAssessmentFeedback("bulk.action.no.such.user", row.getAssessedId())); continue; // nothing to do } Identity identity = securityManager.loadIdentityByKey(identityKey); IdentityEnvironment ienv = new IdentityEnvironment(identity, studentRoles); UserCourseEnvironment uce = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment()); // update comment, empty string will reset comment String userComment = row.getComment(); if (hasUserComment && userComment != null) { // Update userComment in db courseNode.updateUserUserComment(userComment, uce, coachIdentity); // LD: why do we have to update the efficiency statement? // EfficiencyStatementManager esm = EfficiencyStatementManager.getInstance(); // esm.updateUserEfficiencyStatement(uce); } // update score Float score = row.getScore(); if (hasScore && score != null) { // score < minimum score if ((min != null && score.floatValue() < min.floatValue()) || (score.floatValue() < AssessmentHelper.MIN_SCORE_SUPPORTED)) { // "bulk.action.lessThanMin"; } // score > maximum score else if ((max != null && score.floatValue() > max.floatValue()) || (score.floatValue() > AssessmentHelper.MAX_SCORE_SUPPORTED)) { // "bulk.action.greaterThanMax"; } else { // score between minimum and maximum score ScoreEvaluation se; if (hasPassed && cut != null) { Boolean passed = (score.floatValue() >= cut.floatValue()) ? Boolean.TRUE : Boolean.FALSE; se = new ScoreEvaluation(score, passed); } else { se = new ScoreEvaluation(score, null); } // Update score,passed properties in db, and the user's efficiency statement courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, false); } } Boolean passed = row.getPassed(); if (hasPassed && passed != null && cut == null) { // Configuration of manual assessment --> Display passed/not passed: yes, // Type of display: Manual by tutor ScoreEvaluation seOld = courseNode.getUserScoreEvaluation(uce); Float oldScore = seOld.getScore(); ScoreEvaluation se = new ScoreEvaluation(oldScore, passed); // Update score,passed properties in db, and the user's efficiency statement boolean incrementAttempts = false; courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, incrementAttempts); } boolean identityHasReturnFile = false; if (hasReturnFiles && row.getReturnFiles() != null && row.getReturnFiles().size() > 0) { String assessedId = row.getAssessedId(); File assessedFolder = new File(unzipped, assessedId); identityHasReturnFile = assessedFolder.exists(); if (identityHasReturnFile) { processReturnFile(courseNode, row, uce, assessedFolder); } } if (courseNode instanceof GTACourseNode) { // push the state further GTACourseNode gtaNode = (GTACourseNode) courseNode; if ((hasScore && score != null) || (hasPassed && passed != null)) { // pushed to graded updateTasksState(gtaNode, uce, TaskProcess.grading); } else if (hasReturnFiles) { // push to revised updateTasksState(gtaNode, uce, TaskProcess.correction); } } if (count++ % 5 == 0) { dbInstance.commitAndCloseSession(); } else { dbInstance.commit(); } } }
/** @see org.olat.course.nodes.CourseNode#cleanupOnDelete(org.olat.course.ICourse) */ @Override public void cleanupOnDelete(final ICourse course) { final CoursePropertyManager pm = course.getCourseEnvironment().getCoursePropertyManager(); // Delete all properties: score, passed, log, comment, coach_comment pm.deleteNodeProperties(this, null); }
/** * Return <code>PublisherData</code> instance to use for assessment notification.<br> * <br> * <b>PRE CONDITIONS</b> * * <ul> * <li><code>course != null</code> * </ul> * * @param course * @param the business path * @return the publisherdata */ public PublisherData getAssessmentPublisherData(ICourse course, String businessPath) { return new PublisherData( CourseModule.ORES_COURSE_ASSESSMENT, String.valueOf(course.getCourseEnvironment().getCourseResourceableId()), businessPath); }
/** * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, * org.olat.core.gui.components.Component, org.olat.core.gui.control.Event) */ public void event(UserRequest ureq, Component source, Event event) { if (source == startButton && startButton.isEnabled() && startButton.isVisible()) { long courseResId = userCourseEnv.getCourseEnvironment().getCourseResourceableId().longValue(); String courseNodeIdent = courseNode.getIdent(); removeAsListenerAndDispose(displayController); OLATResourceable ores = OresHelper.createOLATResourceableTypeWithoutCheck("test"); ThreadLocalUserActivityLogger.addLoggingResourceInfo( LoggingResourceable.wrapBusinessPath(ores)); WindowControl bwControl = addToHistory(ureq, ores, null); Controller returnController = iqManager.createIQDisplayController( modConfig, secCallback, ureq, bwControl, courseResId, courseNodeIdent, this); /* * either returnController is a MessageController or it is a IQDisplayController * this should not serve as pattern to be copy&pasted. * FIXME:2008-11-21:pb INTRODUCED because of read/write QTI Lock solution for scalability II, 6.1.x Release */ if (returnController instanceof IQDisplayController) { displayController = (IQDisplayController) returnController; listenTo(displayController); if (displayController.isClosed()) { // do nothing } else if (displayController.isReady()) { // in case displayController was unable to initialize, a message was set by // displayController // this is the case if no more attempts or security check was unsuccessfull displayContainerController = new LayoutMain3ColsController(ureq, getWindowControl(), displayController); listenTo(displayContainerController); // autodispose // need to wrap a course restart controller again, because IQDisplay // runs on top of GUIStack ICourse course = CourseFactory.loadCourse(courseResId); RepositoryEntry courseRepositoryEntry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); Panel empty = new Panel("empty"); // empty panel set as "menu" and "tool" Controller courseCloser = new DisposedCourseRestartController(ureq, getWindowControl(), courseRepositoryEntry); Controller disposedRestartController = new LayoutMain3ColsController( ureq, getWindowControl(), empty, courseCloser.getInitialComponent(), "disposed course whily in iqRun" + courseResId); displayContainerController.setDisposedMessageController(disposedRestartController); final boolean fullWindow = modConfig.getBooleanSafe(IQEditController.CONFIG_FULLWINDOW, true); if (fullWindow) { displayContainerController.setAsFullscreen(ureq); } displayContainerController.activate(); if (modConfig .get(IQEditController.CONFIG_KEY_TYPE) .equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS)) { assessmentStopped = false; singleUserEventCenter.registerFor(this, getIdentity(), assessmentInstanceOres); singleUserEventCenter.fireEventToListenersOf( new AssessmentEvent(AssessmentEvent.TYPE.STARTED, ureq.getUserSession()), assessmentEventOres); } } // endif isReady } else { // -> qti file was locked -> show info message // user must click again on course node to activate mainPanel.pushContent(returnController.getInitialComponent()); } } else if (source == showResultsButton) { AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager(); Long assessmentID = am.getAssessmentID(courseNode, ureq.getIdentity()); if (assessmentID == null) { // fallback solution: if the assessmentID is not available via AssessmentManager than try to // get it via IQManager long callingResId = userCourseEnv.getCourseEnvironment().getCourseResourceableId().longValue(); String callingResDetail = courseNode.getIdent(); assessmentID = iqManager.getLastAssessmentID(ureq.getIdentity(), callingResId, callingResDetail); } if (assessmentID != null && !assessmentID.equals("")) { Document doc = iqManager.getResultsReportingFromFile(ureq.getIdentity(), type, assessmentID); // StringBuilder resultsHTML = // LocalizedXSLTransformer.getInstance(ureq.getLocale()).renderResults(doc); String summaryConfig = (String) modConfig.get(IQEditController.CONFIG_KEY_SUMMARY); int summaryType = AssessmentInstance.getSummaryType(summaryConfig); String resultsHTML = iqManager.transformResultsReporting(doc, ureq.getLocale(), summaryType); myContent.contextPut("displayreporting", resultsHTML); myContent.contextPut("resreporting", resultsHTML); myContent.contextPut("showResults", Boolean.TRUE); } } else if (source == hideResultsButton) { myContent.contextPut("showResults", Boolean.FALSE); } }
/** * @see * org.olat.core.commons.services.notifications.NotificationsHandler#createSubscriptionInfo(org.olat.core.commons.services.notifications.Subscriber, * java.util.Locale, java.util.Date) */ public SubscriptionInfo createSubscriptionInfo( final Subscriber subscriber, Locale locale, Date compareDate) { SubscriptionInfo si = null; Publisher p = subscriber.getPublisher(); if (!NotificationsUpgradeHelper.checkCourse(p)) { // course don't exist anymore NotificationsManager.getInstance().deactivate(p); return NotificationsManager.getInstance().getNoSubscriptionInfo(); } try { Date latestNews = p.getLatestNewsDate(); Identity identity = subscriber.getIdentity(); // do not try to create a subscription info if state is deleted - results in // exceptions, course // can't be loaded when already deleted if (NotificationsManager.getInstance().isPublisherValid(p) && compareDate.before(latestNews)) { Long courseId = new Long(p.getData()); final ICourse course = loadCourseFromId(courseId); if (course != null) { // course admins or users with the course right to have full access to // the assessment tool will have full access to user tests CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager(); final boolean hasFullAccess = (cgm.isIdentityCourseAdministrator(identity) ? true : cgm.hasRight(identity, CourseRights.RIGHT_ASSESSMENT)); final List<Identity> coachedUsers = new ArrayList<Identity>(); if (!hasFullAccess) { // initialize list of users, only when user has not full access List<BusinessGroup> coachedGroups = cgm.getOwnedBusinessGroups(identity); BusinessGroupService businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class); List<Identity> coachedIdentites = businessGroupService.getMembers(coachedGroups, GroupRoles.participant.name()); coachedUsers.addAll(coachedIdentites); } List<AssessableCourseNode> testNodes = getCourseTestNodes(course); Translator translator = Util.createPackageTranslator(AssessmentNotificationsHandler.class, locale); for (AssessableCourseNode test : testNodes) { final CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager(); List<Property> scoreProperties = cpm.listCourseNodeProperties(test, null, null, AssessmentManager.SCORE); List<Property> attemptProperties = cpm.listCourseNodeProperties(test, null, null, AssessmentManager.ATTEMPTS); for (Property attemptProperty : attemptProperties) { Date modDate = attemptProperty.getLastModified(); Identity assessedIdentity = attemptProperty.getIdentity(); if (modDate.after(compareDate) && (hasFullAccess || PersistenceHelper.listContainsObjectByKey( coachedUsers, assessedIdentity))) { String score = null; for (Property scoreProperty : scoreProperties) { if (scoreProperty.getIdentity().equalsByPersistableKey(assessedIdentity)) { score = scoreProperty.getFloatValue().toString(); break; } } if (test instanceof ScormCourseNode) { ScormCourseNode scormTest = (ScormCourseNode) test; // check if completed or passed String status = ScormAssessmentManager.getInstance() .getLastLessonStatus( assessedIdentity.getName(), course.getCourseEnvironment(), scormTest); if (!"passed".equals(status) && !"completed".equals(status)) { continue; } } String desc; String type = translator.translate("notifications.entry." + test.getType()); if (score == null) { desc = translator.translate( "notifications.entry.attempt", new String[] { test.getShortTitle(), NotificationHelper.getFormatedName(assessedIdentity), type }); } else { desc = translator.translate( "notifications.entry", new String[] { test.getShortTitle(), NotificationHelper.getFormatedName(assessedIdentity), score, type }); } String urlToSend = null; String businessPath = null; if (p.getBusinessPath() != null) { businessPath = p.getBusinessPath() + "[assessmentTool:0][Identity:" + assessedIdentity.getKey() + "][CourseNode:" + test.getIdent() + "]"; urlToSend = BusinessControlFactory.getInstance() .getURLFromBusinessPathString(businessPath); } SubscriptionListItem subListItem = new SubscriptionListItem( desc, urlToSend, businessPath, modDate, CSS_CLASS_USER_ICON); if (si == null) { String title = translator.translate( "notifications.header", new String[] {course.getCourseTitle()}); String css = CourseNodeFactory.getInstance() .getCourseNodeConfigurationEvenForDisabledBB(test.getType()) .getIconCSSClass(); si = new SubscriptionInfo( subscriber.getKey(), p.getType(), new TitleItem(title, css), null); } si.addSubscriptionListItem(subListItem); } } } } } if (si == null) { si = NotificationsManager.getInstance().getNoSubscriptionInfo(); } return si; } catch (Exception e) { log.error("Error while creating assessment notifications", e); checkPublisher(p); return NotificationsManager.getInstance().getNoSubscriptionInfo(); } }