private void cleanup() {
   if (StringHelper.containsNonWhitespace(datas.getDataBackupFile())) {
     OlatRootFileImpl backupFile = new OlatRootFileImpl(datas.getDataBackupFile(), null);
     if (backupFile.exists()) {
       File dir = backupFile.getBasefile().getParentFile();
       if (dir != null && dir.exists()) {
         FileUtils.deleteDirsAndFiles(dir, true, true);
       }
     }
   }
   cleanupUnzip();
 }
  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);
  }
  /**
   * This constructor start the edit the bulk update.
   *
   * @param ureq
   * @param courseNode
   * @param datas
   */
  public BulkAssessment_2_DatasStep(
      UserRequest ureq,
      AssessableCourseNode courseNode,
      BulkAssessmentDatas savedDatas,
      Task task) {
    super(ureq);
    this.task = task;
    this.savedDatas = savedDatas;
    this.courseNode = courseNode;
    setI18nTitleAndDescr("data.title", "data.title");
    if (savedDatas == null) {
      setNextStep(new BulkAssessment_2b_ChooseColumnsStep(ureq));
    } else {
      setNextStep(new BulkAssessment_2b_ChooseColumnsStep(ureq, savedDatas.getColumnsSettings()));
    }

    hasPreviousStep = (courseNode == null ? false : true);
  }
  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();
      }
    }
  }