Package org.olat.repository.delete.service

Source Code of org.olat.repository.delete.service.RepositoryDeletionManager

/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/

package org.olat.repository.delete.service;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.olat.admin.user.delete.service.UserDeletionManager;
import org.olat.basesecurity.ManagerFactory;
import org.olat.basesecurity.SecurityGroup;
import org.olat.commons.lifecycle.LifeCycleManager;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.commons.persistence.DBQuery;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.translator.PackageTranslator;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity;
import org.olat.core.id.UserConstants;
import org.olat.core.logging.Tracing;
import org.olat.core.util.Util;
import org.olat.core.util.i18n.I18nManager;
import org.olat.core.util.mail.MailTemplate;
import org.olat.core.util.mail.MailerResult;
import org.olat.core.util.mail.MailerWithTemplate;
import org.olat.properties.Property;
import org.olat.properties.PropertyManager;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.repository.delete.SelectionController;
import org.olat.repository.handlers.RepositoryHandler;
import org.olat.repository.handlers.RepositoryHandlerFactory;
import org.olat.resource.OLATResourceManager;
import org.olat.resource.references.ReferenceManager;
import org.olat.user.UserDataDeletable;


/**
* Initial Date:  Mar 31, 2004
*
* @author Mike Stock
*
* Comment: 
*
*/
public class RepositoryDeletionManager implements UserDataDeletable {

  private static final String REPOSITORY_ARCHIVE_DIR = "archive_deleted_resources";

  private static final String PROPERTY_CATEGORY = "RepositoryDeletion";
  private static final String LAST_USAGE_DURATION_PROPERTY_NAME = "LastUsageDuration";
  private static final int DEFAULT_LAST_USAGE_DURATION = 24;
  private static final String DELETE_EMAIL_DURATION_PROPERTY_NAME = "DeleteEmailDuration";
  private static final int DEFAULT_DELETE_EMAIL_DURATION = 30;
 
  private static RepositoryDeletionManager INSTANCE = new RepositoryDeletionManager();
  private static final String PACKAGE = Util.getPackageName(SelectionController.class);

  public static final String SEND_DELETE_EMAIL_ACTION = "sendDeleteEmail";
  private static final String REPOSITORY_DELETED_ACTION = "respositoryEntryDeleted";

  private String archiveRootDir;

  private String emailResponseTo;

  private Identity adminUserIdentity;

  private RepositoryDeletionManager() {
    // private since singleteon
    UserDeletionManager.getInstance().registerDeletableUserData(this);
  }


  /**
   * @return Singleton.
   */
  public static RepositoryDeletionManager getInstance() {
    return INSTANCE;
  }

  //////////////////
  // USER_DELETION
  //////////////////
  /**
   * Remove identity as owner and initial author. Used in user-deletion.
   * If there is no other owner and/or author, the olat-administrator (define in olat_config.xml) will be added as owner.
   *  
   * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
   */
  public void deleteUserData(Identity identity, String newDeletedUserName) {
    // Remove as owner
    List repoEntries = RepositoryManager.getInstance().queryByOwner(identity, new String[] {}/*no type limit*/);
    for (Iterator iter = repoEntries.iterator(); iter.hasNext();) {
      RepositoryEntry repositoryEntry = (RepositoryEntry) iter.next();
     
      ManagerFactory.getManager().removeIdentityFromSecurityGroup(identity, repositoryEntry.getOwnerGroup());
      if (ManagerFactory.getManager().countIdentitiesOfSecurityGroup(repositoryEntry.getOwnerGroup()) == 0 ) {
        // This group has no owner anymore => add OLAT-Admin as owner
        ManagerFactory.getManager().addIdentityToSecurityGroup(adminUserIdentity, repositoryEntry.getOwnerGroup());
        Tracing.logInfo("Delete user-data, add Administrator-identity as owner of repositoryEntry=" + repositoryEntry.getDisplayname(), this.getClass());
      }
    }
    // Remove as initial author
    repoEntries = RepositoryManager.getInstance().queryByInitialAuthor(identity.getName());
    for (Iterator iter = repoEntries.iterator(); iter.hasNext();) {
      RepositoryEntry repositoryEntry = (RepositoryEntry) iter.next();
      repositoryEntry.setInitialAuthor(adminUserIdentity.getName());
      Tracing.logInfo("Delete user-data, add Administrator-identity as initial-author of repositoryEntry=" + repositoryEntry.getDisplayname(), this.getClass());
    }
    Tracing.logDebug("All owner and initial-author entries in repository deleted for identity=" + identity, this.getClass());
  }

 
  //////////////////////
  // REPOSITORY_DELETION
  //////////////////////
  public void setLastUsageDuration(int lastUsageDuration) {
    setProperty(LAST_USAGE_DURATION_PROPERTY_NAME, lastUsageDuration);
  }

  public void setDeleteEmailDuration(int deleteEmailDuration) {
    setProperty(DELETE_EMAIL_DURATION_PROPERTY_NAME, deleteEmailDuration);
  }

  public int getLastUsageDuration() {
    return getPropertyByName(LAST_USAGE_DURATION_PROPERTY_NAME, DEFAULT_LAST_USAGE_DURATION);
  }

  public int getDeleteEmailDuration() {
    return getPropertyByName(DELETE_EMAIL_DURATION_PROPERTY_NAME, DEFAULT_DELETE_EMAIL_DURATION);
  }

  public String sendDeleteEmailTo(List selectedRepositoryEntries, MailTemplate mailTemplate, boolean isTemplateChanged, String key_email_subject,
      String key_email_body, Identity sender, Translator pT) {
    StringBuilder buf = new StringBuilder();
    if (mailTemplate != null) {
      HashMap identityRepositoryList = collectRepositoryEntriesForIdentities(selectedRepositoryEntries);
      // loop over identity list and send email
      for (Iterator iterator = identityRepositoryList.keySet().iterator(); iterator.hasNext();) {
        String result = sendEmailToIdentity((Identity) iterator.next(), identityRepositoryList, mailTemplate, isTemplateChanged, key_email_subject,
            key_email_body, sender, pT);
        if (result != null) {
          buf.append(result).append("\n");
        }
      }
    } else {
      // no template => User decides to sending no delete-email, mark only in lifecycle table 'sendEmail'
      for (Iterator iter = selectedRepositoryEntries.iterator(); iter.hasNext();) {
        RepositoryEntry repositoryEntry = (RepositoryEntry)iter.next();
        Tracing.logAudit("Repository-Deletion: Move in 'Email sent' section without sending email, repositoryEntry=" + repositoryEntry , this.getClass());
        markSendEmailEvent(repositoryEntry);
      }
    }
    return buf.toString();
  }


  /**
   * Loop over all repository-entries and collect repository-entries with the same owner identites
   * @param repositoryList
   * @return HashMap with Identity as key elements, List of RepositoryEntry as objects
   */
  private HashMap collectRepositoryEntriesForIdentities(List repositoryList) {
    HashMap identityRepositoryList = new HashMap();
    for (Iterator iter = repositoryList.iterator(); iter.hasNext();) {
      RepositoryEntry repositoryEntry = (RepositoryEntry)iter.next();
     
      // Build owner group, list of identities
      SecurityGroup ownerGroup = repositoryEntry.getOwnerGroup();
      List<Identity> ownerIdentities;
      if (ownerGroup != null) {
        ownerIdentities = ManagerFactory.getManager().getIdentitiesOfSecurityGroup(ownerGroup);
      } else {
        Tracing.logInfo("collectRepositoryEntriesForIdentities: ownerGroup is null, add adminUserIdentity as owner repositoryEntry=" + repositoryEntry.getDisplayname() + "  repositoryEntry.key=" + repositoryEntry.getKey(), this.getClass());       
        // Add admin user
        ownerIdentities = new ArrayList<Identity>();
        ownerIdentities.add(adminUserIdentity);
      }
      // Loop over owner to collect all repository-entry for each user
      for (Iterator<Identity> iterator = ownerIdentities.iterator(); iterator.hasNext();) {
        Identity identity = iterator.next();
        if (identityRepositoryList.containsKey(identity) ) {
          List repositoriesOfIdentity = (List)identityRepositoryList.get(identity);
          repositoriesOfIdentity.add(repositoryEntry);
        } else {
          List repositoriesOfIdentity = new ArrayList();
          repositoriesOfIdentity.add(repositoryEntry);
          identityRepositoryList.put(identity, repositoriesOfIdentity);
        }
      }
     
    }
    return identityRepositoryList;
  }


  private String sendEmailToIdentity(Identity identity,HashMap identityRepositoryList, MailTemplate template,
      boolean isTemplateChanged, String keyEmailSubject, String keyEmailBody, Identity sender, Translator pT) {
    MailerWithTemplate mailer = MailerWithTemplate.getInstance();
    template.addToContext("responseTo", emailResponseTo);
    if (!isTemplateChanged) {
      // Email template has NOT changed => take translated version of subject and body text
    Translator identityTranslator = new PackageTranslator(PACKAGE, I18nManager.getInstance().getLocaleOrDefault(identity.getUser().getPreferences().getLanguage()));
      template.setSubjectTemplate(identityTranslator.translate(keyEmailSubject));
      template.setBodyTemplate(identityTranslator.translate(keyEmailBody));
    }
    // loop over all repositoriesOfIdentity to build email message
    StringBuilder buf = new StringBuilder();
    for (Iterator repoIterator = ((List)identityRepositoryList.get(identity)).iterator(); repoIterator.hasNext();) {
      RepositoryEntry repositoryEntry = (RepositoryEntry) repoIterator.next();
      buf.append("\n  ").append( repositoryEntry.getDisplayname() ).append(" / ").append(trimDescription(repositoryEntry.getDescription(), 60));
    }
    template.addToContext("repositoryList", buf.toString());
    template.putVariablesInMailContext(template.getContext(), identity);
    Tracing.logDebug(" Try to send Delete-email to identity=" + identity.getName() + " with email=" + identity.getUser().getProperty(UserConstants.EMAIL, null), this.getClass());
    List<Identity> ccIdentities = new ArrayList<Identity>();
    if(template.getCpfrom()) {
      ccIdentities.add(sender);
    } else {
      ccIdentities = null
    }
    MailerResult mailerResult = mailer.sendMailUsingTemplateContext(identity, ccIdentities, null, template, sender);
    if (mailerResult.getReturnCode() == MailerResult.OK) {
      // Email sended ok => set deleteEmailDate
      for (Iterator repoIterator = ((List)identityRepositoryList.get(identity)).iterator(); repoIterator.hasNext();) {
        RepositoryEntry repositoryEntry = (RepositoryEntry) repoIterator.next();
        Tracing.logAudit("Repository-Deletion: Delete-email for repositoryEntry=" + repositoryEntry + "send to identity=" + identity.getName(), this.getClass());
        markSendEmailEvent(repositoryEntry);
      }
      return null; // Send ok => return null
    } else {
      return pT.translate("email.error.send.failed", new String[] {identity.getUser().getProperty(UserConstants.EMAIL, null), identity.getName()} );
    }
  }

  private void markSendEmailEvent(RepositoryEntry repositoryEntry) {
    repositoryEntry = (RepositoryEntry)DBFactory.getInstance().loadObject(repositoryEntry);
    LifeCycleManager.createInstanceFor(repositoryEntry).markTimestampFor(SEND_DELETE_EMAIL_ACTION);
    DBFactory.getInstance().updateObject(repositoryEntry);
  }


  private String trimDescription(String description, int maxlength) {
    if (description.length() > (maxlength) ) {
      return description.substring(0,maxlength-3) + "...";
    }
    return description;
  }


  public List getDeletableReprositoryEntries(int lastLoginDuration) {
    Calendar lastUsageLimit = Calendar.getInstance();
    lastUsageLimit.add(Calendar.MONTH, - lastLoginDuration);
    Tracing.logDebug("lastLoginLimit=" + lastUsageLimit, this.getClass());

    // 1. get all ReprositoryEntries with lastusage > x
    String query = "select re from org.olat.repository.RepositoryEntry as re "
        + " where (re.lastUsage = null or re.lastUsage < :lastUsage)"
        + " and re.olatResource != null ";
    DBQuery dbq = DBFactory.getInstance().createQuery(query);
    dbq.setDate("lastUsage", lastUsageLimit.getTime());
    List reprositoryEntries = dbq.list();
    // 2. get all ReprositoryEntries in deletion-process (email send)
    query = "select re from org.olat.repository.RepositoryEntry as re"
      + " , org.olat.commons.lifecycle.LifeCycleEntry as le"
      + " where re.key = le.persistentRef "
      + " and re.olatResource != null "
      + " and le.persistentTypeName ='" + RepositoryEntry.class.getName() + "'"
      + " and le.action ='" + SEND_DELETE_EMAIL_ACTION + "' ";
    dbq = DBFactory.getInstance().createQuery(query);
    List groupsInProcess = dbq.list();
    // 3. Remove all ReprositoryEntries in deletion-process from all unused-ReprositoryEntries
    reprositoryEntries.removeAll(groupsInProcess);
    return filterRepositoryWithReferences(reprositoryEntries);
  }


  private List filterRepositoryWithReferences(List repositoryList) {
    Tracing.logDebug("filterRepositoryWithReferences repositoryList.size=" + repositoryList.size(), this.getClass());
    List filteredList = new ArrayList();
    int loopCounter = 0;
    for (Iterator iter = repositoryList.iterator(); iter.hasNext();) {
      RepositoryEntry repositoryEntry = (RepositoryEntry) iter.next();
      Tracing.logDebug("filterRepositoryWithReferences repositoryEntry=" + repositoryEntry, this.getClass());
      Tracing.logDebug("filterRepositoryWithReferences repositoryEntry.getOlatResource()=" + repositoryEntry.getOlatResource(), this.getClass());
      if (OLATResourceManager.getInstance().findResourceable(repositoryEntry.getOlatResource()) != null) {
        if ( ReferenceManager.getInstance().getReferencesTo(repositoryEntry.getOlatResource()).size() == 0 ) {
          filteredList.add(repositoryEntry);
          Tracing.logDebug("filterRepositoryWithReferences add to filteredList repositoryEntry=" + repositoryEntry, this.getClass());
        } else {
          // repositoryEntry has references, can not be deleted
          Tracing.logDebug("filterRepositoryWithReferences Do NOT add to filteredList repositoryEntry=" + repositoryEntry, this.getClass());
          if (LifeCycleManager.createInstanceFor(repositoryEntry).lookupLifeCycleEntry(SEND_DELETE_EMAIL_ACTION) != null) {
            LifeCycleManager.createInstanceFor(repositoryEntry).deleteTimestampFor(SEND_DELETE_EMAIL_ACTION);
            Tracing.logInfo("filterRepositoryWithReferences: found repositoryEntry with references, remove from deletion-process repositoryEntry=" + repositoryEntry, this.getClass());
          }
        }
      } else {
        Tracing.logError("filterRepositoryWithReferences, could NOT found Resourceable for repositoryEntry=" + repositoryEntry, this.getClass());       
      }
      if (loopCounter++ % 100 == 0) {
        DBFactory.getInstance().intermediateCommit();
      }
    }
    Tracing.logDebug("filterRepositoryWithReferences filteredList.size=" + filteredList.size(), this.getClass());
    return filteredList;
  }

  public List getReprositoryEntriesInDeletionProcess(int deleteEmailDuration) {
    Calendar deleteEmailLimit = Calendar.getInstance();
    deleteEmailLimit.add(Calendar.DAY_OF_MONTH, - (deleteEmailDuration - 1));
    Tracing.logDebug("deleteEmailLimit=" + deleteEmailLimit, this.getClass());
    String queryStr = "select re from org.olat.repository.RepositoryEntry as re"
      + " , org.olat.commons.lifecycle.LifeCycleEntry as le"
      + " where re.key = le.persistentRef "
      + " and re.olatResource != null "
      + " and le.persistentTypeName ='" + RepositoryEntry.class.getName() + "'"
      + " and le.action ='" + SEND_DELETE_EMAIL_ACTION + "' and le.lcTimestamp >= :deleteEmailDate ";
    DBQuery dbq = DBFactory.getInstance().createQuery(queryStr);
    dbq.setDate("deleteEmailDate", deleteEmailLimit.getTime());
    return filterRepositoryWithReferences(dbq.list());
  }

  public List getReprositoryEntriesReadyToDelete(int deleteEmailDuration) {
    Calendar deleteEmailLimit = Calendar.getInstance();
    deleteEmailLimit.add(Calendar.DAY_OF_MONTH, - (deleteEmailDuration - 1));
    Tracing.logDebug("deleteEmailLimit=" + deleteEmailLimit, this.getClass());
    String queryStr = "select re from org.olat.repository.RepositoryEntry as re"
      + " , org.olat.commons.lifecycle.LifeCycleEntry as le"
      + " where re.key = le.persistentRef "
      + " and re.olatResource != null "
      + " and le.persistentTypeName ='" + RepositoryEntry.class.getName() + "'"
      + " and le.action ='" + SEND_DELETE_EMAIL_ACTION + "' and le.lcTimestamp < :deleteEmailDate ";
    DBQuery dbq = DBFactory.getInstance().createQuery(queryStr);
    dbq.setDate("deleteEmailDate", deleteEmailLimit.getTime());
    return filterRepositoryWithReferences(dbq.list());
  }

  public void deleteRepositoryEntries(UserRequest ureq, WindowControl wControl, List repositoryEntryList) {
    for (Iterator iter = repositoryEntryList.iterator(); iter.hasNext();) {
      RepositoryEntry repositoryEntry = (RepositoryEntry) iter.next();
      RepositoryHandler repositoryHandler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(repositoryEntry);
      File archiveDir = new File(getArchivFilePath());
      if (!archiveDir.exists()) {
        archiveDir.mkdirs();
      }
      String archiveFileName = repositoryHandler.archive(ureq.getIdentity(), getArchivFilePath(), repositoryEntry);
      Tracing.logAudit("Repository-Deletion: archived repositoryEntry=" + repositoryEntry + " , archive-file-name=" + archiveFileName, this.getClass());
      RepositoryManager.getInstance().deleteRepositoryEntryWithAllData( ureq, wControl, repositoryEntry );
      LifeCycleManager.createInstanceFor(repositoryEntry).deleteTimestampFor(SEND_DELETE_EMAIL_ACTION);
      LifeCycleManager.createInstanceFor(repositoryEntry).markTimestampFor(REPOSITORY_DELETED_ACTION, createLifeCycleLogDataFor(repositoryEntry));
      Tracing.logAudit("Repository-Deletion: deleted repositoryEntry=" + repositoryEntry, this.getClass());
      DBFactory.getInstance().intermediateCommit();
    }
  }
 
  private String createLifeCycleLogDataFor(RepositoryEntry repositoryEntry) {
    StringBuilder buf = new StringBuilder();
    buf.append("<repositoryentry>");
    buf.append("<name>").append(repositoryEntry.getDisplayname()).append("</name>");
    buf.append("<description>").append(trimDescription(repositoryEntry.getDescription(),60)).append("</description>");
    buf.append("<resid>").append(repositoryEntry.getOlatResource().getResourceableId()).append("</resid>");
    buf.append("<initialauthor>").append(repositoryEntry.getInitialAuthor()).append("</initialauthor>");
    buf.append("</repositoryentry>");
    return buf.toString();
  }

  private String getArchivFilePath() {
    return archiveRootDir + File.separator + REPOSITORY_ARCHIVE_DIR + File.separator + DeletionModule.getArchiveDatePath();
  }
   
  //////////////////
  // Private Methods
  //////////////////
  private int getPropertyByName(String name, int defaultValue) {
    List properties = PropertyManager.getInstance().findProperties(null, null, null, PROPERTY_CATEGORY, name);
    if (properties.size() == 0) {
      return defaultValue;
    } else {
      return ((Property)properties.get(0)).getLongValue().intValue();
    }
  }

  private void setProperty(String propertyName, int value) {
    List properties = PropertyManager.getInstance().findProperties(null, null, null, PROPERTY_CATEGORY, propertyName);
    Property property = null;
    if (properties.size() == 0) {
      property = PropertyManager.getInstance().createPropertyInstance(null, null, null, PROPERTY_CATEGORY, propertyName, null,  new Long(value), null, null);
    } else {
      property = (Property)properties.get(0);
      property.setLongValue( new Long(value) );
    }
    PropertyManager.getInstance().saveProperty(property);
  }


  public void init(DeletionModule module) {
    archiveRootDir = module.getArchiveRootPath();
    emailResponseTo = module.getEmailResponseTo();
    adminUserIdentity = module.getAdminUserIdentity();
  }

}
TOP

Related Classes of org.olat.repository.delete.service.RepositoryDeletionManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.