/**
   * 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();
  }
Пример #3
0
 private AssessableCourseNode getCourseNode() {
   ICourse course = CourseFactory.loadCourse(courseRes);
   CourseNode node = course.getRunStructure().getNode(courseNodeIdent);
   if (node instanceof AssessableCourseNode) {
     return (AssessableCourseNode) node;
   }
   return null;
 }
Пример #4
0
  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);
  }
Пример #9
0
  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);
  }
Пример #10
0
 /**
  * @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);
  }
Пример #12
0
 @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);
 }
Пример #13
0
  /**
   * 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();
    }
  }
Пример #17
0
  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);
    }
  }
Пример #18
0
 /**
  * @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());
  }
Пример #23
0
  @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));
    }
  }
Пример #24
0
  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();
      }
    }
  }
Пример #25
0
 /** @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);
 }
Пример #27
0
  /**
   * @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();
    }
  }