diff --git a/src/main/java/org/olat/admin/user/UserAdminController.java b/src/main/java/org/olat/admin/user/UserAdminController.java
index bd70419eb707a7b333db747390126e76de9edc6d..cca6b9f46c3d04853a577beb4a07ae932578bc19 100644
--- a/src/main/java/org/olat/admin/user/UserAdminController.java
+++ b/src/main/java/org/olat/admin/user/UserAdminController.java
@@ -35,7 +35,6 @@ import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.OrganisationRoles;
 import org.olat.basesecurity.OrganisationService;
 import org.olat.core.commons.modules.bc.FolderConfig;
-import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.commons.services.notifications.ui.NotificationSubscriptionController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -49,6 +48,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Organisation;
@@ -70,7 +70,9 @@ import org.olat.user.ChangePrefsController;
 import org.olat.user.DisplayPortraitController;
 import org.olat.user.ProfileAndHomePageEditController;
 import org.olat.user.PropFoundEvent;
+import org.olat.user.UserManager;
 import org.olat.user.UserPropertiesController;
+import org.olat.user.ui.data.UserDataExportController;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -115,15 +117,20 @@ public class UserAdminController extends BasicController implements Activateable
 	private DisplayPortraitController portraitCtr;
 	private UserAuthenticationsEditorController authenticationsCtr;
 	private Link backLink;
+	private Link exportDataButton;
 	private ProfileAndHomePageEditController userProfileCtr;
 	private CourseOverviewController courseCtr;
 	private GroupOverviewController grpCtr;
+	private CloseableModalController cmc;
+	private UserDataExportController exportDataCtrl;
 	private IdentityCompetencesController competencesCtrl;
 	private ParticipantLecturesOverviewController lecturesCtrl;
 	private CertificateAndEfficiencyStatementListController efficicencyCtrl;
 
 	private final boolean isOlatAdmin;
 
+	@Autowired
+	private UserManager userManager;
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
@@ -154,6 +161,9 @@ public class UserAdminController extends BasicController implements Activateable
 		if (allowedToManageUser(ureq, myIdentity)) {
 			myContent = createVelocityContainer("udispatcher");
 			backLink = LinkFactory.createLinkBack(myContent, this);
+			exportDataButton = LinkFactory.createButton("export.user.data", myContent, this);
+			exportDataButton.setIconLeftCSS("o_icon o_icon_download");
+			
 			userShortDescrCtr = new UserShortDescription(ureq, wControl, identity);
 			listenTo(userShortDescrCtr);
 			myContent.put("userShortDescription", userShortDescrCtr.getInitialComponent());
@@ -208,6 +218,8 @@ public class UserAdminController extends BasicController implements Activateable
 	public void event(UserRequest ureq, Component source, Event event) {
 		if (source == backLink) {
 			fireEvent(ureq, Event.BACK_EVENT);
+		} else if(exportDataButton == source) {
+			doExportData(ureq);
 		} else if (source == userTabP) {
 			userTabP.addToHistory(ureq, getWindowControl());
 		}
@@ -231,12 +243,39 @@ public class UserAdminController extends BasicController implements Activateable
 		} else if (source == userProfileCtr){
 			if (event == Event.DONE_EVENT){
 				//reload profile data on top
-				myIdentity = (Identity) DBFactory.getInstance().loadObject(myIdentity);
+				myIdentity = securityManager.loadIdentityByKey(myIdentity.getKey());
 				exposeUserDataToVC(ureq, myIdentity);
 				userProfileCtr.resetForm(ureq);
 			}
+		} else if(source == exportDataCtrl) {
+			cmc.deactivate();
+			cleanUp();
+		} else if(source == cmc) {
+			cleanUp();
 		}
 	}
+	
+	private void cleanUp() {
+		removeAsListenerAndDispose(exportDataCtrl);
+		removeAsListenerAndDispose(cmc);
+		exportDataCtrl = null;
+		cmc = null;
+	}
+	
+	private void doExportData(UserRequest ureq) {
+		if(exportDataCtrl != null) return;
+		
+		exportDataCtrl = new UserDataExportController(ureq, getWindowControl(), myIdentity);
+		listenTo(exportDataCtrl);
+		
+		String fullname = userManager.getUserDisplayName(myIdentity);
+		String title = translate("export.user.data.title", new String[] { fullname });
+		cmc = new CloseableModalController(getWindowControl(), translate("close"), exportDataCtrl.getInitialComponent(),
+				true, title);
+		listenTo(cmc);
+		cmc.activate();
+		
+	}
 
 	/**
 	 * Check if user allowed to modify this identity. Only modification of user
diff --git a/src/main/java/org/olat/admin/user/_content/udispatcher.html b/src/main/java/org/olat/admin/user/_content/udispatcher.html
index d9580d017dd3f7311d6c7b90541f7367a9072ecc..b62cb943d4f3830b783378236237c301210c4087 100644
--- a/src/main/java/org/olat/admin/user/_content/udispatcher.html
+++ b/src/main/java/org/olat/admin/user/_content/udispatcher.html
@@ -4,10 +4,13 @@
 #if($r.isTrue($showTitle))
 	<h4>$r.translate("content.usermgmt.userfound")</h4>
 #end
-<div class="o_user_infos row">
+<div class="o_user_infos">
 	<div class="o_user_portrait">$r.render("portrait")</div>
 	<div class="o_user_infos_inner">
 	$r.render("userShortDescription")
 	</div>
 </div>
+<div class="o_button_group o_button_group_right">
+	$r.render("export.user.data")
+</div>
 $r.render("userTabP")
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
index 4ab3a1608b49404134e2cba7e8415a061d519d4c..d86858b60f390160d3342d2333e76f374784c9ab 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
@@ -44,6 +44,8 @@ error.search.form.no.wildcard.dublicates=Suchbegriffe mit `**` sind nicht erlaub
 error.search.form.notempty=F\u00FCllen Sie bitte mindestens ein Feld aus.
 error.search.form.to.short=Suchbegriff ist zu kurz.
 error.search.maxResults=Zuviele Treffer wurde gefunden. Nur die ersten {0} werden angezeigt.
+export.user.data=Daten exportieren
+export.user.data.title=Benutzerdaten von "{0}" exportieren
 form.password.new1=Neues Passwort
 form.password.new2=Passwort best\u00E4tigen
 form.please.enter.new=Bitte geben Sie das neue Passwort f\u00FCr diesen Benutzer ein.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
index 5165d01b05f64cdb5d66505eedfc9cc9d30029fc..721d1700baff84ead6dc49ad800e032787da9500 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
@@ -44,6 +44,8 @@ error.search.form.no.wildcard.dublicates=Search terms including `**` are not all
 error.search.form.notempty=Please fill in at least one field.
 error.search.form.to.short=Search term too short.
 error.search.maxResults=To many results found. Only the first {0} are displayed.
+export.user.data=Export data
+export.user.data.title=Export user data of "{0}"
 form.password.new1=New password
 form.password.new2=Confirm password
 form.please.enter.new=Please enter a new password for this user
diff --git a/src/main/java/org/olat/admin/user/delete/service/DeleteUserDataTask.java b/src/main/java/org/olat/admin/user/delete/service/DeleteUserDataTask.java
index 3c82315d067f9a24f5268a4b4c8207b31c42e461..0a2672fac3e2b581c3dbd969f1cc99ece243c82f 100644
--- a/src/main/java/org/olat/admin/user/delete/service/DeleteUserDataTask.java
+++ b/src/main/java/org/olat/admin/user/delete/service/DeleteUserDataTask.java
@@ -28,7 +28,6 @@ import java.io.File;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
 import org.olat.core.commons.services.taskexecutor.LongRunnable;
 import org.olat.core.id.Identity;
@@ -44,7 +43,6 @@ import org.olat.course.nodes.ProjectBrokerCourseNode;
 import org.olat.course.nodes.TACourseNode;
 import org.olat.course.nodes.ta.DropboxController;
 import org.olat.course.nodes.ta.ReturnboxController;
-import org.olat.ims.qti.editor.QTIEditorPackageImpl;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceManager;
 
@@ -71,46 +69,9 @@ public class DeleteUserDataTask implements LongRunnable {
 	public void run() {
 		long startTime = System.currentTimeMillis();
 		Identity identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityByKey(identityKey);
-		deleteHomesMetaAndVersionDataOf(identity);
-		deleteAllTempQtiEditorFilesOf(identity);
 		deleteAllCoursesUserFilesOf(identity);
 		log.info("Finished UserFileDeletionManager thread for identity=" + identity + " in " + (System.currentTimeMillis() - startTime) + " (ms)");
 	}
-	
-	/**
-	 * Delete the temporary files of the QTI-editor File e.g. /usr/local/olatfs/olat/olatdata/tmp/qtieditor/schuessler
-	 * @param identity
-	 */
-	private void deleteAllTempQtiEditorFilesOf(Identity identity) {
-		File userTempQtiEditorDir = new File(QTIEditorPackageImpl.getQTIEditorBaseDir(), newDeletedUserName);
-		if (userTempQtiEditorDir.exists()) {
-			FileUtils.deleteDirsAndFiles(userTempQtiEditorDir, true, true); 
-			log.audit("User-Deletion: identity=" + identity.getKey() + " : QTI editor temp files deleted under dir=" + userTempQtiEditorDir.getAbsolutePath());
-		}
-	}
-
-	/**
-	 * Delete the meta and version data of the home.
-	 * @param identity
-	 */
-	private void deleteHomesMetaAndVersionDataOf(Identity identity) {
-		String userHome =  FolderConfig.getUserHomes().substring(1);
-		File metaHomeDir = new File(FolderConfig.getCanonicalMetaRoot(), userHome);
-		File metaHomeUserDir = new File(metaHomeDir, newDeletedUserName);
-		if(metaHomeUserDir.exists()) {
-			// the meta-data under home/<USER> can be deleted and must not be renamed
-			FileUtils.deleteDirsAndFiles(metaHomeUserDir, true, true); 			
-			log.audit("User-Deletion: Delete meta-data homes directory for identity=" + identity.getKey() + " directory=" + metaHomeUserDir.getAbsolutePath());
-		}
-
-		File versionHomeDir = new File(FolderConfig.getCanonicalVersionRoot(), userHome);
-		File versionHomeUserDir = new File(versionHomeDir, newDeletedUserName);
-		if(versionHomeUserDir.exists()) {
-			// the meta-data under home/<USER> can be deleted and must not be renamed
-			FileUtils.deleteDirsAndFiles(versionHomeUserDir, true, true); 			
-			log.audit("User-Deletion: Delete meta-data homes directory for identity=" + identity.getKey() + " directory=" + metaHomeUserDir.getAbsolutePath());
-		}
-	}
 
 	/**
 	 * Delete all 'dropboxes' or 'returnboxes' directories for certain user in the course-file structure.
diff --git a/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java b/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java
index 82b84819702226bb2d3d1c157051c1b6a843dd9c..0a6e6413545af5e0d7ca86b5507cf6524df3f8e4 100644
--- a/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java
+++ b/src/main/java/org/olat/admin/user/delete/service/UserDeletionManager.java
@@ -25,7 +25,6 @@
 
 package org.olat.admin.user.delete.service;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
@@ -272,7 +271,6 @@ public class UserDeletionManager {
 		
 		// Delete data of modules that implement the user data deletable
 		String anonymisedIdentityName = identity.getKey().toString();
-		File archiveFilePath = getArchivFilePath(identity);
 		Map<String,UserDataDeletable> userDataDeletableResourcesMap = CoreSpringFactory.getBeansOfType(UserDataDeletable.class);
 		List<UserDataDeletable> userDataDeletableResources = new ArrayList<>(userDataDeletableResourcesMap.values());
 		// Start with high priorities (900: user manager), then continue with
@@ -282,7 +280,7 @@ public class UserDeletionManager {
 		for (UserDataDeletable element : userDataDeletableResources) {
 			try {
 				log.info("UserDataDeletable-Loop for identity::" + identity.getKey() + " and element::" + element.getClass().getSimpleName());
-				element.deleteUserData(identity, anonymisedIdentityName, archiveFilePath);				
+				element.deleteUserData(identity, anonymisedIdentityName);				
 			} catch (Exception e) {
 				log.error("Error while deleting identity::" + identity.getKey() + " data for and element::"
 						+ element.getClass().getSimpleName()
@@ -375,16 +373,6 @@ public class UserDeletionManager {
 		}
 		PropertyManager.getInstance().saveProperty(property);
 	}
-
-	private File getArchivFilePath(Identity identity) {
-		String archiveFilePath = deletionModule.getArchiveRootPath() + File.separator + USER_ARCHIVE_DIR + File.separator + RepositoryDeletionModule.getArchiveDatePath()
-		     + File.separator + "del_identity_" + identity.getName();
-		File archiveIdentityRootDir = new File(archiveFilePath);
-		if (!archiveIdentityRootDir.exists()) {
-			archiveIdentityRootDir.mkdirs();
-		}
-		return archiveIdentityRootDir;
-	}
 	
 	public static class UserDataDeletableComparator implements Comparator<UserDataDeletable> {
 		@Override
diff --git a/src/main/java/org/olat/admin/user/delete/service/UserFileDeletionManager.java b/src/main/java/org/olat/admin/user/delete/service/UserFileDeletionManager.java
index 91ae05e23c15b53775a72b57f66fee9eb541bf2c..c46bfcd0f3ebcf33f754803eab936361e493a17b 100644
--- a/src/main/java/org/olat/admin/user/delete/service/UserFileDeletionManager.java
+++ b/src/main/java/org/olat/admin/user/delete/service/UserFileDeletionManager.java
@@ -25,8 +25,6 @@
 
 package org.olat.admin.user.delete.service;
 
-import java.io.File;
-
 import org.olat.core.commons.services.taskexecutor.TaskExecutorManager;
 import org.olat.core.id.Identity;
 import org.olat.user.UserDataDeletable;
@@ -46,7 +44,7 @@ public class UserFileDeletionManager implements UserDataDeletable {
 	private TaskExecutorManager taskExecutorManager;
 
 	@Override
-	public void deleteUserData(final Identity identity, final String newDeletedUserName, File archivePath) {
+	public void deleteUserData(final Identity identity, final String newDeletedUserName) {
 		taskExecutorManager.execute(new DeleteUserDataTask(identity.getKey(), identity.getName()));
 	}
 }
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
index 58ec39b897bdea24f5f9c60e8859bcf0ecc1a3e8..82c8c31d0cdb7562c5fa94e863bf1e8f4208ce17 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
@@ -26,7 +26,6 @@
 
 package org.olat.basesecurity;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -1353,7 +1352,7 @@ public class BaseSecurityManager implements BaseSecurity, UserDataDeletable {
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		// 1) delete all authentication tokens
 		List<Authentication> authentications = getAuthentications(identity);
 		for (Authentication auth:authentications) {
diff --git a/src/main/java/org/olat/basesecurity/GroupRoles.java b/src/main/java/org/olat/basesecurity/GroupRoles.java
index 2e7a32e6ce58d8b2a7f7abc613d27efdd2291df7..0d0cab32dbd6afdca1506439ac7f23174004ea1a 100644
--- a/src/main/java/org/olat/basesecurity/GroupRoles.java
+++ b/src/main/java/org/olat/basesecurity/GroupRoles.java
@@ -39,6 +39,14 @@ public enum GroupRoles {
 	invitee,
 	waiting;
 	
+	public static boolean isValueOf(String val) {
+		for(GroupRoles role:values()) {
+			if(role.name().equals(val)) {
+				return true;
+			}
+		}
+		return false;
+	}
 	
 	public static List<String> toList(String... roles) {
 		if(roles != null && roles.length > 0 && !(roles.length == 1 && roles[0] == null)) {
diff --git a/src/main/java/org/olat/basesecurity/manager/SecurityGroupDAO.java b/src/main/java/org/olat/basesecurity/manager/SecurityGroupDAO.java
index bd2a02f0f4362004ce7536d474fed0be3c085cec..07c15b6bd50d3d76347b3a354b27913cc4de212e 100644
--- a/src/main/java/org/olat/basesecurity/manager/SecurityGroupDAO.java
+++ b/src/main/java/org/olat/basesecurity/manager/SecurityGroupDAO.java
@@ -19,7 +19,6 @@
  */
 package org.olat.basesecurity.manager;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -316,7 +315,7 @@ public class SecurityGroupDAO implements UserDataDeletable {
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		// Remove legacy security group memberships
 		List<SecurityGroup> securityGroups = getSecurityGroupsForIdentity(identity);
 		for (SecurityGroup secGroup : securityGroups) {
diff --git a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java
index a003a306b92447879947fc992669149e511fc5fb..836a9527210987df084de3315314909d09e661a4 100644
--- a/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java
+++ b/src/main/java/org/olat/commons/calendar/manager/ICalFileCalendarUserDeleteManager.java
@@ -19,8 +19,6 @@
  */
 package org.olat.commons.calendar.manager;
 
-import java.io.File;
-
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
@@ -46,7 +44,7 @@ public class ICalFileCalendarUserDeleteManager implements UserDataDeletable {
 	private ImportToCalendarManager importToCalendarManager;
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		importToCalendarManager.deletePersonalImportedCalendars(identity);
 		log.debug("Personal imported calendars deleted for identity=" + identity);
 		calendarManager.deletePersonalCalendar(identity);
diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java
index 7acba9a11cfb239463bf0bca00b603bdb55d3108..bb9d42af0119d201a41efc5297d4c3dcec22a047 100644
--- a/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java
+++ b/src/main/java/org/olat/commons/memberlist/ui/MembersAvatarDisplayRunController.java
@@ -95,7 +95,6 @@ public class MembersAvatarDisplayRunController extends FormBasicController {
 	private final List<UserPropertyHandler> userPropertyAvatarHandlers;
 
 	private final CourseEnvironment courseEnv;
-	private final DisplayPortraitManager portraitManager;
 	private final String avatarBaseURL;
 	
 	private Link printLink;
@@ -143,6 +142,8 @@ public class MembersAvatarDisplayRunController extends FormBasicController {
 	private UserSessionManager sessionManager;
 	@Autowired
 	private MembersExportManager exportManager;
+	@Autowired
+	private DisplayPortraitManager portraitManager;
 
 	private BusinessGroup businessGroup;
 	private RepositoryEntry repoEntry;
@@ -164,7 +165,6 @@ public class MembersAvatarDisplayRunController extends FormBasicController {
 		userPropertyAvatarHandlers = userManager.getUserPropertyHandlersFor(MembersDisplayRunController.USER_PROPS_AVATAR_ID, isAdministrativeUser);
 		
 		avatarBaseURL = registerCacheableMapper(ureq, "avatars-members", new UserAvatarMapper(true));
-		portraitManager = DisplayPortraitManager.getInstance();
 		chatEnabled = imModule.isEnabled() && imModule.isPrivateEnabled();
 		// lists
 		this.owners = owners;
@@ -221,13 +221,13 @@ public class MembersAvatarDisplayRunController extends FormBasicController {
 		if(formLayout instanceof FormLayoutContainer) {
 			FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
 			layoutCont.contextPut("showOwners", showOwners);
-			layoutCont.contextPut("hasOwners", new Boolean(!ownerList.isEmpty()));
+			layoutCont.contextPut("hasOwners", Boolean.valueOf(!ownerList.isEmpty()));
 			layoutCont.contextPut("showCoaches", showCoaches);
-			layoutCont.contextPut("hasCoaches", new Boolean(!coachList.isEmpty()));
+			layoutCont.contextPut("hasCoaches", Boolean.valueOf(!coachList.isEmpty()));
 			layoutCont.contextPut("showParticipants", showParticipants);
-			layoutCont.contextPut("hasParticipants", new Boolean(!participantList.isEmpty()));
+			layoutCont.contextPut("hasParticipants", Boolean.valueOf(!participantList.isEmpty()));
 			layoutCont.contextPut("showWaiting", showWaiting);
-			layoutCont.contextPut("hasWaiting", new Boolean(!waitingtList.isEmpty()));
+			layoutCont.contextPut("hasWaiting", Boolean.valueOf(!waitingtList.isEmpty()));
 		}
 	}
 	
diff --git a/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java b/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java
index 01de8a32e7faf56f04c186be76a4abc6c320fdca..323d00ea71dfabfae3896470b0ebbc73c540bb5f 100644
--- a/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java
+++ b/src/main/java/org/olat/commons/memberlist/ui/MembersListDisplayRunController.java
@@ -122,6 +122,8 @@ public class MembersListDisplayRunController extends BasicController {
 	@Autowired
 	private MembersExportManager exportManager;
 	@Autowired
+	private DisplayPortraitManager portraitManager;
+	@Autowired
 	private BaseSecurityModule securityModule;
 	@Autowired
 	private UserCourseInformationsManager userInfosMgr;
@@ -346,7 +348,7 @@ public class MembersListDisplayRunController extends BasicController {
 	}
 	
 	private Member createMember(Identity identity) {		
-		boolean hasPortrait = DisplayPortraitManager.getInstance().hasPortrait(identity.getName());
+		boolean hasPortrait = portraitManager.hasPortrait(identity.getName());
 
 		String portraitCssClass;
 		String gender = identity.getUser().getProperty(UserConstants.GENDER, Locale.ENGLISH);
diff --git a/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java b/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java
index 3b04801e0996d9c72463606d2c7784ba6ab5bb2b..101e9f52f01002be2b0aa083baa31ee0bbe34212 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVMergeSource.java
@@ -83,7 +83,7 @@ public class BriefcaseWebDAVMergeSource  extends MergeSource {
 		if(super.getLocalSecurityCallback() == null) {
 			//set quota for this merge source
 			QuotaManager qm = CoreSpringFactory.getImpl(QuotaManager.class);
-			String path = PersonalFolderManager.getInstance().getRootPathFor(identity);
+			String path = PersonalFolderManager.getRootPathFor(identity);
 			Quota quota = qm.getCustomQuotaOrDefaultDependingOnRole(identity, roles, path);
 			FullAccessWithQuotaCallback secCallback = new FullAccessWithQuotaCallback(quota);
 			setLocalSecurityCallback(secCallback);
@@ -95,7 +95,7 @@ public class BriefcaseWebDAVMergeSource  extends MergeSource {
 	protected void init() {
 		super.init();
 		// mount /public
-		String rootPath = PersonalFolderManager.getInstance().getRootPathFor(identity);
+		String rootPath = PersonalFolderManager.getRootPathFor(identity);
 		OlatRootFolderImpl vfsPublic = new OlatRootFolderImpl(rootPath + "/public", this);
 		//vfsPublic.getBasefile().mkdirs(); // lazy initialize folders
 		// we do a little trick here and wrap it again in a NamedContainerImpl so
diff --git a/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVProvider.java b/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVProvider.java
index 6a64265f371d9ed33cf4a2fd602ce4b2ecceb1db..9a44dd74b8b8c84a45132d732c20bf26d2830762 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVProvider.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/BriefcaseWebDAVProvider.java
@@ -62,7 +62,7 @@ public class BriefcaseWebDAVProvider implements WebDAVProvider {
 		return getContainer(identityEnv.getIdentity(), identityEnv.getRoles());
 	}
 	
-	protected String getRootPathFor(Identity identity) {
+	protected static String getRootPathFor(Identity identity) {
 		return FolderConfig.getUserHomes() + "/" + identity.getName();
 	}
 }
diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java
index 7632019edb79fb6b949cf373faa08791e4526944..22f1e189f3aee6e68073f0d3c560b13230e58015 100644
--- a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingServiceImpl.java
@@ -20,7 +20,6 @@
 
 package org.olat.core.commons.services.commentAndRating.manager;
 
-import java.io.File;
 import java.util.List;
 
 import org.olat.core.commons.services.commentAndRating.CommentAndRatingService;
@@ -175,7 +174,7 @@ public class CommentAndRatingServiceImpl implements CommentAndRatingService, Use
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		int rows = userRatingsDao.deleteRatings(identity);
 		log.audit(rows + " rating deleted");
 		int comments = userCommentsDao.deleteAllComments(identity);
diff --git a/src/main/java/org/olat/core/commons/services/notifications/manager/NotificationsManagerImpl.java b/src/main/java/org/olat/core/commons/services/notifications/manager/NotificationsManagerImpl.java
index 486d9b3a6ff866eb69e2b1d8054bde2af6114131..003938a7c8271d6a00974ce3995976b3c9572346 100644
--- a/src/main/java/org/olat/core/commons/services/notifications/manager/NotificationsManagerImpl.java
+++ b/src/main/java/org/olat/core/commons/services/notifications/manager/NotificationsManagerImpl.java
@@ -26,6 +26,9 @@
 package org.olat.core.commons.services.notifications.manager;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
@@ -84,10 +87,15 @@ import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailManager;
 import org.olat.core.util.mail.MailerResult;
+import org.olat.core.util.openxml.OpenXMLWorkbook;
+import org.olat.core.util.openxml.OpenXMLWorksheet;
+import org.olat.core.util.openxml.OpenXMLWorksheet.Row;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.properties.Property;
 import org.olat.properties.PropertyManager;
 import org.olat.user.UserDataDeletable;
+import org.olat.user.UserDataExportable;
+import org.olat.user.manager.ManifestBuilder;
 
 /**
  * Description: <br>
@@ -96,7 +104,7 @@ import org.olat.user.UserDataDeletable;
  * Initial Date: 21.10.2004 <br>
  * @author Felix Jost
  */
-public class NotificationsManagerImpl extends NotificationsManager implements UserDataDeletable {
+public class NotificationsManagerImpl extends NotificationsManager implements UserDataDeletable, UserDataExportable {
 	private static final OLog log = Tracing.createLoggerFor(NotificationsManagerImpl.class);
 
 	private static final int PUB_STATE_OK = 0;
@@ -1275,11 +1283,8 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us
 		
 		return titleSb.toString(); 
 	}
-	
-	/**
-	 * 
-	 * @see org.olat.core.commons.services.notifications.NotificationsManager#getNoSubscriptionInfo()
-	 */
+
+	@Override
 	public SubscriptionInfo getNoSubscriptionInfo() {
 		return NOSUBSINFO;
 	}
@@ -1289,21 +1294,68 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us
 	 * @param identity
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		List<Subscriber> subscribers = getSubscribers(identity);
-		for (Iterator<Subscriber> iter = subscribers.iterator(); iter.hasNext();) {
-			deleteSubscriber( iter.next() );
+		for (Subscriber subscriber:subscribers) {
+			deleteSubscriber(subscriber);
 		}
 		logDebug("All notification-subscribers deleted for identity=" + identity, null);
 	}
 
+	@Override
+	public String getExporterID() {
+		return "notifications";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		File noteArchive = new File(archiveDirectory, "Notifications.xlsx");
+		try(OutputStream out = new FileOutputStream(noteArchive);
+			OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1)) {
+			OpenXMLWorksheet sheet = workbook.nextWorksheet();
+			sheet.setHeaderRows(1);
+			
+			Row row = sheet.newRow();
+			row.addCell(0, "Type");
+			row.addCell(1, "Type");
+			row.addCell(2, "Creation date");
+			row.addCell(3, "Title");
+			
+			List<Subscriber> subscribers = getSubscribers(identity);
+			for(Subscriber subscriber:subscribers) {
+				exportSubscriberData(subscriber, sheet, workbook, locale);
+			}
+		} catch (IOException e) {
+			log.error("Unable to export xlsx", e);
+		}
+
+		manifest.appendFile("Notifications.xlsx");
+	}
+
+	private void exportSubscriberData(Subscriber subscriber, OpenXMLWorksheet sheet, OpenXMLWorkbook workbook, Locale locale) {
+		Row row = sheet.newRow();
+		Publisher pub = subscriber.getPublisher();
+		
+		String innerType = NewControllerFactory.translateResourceableTypeName(pub.getType(), locale);
+		row.addCell(0, innerType);
+		String containerType = NewControllerFactory.translateResourceableTypeName(pub.getResName(), locale);
+		row.addCell(1, containerType);
+		row.addCell(2, subscriber.getCreationDate(), workbook.getStyles().getDateTimeStyle());
+		
+		NotificationsHandler handler = getNotificationsHandler(pub);
+		if(handler != null) {
+			String title = handler.createTitleInfo(subscriber, locale);
+			row.addCell(3, title);
+		}
+	}
+
 	/**
 	 * Spring setter method
 	 * 
 	 * @param notificationIntervals
 	 */
 	public void setNotificationIntervals(Map<String, Boolean> intervals) {
-		notificationIntervals = new ArrayList<String>();
+		notificationIntervals = new ArrayList<>();
 		for(String key : intervals.keySet()) {
 			if (intervals.get(key)) {
 				if(key.length() <= 16) {
diff --git a/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationSubscriptionController.java b/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationSubscriptionController.java
index 966bfdf175ff06ebc3dc55b44c9ba1bb0601674f..9a76667e9e00b631eb950a4f9aade399ba91eddb 100644
--- a/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationSubscriptionController.java
+++ b/src/main/java/org/olat/core/commons/services/notifications/ui/NotificationSubscriptionController.java
@@ -41,6 +41,7 @@ import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
 import org.olat.home.HomeMainController;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description:<br>
@@ -63,6 +64,9 @@ public class NotificationSubscriptionController extends BasicController {
 	private NotificationSubscriptionTableDataModel subscriptionsTableModel;
 	private DialogBoxController delYesNoC;
 	private Identity subscriberIdentity;
+	
+	@Autowired
+	private NotificationsManager notificationsManager;
 
 	public NotificationSubscriptionController(UserRequest ureq, WindowControl wControl,
 			Identity subscriberIdentity, boolean adminColumns) {
@@ -93,11 +97,10 @@ public class NotificationSubscriptionController extends BasicController {
 		// Load subscriptions from DB. Don't use the ureq.getIdentity() but the
 		// subscriberIdentity instead to make this controller also be usable in the
 		// admin environment (admins might change notifications for a user)
-		NotificationsManager man = NotificationsManager.getInstance();
-		List<Subscriber> subs = man.getSubscribers(subscriberIdentity);
+		List<Subscriber> subs = notificationsManager.getSubscribers(subscriberIdentity);
 		for(Iterator<Subscriber> subIt=subs.iterator(); subIt.hasNext(); ) {
 			Subscriber sub = subIt.next();
-			if(!man.isPublisherValid(sub.getPublisher())) {
+			if(!notificationsManager.isPublisherValid(sub.getPublisher())) {
 				subIt.remove();
 			}
 		}
@@ -153,7 +156,7 @@ public class NotificationSubscriptionController extends BasicController {
 			if (DialogBoxUIFactory.isYesEvent(event)) { // ok
 				// Remove subscription and update data model
 				Subscriber sub = (Subscriber) delYesNoC.getUserObject();
-				NotificationsManager.getInstance().unsubscribe(sub);
+				notificationsManager.unsubscribe(sub);
 				updateSubscriptionsDataModel();
 				showInfo("info.notification.deleted");
 				// Notify parent controller
diff --git a/src/main/java/org/olat/core/commons/services/taskexecutor/manager/ExecutorJob.java b/src/main/java/org/olat/core/commons/services/taskexecutor/manager/ExecutorJob.java
index 48652e0995e80b905269040e8b860e525f157294..8c869c21f6ad59c1453952206d919fbed9fe1318 100644
--- a/src/main/java/org/olat/core/commons/services/taskexecutor/manager/ExecutorJob.java
+++ b/src/main/java/org/olat/core/commons/services/taskexecutor/manager/ExecutorJob.java
@@ -33,9 +33,6 @@ import org.quartz.JobExecutionContext;
  */
 public class ExecutorJob extends JobWithDB {
 	
-	/**
-	 * @see org.olat.core.commons.services.scheduler.JobWithDB#executeWithDB(org.quartz.JobExecutionContext)
-	 */
 	@Override
 	public void executeWithDB(JobExecutionContext context) {
 		try {
diff --git a/src/main/java/org/olat/core/util/coordinate/DBPersistentLockManager.java b/src/main/java/org/olat/core/util/coordinate/DBPersistentLockManager.java
index d070cdf2e42fc9f7e55dd13b9dd18d3eb1221ddf..4a7787642af64f28430ae28f1da3c0327ec0a00c 100644
--- a/src/main/java/org/olat/core/util/coordinate/DBPersistentLockManager.java
+++ b/src/main/java/org/olat/core/util/coordinate/DBPersistentLockManager.java
@@ -24,8 +24,6 @@
 */
 package org.olat.core.util.coordinate;
 
-import java.io.File;
-
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.Identity;
@@ -39,9 +37,7 @@ import org.olat.properties.PropertyManager;
 import org.olat.user.UserDataDeletable;
 
 /**
- * Description:<br>
- * TODO: patrickb Class Description for DBPersistentLockManager
- * <P>
+ * 
  * Initial Date: 21.06.2006 <br>
  * 
  * @author patrickb
@@ -122,7 +118,7 @@ public class DBPersistentLockManager implements PersistentLockManager, UserDataD
 	 * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {		
+	public void deleteUserData(Identity identity, String newDeletedUserName) {		
 		String query = "delete from org.olat.properties.Property where category=:category and longValue=:val";
 		
 		DBFactory.getInstance().getCurrentEntityManager()
diff --git a/src/main/java/org/olat/core/util/mail/MailBoxExtension.java b/src/main/java/org/olat/core/util/mail/MailBoxExtension.java
index 648970272bf4d05b67c3c5b64f9f1fab072e6eef..e80af84102a80eb60b7c1f7564833a197d1b2562 100644
--- a/src/main/java/org/olat/core/util/mail/MailBoxExtension.java
+++ b/src/main/java/org/olat/core/util/mail/MailBoxExtension.java
@@ -19,7 +19,6 @@
  */
 package org.olat.core.util.mail;
 
-import java.io.File;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -76,16 +75,16 @@ public class MailBoxExtension implements MailContextResolver, UserDataDeletable,
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		//set as deleted all recipients
 		log.info("Delete intern messages");
 		
-		Collection<DBMailLight> inbox = new HashSet<DBMailLight>(mailManager.getInbox(identity, null, Boolean.FALSE, null, 0, 0));
+		Collection<DBMailLight> inbox = new HashSet<>(mailManager.getInbox(identity, null, Boolean.FALSE, null, 0, 0));
 		for(DBMailLight inMail:inbox) {
 			mailManager.delete(inMail, identity, true);
 		}
 
-		Collection<DBMailLight> outbox = new HashSet<DBMailLight>(mailManager.getOutbox(identity, 0, 0, false));
+		Collection<DBMailLight> outbox = new HashSet<>(mailManager.getOutbox(identity, 0, 0, false));
 		for(DBMailLight outMail:outbox) {
 			mailManager.delete(outMail, identity, true);
 		}
diff --git a/src/main/java/org/olat/course/assessment/EfficiencyStatementArchiver.java b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementArchiver.java
similarity index 97%
rename from src/main/java/org/olat/course/assessment/EfficiencyStatementArchiver.java
rename to src/main/java/org/olat/course/assessment/manager/EfficiencyStatementArchiver.java
index a57671d8baa3e5650b2d65c10e8e6dfd8f9b3b73..cf94b749bf36dddad726440c0ba682cbc8a739dd 100644
--- a/src/main/java/org/olat/course/assessment/EfficiencyStatementArchiver.java
+++ b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementArchiver.java
@@ -23,7 +23,7 @@
 * under the Apache 2.0 license as the original file.
 */
 
-package org.olat.course.assessment;
+package org.olat.course.assessment.manager;
 
 import java.io.File;
 import java.util.List;
@@ -35,6 +35,8 @@ import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.EfficiencyStatement;
 import org.olat.course.nodes.CourseNode;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -51,7 +53,6 @@ public class EfficiencyStatementArchiver {
 	private static final String EOL = "\n";
 	private static final String EFFICIENCY_ARCHIVE_FILE = "efficiencyArchive.xls";
 
-	private static EfficiencyStatementArchiver instance = new EfficiencyStatementArchiver();
 	private Translator translator;
 	private List<UserPropertyHandler> userPropertyHandler;
 
@@ -67,15 +68,10 @@ public class EfficiencyStatementArchiver {
 		userPropertyHandler = UserManager.getInstance().getUserPropertyHandlersFor(EfficiencyStatementArchiver.class.getCanonicalName(), true);
 	}
 
-	public static EfficiencyStatementArchiver getInstance() {
-		return instance;
-	}
-
 	public void archive(List<EfficiencyStatement> efficiencyStatements, Identity identity, File archiveFile) {
 		FileUtils.save(new File(archiveFile, EFFICIENCY_ARCHIVE_FILE), toXls(efficiencyStatements, identity), "utf-8");
 	}
 
-
 	private String toXls(List<EfficiencyStatement> efficiencyStatements, Identity identity) {
 		StringBuilder buf = new StringBuilder();
 		buf.append(translator.translate("efficiencystatement.title"));
diff --git a/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java
index b6812288593b1af929c929a3736b33b5e4c3fc77..5bacc16dca1d0cb107b66232ecfc6116a08d0766 100644
--- a/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java
+++ b/src/main/java/org/olat/course/assessment/manager/EfficiencyStatementManager.java
@@ -31,6 +31,7 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import org.olat.basesecurity.IdentityRef;
@@ -40,6 +41,7 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.coordinate.SyncerExecutor;
 import org.olat.core.util.resource.OresHelper;
@@ -51,7 +53,6 @@ import org.olat.course.assessment.AssessmentChangedEvent;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.EfficiencyStatement;
-import org.olat.course.assessment.EfficiencyStatementArchiver;
 import org.olat.course.assessment.UserEfficiencyStatement;
 import org.olat.course.assessment.model.AssessmentNodeData;
 import org.olat.course.assessment.model.AssessmentNodesLastModified;
@@ -66,7 +67,9 @@ import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.model.RepositoryEntryRefImpl;
 import org.olat.resource.OLATResource;
 import org.olat.user.UserDataDeletable;
+import org.olat.user.UserDataExportable;
 import org.olat.user.UserManager;
+import org.olat.user.manager.ManifestBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -82,7 +85,7 @@ import com.thoughtworks.xstream.XStream;
  * @author gnaegi
  */
 @Service
-public class EfficiencyStatementManager implements UserDataDeletable {
+public class EfficiencyStatementManager implements UserDataDeletable, UserDataExportable {
 	
 	private static final OLog log = Tracing.createLoggerFor(EfficiencyStatementManager.class);
 
@@ -451,7 +454,7 @@ public class EfficiencyStatementManager implements UserDataDeletable {
 		sb.append("select statement from ").append(UserEfficiencyStatementLight.class.getName()).append(" as statement ")
 		  .append(" where statement.identity.key=:studentKey and statement.resource.key in (:courseResourcesKey)");
 		
-		List<Long> coursesKey = new ArrayList<Long>();
+		List<Long> coursesKey = new ArrayList<>();
 		for(RepositoryEntry course:courses) {
 			coursesKey.add(course.getOlatResource().getKey());
 		}
@@ -493,7 +496,7 @@ public class EfficiencyStatementManager implements UserDataDeletable {
 			return Collections.emptyList();
 		}
 		
-		List<Long> resourcesKey = new ArrayList<Long>();
+		List<Long> resourcesKey = new ArrayList<>();
 		for(RepositoryEntry course:courses) {
 			resourcesKey.add(course.getOlatResource().getKey());
 		}
@@ -652,7 +655,7 @@ public class EfficiencyStatementManager implements UserDataDeletable {
 	 * @return List of efficiency statements
 	 */
 	protected List<EfficiencyStatement> findEfficiencyStatements(Identity identity) {
-		List<EfficiencyStatement> efficiencyStatements = new ArrayList<EfficiencyStatement>();
+		List<EfficiencyStatement> efficiencyStatements = new ArrayList<>();
 		try {
 			StringBuilder sb = new StringBuilder();
 			sb.append("select statement from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ")
@@ -663,8 +666,10 @@ public class EfficiencyStatementManager implements UserDataDeletable {
 					.setParameter("identityKey", identity.getKey())
 					.getResultList();
 			for(UserEfficiencyStatementImpl statement:statements) {
-				EfficiencyStatement s = (EfficiencyStatement)xstream.fromXML(statement.getStatementXml());
-				efficiencyStatements.add(s);
+				if(StringHelper.containsNonWhitespace(statement.getStatementXml())) {
+					EfficiencyStatement s = (EfficiencyStatement)xstream.fromXML(statement.getStatementXml());
+					efficiencyStatements.add(s);
+				}
 			}
 
 		} catch (Exception e) {
@@ -811,19 +816,24 @@ public class EfficiencyStatementManager implements UserDataDeletable {
 		}
 	}
 
-	public void archiveUserData(Identity identity, File archiveDir) {
+	@Override
+	public String getExporterID() {
+		return "efficiency.statements";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDir, Locale locale) {
 		List<EfficiencyStatement> efficiencyStatements = findEfficiencyStatements(identity);
-		EfficiencyStatementArchiver.getInstance().archive(efficiencyStatements, identity, archiveDir);
+		new EfficiencyStatementArchiver().archive(efficiencyStatements, identity, archiveDir);
 	}
-	
+
 	/**
 	 * Archive efficiency statement and than delete them for the specified identity.
 	 * 
 	 * @param identity  Delete data for this identity.
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
-		archiveUserData(identity, archivePath);
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		deleteEfficientyStatement(identity);
 	}
 	
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
index b6ef2891ef08aa608032c7a3dac466697ca56a0c..8123aaeccbece4ac1416be3e45afba9694c231c1 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
@@ -174,7 +174,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD
 	private DB dbInstance;
 	
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		// remove as Participant 
 		List<BusinessGroup> attendedGroups = findBusinessGroupsAttendedBy(identity);
 		for (Iterator<BusinessGroup> iter = attendedGroups.iterator(); iter.hasNext();) {
diff --git a/src/main/java/org/olat/home/HomeCalendarManager.java b/src/main/java/org/olat/home/HomeCalendarManager.java
index 5802958b78c8810f927f34dd24a988ff26d3ab6c..01d86f5aad8386ddc9b2d8b3b54993719bcdfd57 100644
--- a/src/main/java/org/olat/home/HomeCalendarManager.java
+++ b/src/main/java/org/olat/home/HomeCalendarManager.java
@@ -20,10 +20,13 @@
 package org.olat.home;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -46,6 +49,7 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.FileUtils;
 import org.olat.core.util.nodes.INode;
 import org.olat.core.util.tree.TreeVisitor;
 import org.olat.core.util.tree.Visitor;
@@ -61,6 +65,9 @@ import org.olat.group.BusinessGroupService;
 import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.repository.RepositoryEntry;
 import org.olat.resource.OLATResource;
+import org.olat.user.UserDataDeletable;
+import org.olat.user.UserDataExportable;
+import org.olat.user.manager.ManifestBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -71,7 +78,7 @@ import org.springframework.stereotype.Service;
  *
  */
 @Service
-public class HomeCalendarManager implements PersonalCalendarManager {
+public class HomeCalendarManager implements PersonalCalendarManager, UserDataDeletable, UserDataExportable {
 	
 	private static final OLog log = Tracing.createLoggerFor(HomeCalendarManager.class);
 	
@@ -158,15 +165,17 @@ public class HomeCalendarManager implements PersonalCalendarManager {
 		return aggregatedFiles;
 	}
 	
+	//
+	
 	@Override
 	public List<KalendarRenderWrapper> getListOfCalendarWrappers(UserRequest ureq, WindowControl wControl) {
 		if(!calendarModule.isEnabled()) {
-			return new ArrayList<KalendarRenderWrapper>();
+			return new ArrayList<>();
 		}
 		
 		Identity identity = ureq.getIdentity();
 		
-		List<KalendarRenderWrapper> calendars = new ArrayList<KalendarRenderWrapper>();
+		List<KalendarRenderWrapper> calendars = new ArrayList<>();
 		Map<CalendarKey,CalendarUserConfiguration> configMap = calendarManager
 				.getCalendarUserConfigurationsMap(ureq.getIdentity());
 		appendPersonalCalendar(identity, calendars, configMap);
@@ -366,6 +375,50 @@ public class HomeCalendarManager implements PersonalCalendarManager {
 		}
 	}
 	
+	@Override
+	public String getExporterID() {
+		return "calendars";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		File calendars = new File(archiveDirectory, "calendars");
+		File iCalFile = calendarManager.getCalendarICalFile(CalendarManager.TYPE_USER, identity.getName());
+		if(iCalFile != null && iCalFile.exists()) {
+			FileUtils.copyFileToDir(iCalFile, calendars, false, "Archive calendar");
+			manifest.appendFile("calendars/" + iCalFile.getName());
+		}
+		List<CalendarFileInfos> importedCalendars = importCalendarManager.getImportedCalendarInfosForIdentity(identity, false);
+		for(CalendarFileInfos importedCalendar:importedCalendars) {
+			File importedCalFile = importedCalendar.getCalendarFile();
+			if(importedCalFile != null && importedCalFile.exists()) {
+				FileUtils.copyFileToDir(importedCalFile, calendars, false, "Archive calendar");
+				manifest.appendFile("calendars/" + importedCalFile.getName());
+			}
+		}
+	}
+
+	@Override
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
+		File iCalFile = calendarManager.getCalendarICalFile(CalendarManager.TYPE_USER, identity.getName());
+		deleteCalendarFile(iCalFile);
+
+		List<CalendarFileInfos> importedCalendars = importCalendarManager.getImportedCalendarInfosForIdentity(identity, false);
+		for(CalendarFileInfos importedCalendar:importedCalendars) {
+			deleteCalendarFile(importedCalendar.getCalendarFile());
+		}
+	}
+	
+	private void deleteCalendarFile(File calendarFile) {
+		if(calendarFile != null && calendarFile.exists()) {
+			try {
+				Files.deleteIfExists(calendarFile.toPath());
+			} catch (IOException e) {
+				log.error("Cannot delete calendar: " + calendarFile);
+			}
+		}
+	}
+
 	private static class CalCourseNodeVisitor implements Visitor {
 		private boolean found = false;
 		
diff --git a/src/main/java/org/olat/home/controllerCreators/PersonalFolderControllerCreator.java b/src/main/java/org/olat/home/controllerCreators/PersonalFolderControllerCreator.java
index 0ac8f3b76687a2c847b785bb8b0a8f6f8002fa2b..3a0df74df5e6d4b384df153b09c8bdfdd2ac69a9 100644
--- a/src/main/java/org/olat/home/controllerCreators/PersonalFolderControllerCreator.java
+++ b/src/main/java/org/olat/home/controllerCreators/PersonalFolderControllerCreator.java
@@ -19,6 +19,7 @@
  */
 package org.olat.home.controllerCreators;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderRunController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.control.Controller;
@@ -37,9 +38,6 @@ import org.olat.user.PersonalFolderManager;
  */
 public class PersonalFolderControllerCreator extends AutoCreator  {
 
-	/**
-	 * @see org.olat.core.gui.control.creator.AutoCreator#getClassName()
-	 */
 	@Override
 	public String getClassName() {
 		return this.getClass().getCanonicalName();
@@ -48,14 +46,11 @@ public class PersonalFolderControllerCreator extends AutoCreator  {
 	public PersonalFolderControllerCreator() {
 		super();
 	}	
-	
-	/**
-	 * @see org.olat.core.gui.control.creator.ControllerCreator#createController(org.olat.core.gui.UserRequest,
-	 *      org.olat.core.gui.control.WindowControl)
-	 */
+
 	@Override
 	public Controller createController(UserRequest ureq, WindowControl lwControl) {
 		IdentityEnvironment identityEnv = ureq.getUserSession().getIdentityEnvironment();
-		return new FolderRunController(PersonalFolderManager.getInstance().getContainer(identityEnv), true, true, true, ureq, lwControl);
+		
+		return new FolderRunController(CoreSpringFactory.getImpl(PersonalFolderManager.class).getContainer(identityEnv), true, true, true, ureq, lwControl);
 	}
 }
diff --git a/src/main/java/org/olat/ims/qti/QTIResultManager.java b/src/main/java/org/olat/ims/qti/QTIResultManager.java
index 57f3aa97f3496f232b2512c0e28141e26ff28a62..95fd7815d3fd597f52d3643a1836da5b6b274d23 100644
--- a/src/main/java/org/olat/ims/qti/QTIResultManager.java
+++ b/src/main/java/org/olat/ims/qti/QTIResultManager.java
@@ -25,7 +25,6 @@
 
 package org.olat.ims.qti;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -337,7 +336,7 @@ public class QTIResultManager implements UserDataDeletable {
 	 * @param identity
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		List<QTIResultSet> qtiResults = findQtiResultSets(identity);
 		for (QTIResultSet set:qtiResults) {
 			deleteResultSet(set);
diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
index 1d3c50aa1611e3aecec481c7fcd83f55b2d87632..dede2a938cea0d69e8b7a9a3bd73e0fd6087c9fb 100644
--- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
+++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
@@ -421,7 +421,7 @@ public class QTI21ServiceImpl implements QTI21Service, UserDataDeletable, Initia
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		List<AssessmentTestSession> sessions = testSessionDao.getUserTestSessions(identity);
 		for(AssessmentTestSession session:sessions) {
 			testSessionDao.deleteTestSession(session);
diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityInteractionsController.java b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityInteractionsController.java
index a270269ddea4a394b0588c4ff4c9469475c4862f..0ecb3a916070799bb14cdde2aa2d2de8ee68d293 100644
--- a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityInteractionsController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityInteractionsController.java
@@ -54,9 +54,11 @@ import org.olat.fileresource.types.ImsQTI21Resource;
 import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator;
 import org.olat.ims.qti21.AssessmentItemSession;
 import org.olat.ims.qti21.AssessmentTestSession;
+import org.olat.ims.qti21.QTI21Constants;
 import org.olat.ims.qti21.QTI21Service;
 import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
 import org.olat.ims.qti21.ui.assessment.model.AssessmentItemCorrection;
+import org.olat.ims.qti21.ui.components.FeedbackResultFormItem;
 import org.olat.ims.qti21.ui.components.InteractionResultFormItem;
 import org.olat.ims.qti21.ui.components.ItemBodyResultFormItem;
 import org.olat.repository.RepositoryEntry;
@@ -64,6 +66,7 @@ import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
+import uk.ac.ed.ph.jqtiplus.node.item.ModalFeedback;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.DrawingInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.ExtendedTextInteraction;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
@@ -74,6 +77,7 @@ import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
 import uk.ac.ed.ph.jqtiplus.state.TestPlanNode;
 import uk.ac.ed.ph.jqtiplus.state.TestPlanNodeKey;
 import uk.ac.ed.ph.jqtiplus.state.TestSessionState;
+import uk.ac.ed.ph.jqtiplus.types.Identifier;
 import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator;
 
 /**
@@ -94,8 +98,10 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
 	private StaticTextElement statusEl;
 	private FormLink viewSolutionButton;
 	private FormLink overrideScoreButton;
+	private FormLink viewCorrectSolutionButton;
 	private ItemBodyResultFormItem answerItem;
 	private ItemBodyResultFormItem solutionItem;
+	private FeedbackResultFormItem correctSolutionItem;
 	private MultipleSelectionElement toReviewEl;
 	private FormLayoutContainer overrideScoreCont;
 	
@@ -166,6 +172,16 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
 		solutionItem.setVisible(false);
 		solutionItem.setShowSolution(true);
 		formLayout.add("solution", solutionItem);
+		
+		if(hasCorrectSolution()) {
+			viewCorrectSolutionButton = uifactory.addFormLink("view.correct.solution", formLayout);
+			viewCorrectSolutionButton.setIconLeftCSS("o_icon o_icon_open_togglebox");
+			
+			correctSolutionItem = initFormCorrectSolution(testPlanNodeKey, testSessionState, testSession, formLayout);
+			correctSolutionItem.setVisible(false);
+			correctSolutionItem.setShowSolution(true);
+			formLayout.add("correctSolution", correctSolutionItem);
+		}
 
 		List<InteractionResultFormItem> responseItems = new ArrayList<>(interactions.size());
 		for(Interaction interaction:interactions) {
@@ -274,6 +290,33 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
 		return responseFormItem;
 	}
 	
+	private FeedbackResultFormItem initFormCorrectSolution(TestPlanNodeKey testPlanNodeKey,
+			TestSessionState testSessionState, AssessmentTestSession assessmentTestSession, FormItemContainer layoutCont) {
+		
+		ItemSessionState sessionState = testSessionState.getItemSessionStates().get(testPlanNodeKey);
+
+		String correctSolutionId = "correctSolutionItem" + count++;
+		FeedbackResultFormItem feedbackItem = new FeedbackResultFormItem(correctSolutionId, resolvedAssessmentItem);
+		feedbackItem.setItemSessionState(sessionState);
+		feedbackItem.setCandidateSessionContext(new TerminatedStaticCandidateSessionContext(assessmentTestSession));
+		feedbackItem.setResolvedAssessmentTest(resolvedAssessmentTest);
+		feedbackItem.setResourceLocator(inputResourceLocator);
+		feedbackItem.setAssessmentObjectUri(assessmentObjectUri);
+		feedbackItem.setMapperUri(mapperUri);
+		layoutCont.add(feedbackItem);
+		return feedbackItem;
+	}
+	
+	private boolean hasCorrectSolution() {
+		for(ModalFeedback modalFeedback:assessmentItem.getModalFeedbacks()) {
+			Identifier outcomeIdentifier = modalFeedback.getOutcomeIdentifier();
+			if(QTI21Constants.CORRECT_SOLUTION_IDENTIFIER.equals(outcomeIdentifier)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
 	protected String getStatus() {
 		AssessmentItemSession itemSession = correction.getItemSession();
 		StringBuilder sb = new StringBuilder();
@@ -334,6 +377,8 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
 			doOverrideScore(ureq);
 		} else if(viewSolutionButton == source) {
 			doToggleSolution();
+		} else if(viewCorrectSolutionButton == source) {
+			doToggleCorrectSolution();
 		}
 		super.formInnerEvent(ureq, source, event);
 	}
@@ -425,6 +470,16 @@ public class CorrectionIdentityInteractionsController extends FormBasicControlle
 		}
 	}
 	
+	private void doToggleCorrectSolution() {
+		if(correctSolutionItem.isVisible()) {
+			viewCorrectSolutionButton.setIconLeftCSS("o_icon o_icon_open_togglebox");
+			correctSolutionItem.setVisible(false);
+		} else {
+			viewCorrectSolutionButton.setIconLeftCSS("o_icon o_icon_close_togglebox");
+			correctSolutionItem.setVisible(true);
+		}
+	}
+	
 	private void doSetOverridenScore(BigDecimal newScore) {
 		overrideAutoScore = newScore;
 		if(newScore == null) {
diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_interactions.html b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_interactions.html
index 735527cbd73ef5b18dd92bbc57bcbd1d0d03704d..5d2a0d398e9ebee8c0689d9f3d4cab8ad0112c37 100644
--- a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_interactions.html
+++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_interactions.html
@@ -6,11 +6,25 @@
 #if($r.visible("solution"))
 	<div class="o_assessmentitem_control_view_solution">$r.render("view.solution")</div>
 	<div class="o_qti_item_body clearfix">$r.render("solution")</div>
+	#if(!$r.visible("view.correct.solution"))
 	<div class="o_assessmentitem_controls"> </div>
+	#end
+#elseif($r.visible("view.correct.solution"))
+	<div class="o_assessmentitem_control_view_solution">$r.render("view.solution")</div>
 #else
 	<div class="o_assessmentitem_controls">$r.render("view.solution")</div>
 #end
 
+#if($r.visible("view.correct.solution"))
+	#if($r.visible("correctSolution"))
+		<div class="o_assessmentitem_control_view_solution">$r.render("view.correct.solution")</div>
+		<div class="o_qti_item_body clearfix">$r.render("correctSolution")</div>
+		<div class="o_assessmentitem_controls"> </div>
+	#else
+		<div class="o_assessmentitem_controls">$r.render("view.correct.solution")</div>
+	#end
+#end
+
 <div class="o_assessmentitem_scoring">
 	$r.render("score.container")
 </div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties
index bf3579a36e2d535d8e74f97c88eb0543c9ff3679..63eeb5b19ff3ab8d92a812eac1435c03e59468a9 100644
--- a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties
@@ -44,6 +44,7 @@ table.header.not.corrected=Nicht korrigiert
 to.review=Zur \u00DCberpr\u00FCfung markieren
 tool.review.all=Alle f\u00FCr \u00DCberpr\u00FCfung markieren
 tool.unreview.all=Markierung aufheben
+view.correct.solution=Korrekte L\u00F6sung ansehen
 view.solution=L\u00F6sung ansehen
 warning.not.submitted=Diese Frage wurde vom Benutzer nicht beantwortet
 warning.no.assessment.item=Es gibt nichts zu korrigieren
diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties
index 45e2507241db0e086f7a6870a3646017fc4f255c..9eea6feec63bdb47550ba17711a8b1ecb8dec9b4 100644
--- a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties
@@ -44,6 +44,7 @@ table.header.username=Username
 to.review=Mark for review
 tool.review.all=Mark all for review
 tool.unreview.all=Remove marks
+view.correct.solution=View correct solution
 view.solution=View solution
 waring.atleast.one=You need at least a question.
 warning.assessment.item.locked=The answer is currently locked by an other user\: {0}.
diff --git a/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java b/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java
index ff599787a4646aaa15904532bc2055146b34a8eb..8a80ef02690bd0eb1210ead508d36f66d35abddc 100644
--- a/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java
+++ b/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java
@@ -19,7 +19,6 @@
  */
 package org.olat.instantMessaging.manager;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -36,7 +35,6 @@ import org.olat.basesecurity.IdentityShort;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
-import org.olat.core.manager.BasicManager;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.GenericEventListener;
@@ -70,7 +68,7 @@ import org.springframework.stereotype.Service;
  *
  */
 @Service
-public class InstantMessagingServiceImpl extends BasicManager implements InstantMessagingService, DeletableGroupData, UserDataDeletable {
+public class InstantMessagingServiceImpl implements InstantMessagingService, DeletableGroupData, UserDataDeletable {
 	
 	@Autowired
 	private RosterDAO rosterDao;
@@ -100,7 +98,7 @@ public class InstantMessagingServiceImpl extends BasicManager implements Instant
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		imDao.deleteMessages(identity);
 		rosterDao.deleteEntry(identity);
 		prefsDao.deletePreferences(identity);
diff --git a/src/main/java/org/olat/instantMessaging/ui/ChatController.java b/src/main/java/org/olat/instantMessaging/ui/ChatController.java
index 0b56a557eb7f54c1b0cb050e8ba2a3f26210bbec..54ff541c1027f4886bba7a68ceebd59a6137140a 100644
--- a/src/main/java/org/olat/instantMessaging/ui/ChatController.java
+++ b/src/main/java/org/olat/instantMessaging/ui/ChatController.java
@@ -365,7 +365,7 @@ public class ChatController extends BasicController implements GenericEventListe
 		messageHistory.addLast(msg);
 
 		chatMsgFieldContent.contextPut("chatMessages", messageHistory);
-		chatMsgFieldContent.contextPut("focus", new Boolean(focus));
+		chatMsgFieldContent.contextPut("focus", Boolean.valueOf(focus));
 	}
 	
 	private Long getAvatarKey(Long identityKey) {
diff --git a/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java b/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java
index 915da459e073a8122b56350b23225b3f46c7c928..4af6a702743392e385ee82b54b078f3c8aa5c389 100644
--- a/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java
+++ b/src/main/java/org/olat/modules/assessment/manager/AssessmentServiceImpl.java
@@ -19,7 +19,6 @@
  */
 package org.olat.modules.assessment.manager;
 
-import java.io.File;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
@@ -123,7 +122,7 @@ public class AssessmentServiceImpl implements AssessmentService, UserDataDeletab
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		assessmentEntryDao.deleteEntryForIdentity(identity);
 	}
 }
diff --git a/src/main/java/org/olat/modules/fo/ForumHelper.java b/src/main/java/org/olat/modules/fo/ForumHelper.java
deleted file mode 100644
index b1ad9a0b4f98ab070805c8709b206f98e45098d4..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/modules/fo/ForumHelper.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
-* 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.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-
-package org.olat.modules.fo;
-
-import java.io.File;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.olat.core.commons.modules.bc.FolderConfig;
-import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
-import org.olat.core.gui.UserRequest;
-import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.VFSItem;
-
-/**
- * 
- * Description:<br>
- * Provides utilities methods and classes.
- *  
- * <P>
- * Initial Date:  14.08.2007 <br>
- * @author Lavinia Dumitrescu
- */
-public class ForumHelper {
-	public static final String CSS_ICON_CLASS_FORUM = "o_fo_icon";
-	public static final String CSS_ICON_CLASS_MESSAGE = "o_forum_message_icon";
-	
-	public static int NOT_MY_JOB = 0;
-	
-	public static final VFSContainer getArchiveContainer(UserRequest ureq, Forum forum) {
-		VFSContainer container = new OlatRootFolderImpl(FolderConfig.getUserHomes() + File.separator + ureq.getIdentity().getName() + "/private/archive", null);
-		// append export timestamp to avoid overwriting previous export 
-		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH_mm_ss");
-		String folder = "forum_" + forum.getKey().toString()+"_"+formatter.format(new Date());
-		VFSItem vfsItem = container.resolve(folder);
-		if (vfsItem == null || !(vfsItem instanceof VFSContainer)) {
-			vfsItem = container.createChildContainer(folder);
-		}
-		container = (VFSContainer) vfsItem;
-		return container;
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java b/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java
index 2f3c8c73ff48ca21226ff5b32e995a1d9febbddb..d96d83d1d5d515051b533ebdf74fde97de050fd6 100644
--- a/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java
+++ b/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java
@@ -131,7 +131,7 @@ public class ForumNotificationsHandler extends LogDelegator implements Notificat
 						urlToSend = BusinessControlFactory.getInstance().getURLFromBusinessPathString(businessPath);
 					}
 					
-					SubscriptionListItem subListItem = new SubscriptionListItem(desc, urlToSend, businessPath, modDate, ForumHelper.CSS_ICON_CLASS_MESSAGE);
+					SubscriptionListItem subListItem = new SubscriptionListItem(desc, urlToSend, businessPath, modDate, ForumUIFactory.CSS_ICON_CLASS_MESSAGE);
 					si.addSubscriptionListItem(subListItem);
 				}
 			} else {
@@ -190,7 +190,7 @@ public class ForumNotificationsHandler extends LogDelegator implements Notificat
 			checkPublisher(p);
 			title = translator.translate("notifications.header");
 		}
-		return new TitleItem(title, ForumHelper.CSS_ICON_CLASS_FORUM);
+		return new TitleItem(title, ForumUIFactory.CSS_ICON_CLASS_FORUM);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/fo/ForumUIFactory.java b/src/main/java/org/olat/modules/fo/ForumUIFactory.java
index 0e9ed885622a530d8d314ca28f01d81f5c1097e2..6971e9ee312c1ff1b2582579f4e8ab0301354a11 100644
--- a/src/main/java/org/olat/modules/fo/ForumUIFactory.java
+++ b/src/main/java/org/olat/modules/fo/ForumUIFactory.java
@@ -49,6 +49,9 @@ import org.olat.modules.fo.ui.ForumController;
  */
 public class ForumUIFactory {
 	
+	public static final String CSS_ICON_CLASS_FORUM = "o_fo_icon";
+	public static final String CSS_ICON_CLASS_MESSAGE = "o_forum_message_icon";
+	
 	/**
 	 * Provides a popable ForumController wrapped in a titled controller.
 	 * @param ureq
@@ -69,8 +72,7 @@ public class ForumUIFactory {
 		};
 		//wrap the content controller into a full header layout
 		ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator);
-		PopupBrowserWindow pbw = wControl.getWindowBackOffice().getWindowManager().createNewPopupBrowserWindowFor(ureq, layoutCtrlr);
-		return pbw;							
+		return wControl.getWindowBackOffice().getWindowManager().createNewPopupBrowserWindowFor(ureq, layoutCtrlr);						
 	}
 	
 	/**
@@ -86,7 +88,7 @@ public class ForumUIFactory {
 		TitledWrapperController forumWrapperController = new TitledWrapperController(ureq, wControl, popupFoCtr, "o_course_run", titleInfo);
 		// Set CSS values to default forum icons if no values are set in the title info
 		if (!StringHelper.containsNonWhitespace(titleInfo.getIconCssClass())) {
-			forumWrapperController.setIconCssClass(ForumHelper.CSS_ICON_CLASS_FORUM);
+			forumWrapperController.setIconCssClass(CSS_ICON_CLASS_FORUM);
 		}
 		return forumWrapperController;							
 	}
diff --git a/src/main/java/org/olat/modules/iq/IQManager.java b/src/main/java/org/olat/modules/iq/IQManager.java
index e3da8f052c85c50b219e0cbcd8c5402c386e52e0..d437d2c8c3243931665116c56093e0450c150d67 100644
--- a/src/main/java/org/olat/modules/iq/IQManager.java
+++ b/src/main/java/org/olat/modules/iq/IQManager.java
@@ -55,6 +55,7 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.logging.activity.OlatResourceableType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.FileUtils;
 import org.olat.core.util.Util;
 import org.olat.core.util.controller.OLATResourceableListeningWrapperController;
 import org.olat.core.util.coordinate.CoordinatorManager;
@@ -73,6 +74,7 @@ import org.olat.ims.qti.container.ItemContext;
 import org.olat.ims.qti.container.ItemInput;
 import org.olat.ims.qti.container.ItemsInput;
 import org.olat.ims.qti.container.SectionContext;
+import org.olat.ims.qti.editor.QTIEditorPackageImpl;
 import org.olat.ims.qti.navigator.NavigatorDelegate;
 import org.olat.ims.qti.process.AssessmentInstance;
 import org.olat.ims.qti.process.FilePersister;
@@ -439,10 +441,15 @@ public class IQManager implements UserDataDeletable {
 	 * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		FilePersister.deleteUserData(identity);
-		if(log.isDebug())
-			log.debug("Delete all qti.ser data and qti-resreporting data for identity=" + identity);
+		log.audit("Delete all qti.ser data and qti-resreporting data for identity=" + identity.getKey());
+		
+		File userTempQtiEditorDir = new File(QTIEditorPackageImpl.getQTIEditorBaseDir(), identity.getName());
+		if (userTempQtiEditorDir.exists()) {
+			FileUtils.deleteDirsAndFiles(userTempQtiEditorDir, true, true); 
+			log.audit("User-Deletion: identity=" + identity.getKey() + " : QTI editor temp files deleted under dir=" + userTempQtiEditorDir.getAbsolutePath());
+		}
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java b/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java
index d0d6cfb8057f548b5122b0e008a7c6c9ab22fae7..6c0ad0f5a7b70ca91b4dbbd20ded4c9bac603dae 100644
--- a/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java
+++ b/src/main/java/org/olat/modules/lecture/manager/LectureServiceImpl.java
@@ -20,7 +20,6 @@
  */
 package org.olat.modules.lecture.manager;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
@@ -346,7 +345,7 @@ public class LectureServiceImpl implements LectureService, UserDataDeletable, De
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		lectureParticipantSummaryDao.deleteSummaries(identity);
 		lectureBlockRollCallDao.deleteRollCalls(identity);
 		lectureBlockReminderDao.deleteReminders(identity);
diff --git a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java
index 5ce16dd722c63046c8d2ac2ff0d09123fc45c9d8..510de8798c734fc5db8b332819c4299e73795e6b 100644
--- a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java
+++ b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java
@@ -86,6 +86,8 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	private CoordinatorManager coordinator;
 	@Autowired
 	private RepositoryManager repositoryManager;
+	@Autowired
+	private DisplayPortraitManager portraitManager;
 
 	private CacheWrapper<String,Long> sessionCache;
 	private OpenMeetingsLanguages languagesMapping;
@@ -121,7 +123,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			getRooms.setMax(2000);
 			getRooms.setSID(adminSID);
 			
-			Map<Long,RoomReturnInfo> realRooms = new HashMap<Long,RoomReturnInfo>();
+			Map<Long,RoomReturnInfo> realRooms = new HashMap<>();
 			
 			//get rooms on openmeetings
 			List<RoomReturn> roomsRet = roomWs.getRoomsWithCurrentUsersByListAndType(adminSID, 0, 2000, "name", true, getOpenOLATExternalType());
@@ -147,7 +149,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			List<OpenMeetingsRoomReference> props = openMeetingsDao.getReferences();
 			Map<Long,String> roomIdToResources = getResourceNames(props);
 
-			List<OpenMeetingsRoom> rooms = new ArrayList<OpenMeetingsRoom>();
+			List<OpenMeetingsRoom> rooms = new ArrayList<>();
 			for(OpenMeetingsRoomReference prop:props) {
 				Long roomId = new Long(prop.getRoomId());
 				RoomReturnInfo infos = realRooms.get(roomId);
@@ -171,8 +173,8 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	}
 	
 	private Map<Long,String> getResourceNames(List<OpenMeetingsRoomReference> properties) {
-		Map<Long,String> roomIdToResourceName = new HashMap<Long,String>();
-		Map<Long,List<Long>> resourceIdToRoomIds = new HashMap<Long,List<Long>>();
+		Map<Long,String> roomIdToResourceName = new HashMap<>();
+		Map<Long,List<Long>> resourceIdToRoomIds = new HashMap<>();
 		for(OpenMeetingsRoomReference prop:properties) {
 			long roomId = prop.getRoomId();
 			if(prop.getGroup() != null) {
@@ -254,7 +256,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	}
 	
 	private String getPortraitURL(Identity identity) {
-		File portrait = DisplayPortraitManager.getInstance().getBigPortrait(identity.getName());
+		File portrait = portraitManager.getBigPortrait(identity.getName());
 		if(portrait == null || !portrait.exists()) {
 			return "";
 		}
@@ -431,7 +433,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			RoomServicePortType roomWs = getRoomWebService();
 			List<FlvRecording> recordings = roomWs.getFlvRecordingByRoomId(adminSID, roomId);
 
-			List<OpenMeetingsRecording> recList = new ArrayList<OpenMeetingsRecording>();
+			List<OpenMeetingsRecording> recList = new ArrayList<>();
 			if(recordings != null) {
 				for(FlvRecording recording:recordings) {
 					if(recording != null) {
@@ -461,14 +463,12 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	throws OpenMeetingsException {
 		try {
 			String sid = adminLogin();
-
-			String url = UriBuilder.fromUri(openMeetingsModule.getOpenMeetingsURI()).path("DownloadHandler")
+			return UriBuilder.fromUri(openMeetingsModule.getOpenMeetingsURI()).path("DownloadHandler")
 				.queryParam("fileName", recording.getDownloadName())
 				.queryParam("moduleName", "lzRecorderApp")
 				.queryParam("parentPath", "")
 				.queryParam("room_id", Long.toString(recording.getRoomId()))
 				.queryParam("sid", sid).build().toString();
-			return url;
 		} catch (Exception e) {
 			log.error("", e);
 			throw translateException(e, 0);
@@ -557,8 +557,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 		try {
 			String adminSID = adminLogin();
 			RoomServicePortType roomWs = getRoomWebService();
-			boolean resp = roomWs.deleteFlvRecording(adminSID, recording.getRecordingId());
-			return resp;
+			return roomWs.deleteFlvRecording(adminSID, recording.getRecordingId());
 		} catch (Exception e) {
 			log.error("", e);
 			return false;
@@ -584,7 +583,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	}
 	
 	private List<OpenMeetingsUser> convert(List<RoomUser> clients) {
-		List<OpenMeetingsUser> users = new ArrayList<OpenMeetingsUser>();
+		List<OpenMeetingsUser> users = new ArrayList<>();
 		if(clients != null) {
 			for(RoomUser client:clients) {
 				OpenMeetingsUser user = convert(client);
@@ -611,8 +610,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	public boolean removeUser(String publicSID) {
 		try {
 			String adminSID = adminLogin();
-			boolean kickResponse = getUserWebService().kickUserByPublicSID(adminSID, publicSID);
-			return kickResponse;
+			return getUserWebService().kickUserByPublicSID(adminSID, publicSID);
 		} catch (Exception e) {
 			log.error("", e);
 			return false;
@@ -623,8 +621,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	public boolean removeUsersFromRoom(OpenMeetingsRoom room) {	
 		try {
 			String adminSID = adminLogin();
-			boolean kickResponse = getRoomWebService().kickUser(adminSID, room.getRoomId());
-			return kickResponse;
+			return getRoomWebService().kickUser(adminSID, room.getRoomId());
 		} catch (Exception e) {
 			log.error("", e);
 			return false;
@@ -634,8 +631,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	private String getSessionID() {
 		try {
 			Sessiondata getSessionResponse = getUserWebService().getSession();
-			String sessionId = getSessionResponse.getSessionId();
-			return sessionId;
+			return getSessionResponse.getSessionId();
 		} catch (Exception e) {
 			log.error("", e);
 			return null;
@@ -707,7 +703,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	}
 	
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		//
 	}
 
diff --git a/src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java b/src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java
index 0c4388348f91ade0287b70aff28e5fa9ae1cc873..7cfa5400ac1f47f58f3dec20c57b06359fa8eb3c 100644
--- a/src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java
+++ b/src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java
@@ -26,7 +26,6 @@ import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.CacheControl;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
@@ -49,7 +48,7 @@ import org.olat.user.UserManager;
 @Path("openmeetings")
 public class OpenMeetingsWebService {
 
-	public static CacheControl cc = new CacheControl();
+	private static final CacheControl cc = new CacheControl();
 	
 	/**
 	 * Retrieves the portrait of an user
@@ -64,36 +63,31 @@ public class OpenMeetingsWebService {
 	@Path("{identityToken}/portrait")
 	@Produces({"image/jpeg","image/jpg",MediaType.APPLICATION_OCTET_STREAM})
 	public Response getPortrait(@PathParam("identityToken") String identityToken, @Context Request request) {
-		try {
-			OpenMeetingsModule module = CoreSpringFactory.getImpl(OpenMeetingsModule.class);
-			if(!module.isEnabled()) {
-				return Response.serverError().status(Status.FORBIDDEN).build();
-			}
+		OpenMeetingsModule module = CoreSpringFactory.getImpl(OpenMeetingsModule.class);
+		if(!module.isEnabled()) {
+			return Response.serverError().status(Status.FORBIDDEN).build();
+		}
 
-			OpenMeetingsManager omm = CoreSpringFactory.getImpl(OpenMeetingsManager.class);
-			Long identityKey = omm.getIdentityKey(identityToken);
-			if(identityKey == null) {
-				return Response.serverError().status(Status.NOT_FOUND).build();
-			}
-			String username = CoreSpringFactory.getImpl(UserManager.class).getUsername(identityKey);
-			if(username == null) {
-				return Response.serverError().status(Status.NOT_FOUND).build();
-			}
-			
-			File portrait = DisplayPortraitManager.getInstance().getBigPortrait(username);
-			if(portrait == null || !portrait.exists()) {
-				return Response.serverError().status(Status.NOT_FOUND).build();
-			}
+		OpenMeetingsManager omm = CoreSpringFactory.getImpl(OpenMeetingsManager.class);
+		Long identityKey = omm.getIdentityKey(identityToken);
+		if(identityKey == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		String username = CoreSpringFactory.getImpl(UserManager.class).getUsername(identityKey);
+		if(username == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
+		
+		File portrait = CoreSpringFactory.getImpl(DisplayPortraitManager.class).getBigPortrait(username);
+		if(portrait == null || !portrait.exists()) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		}
 
-			Date lastModified = new Date(portrait.lastModified());
-			Response.ResponseBuilder response = request.evaluatePreconditions(lastModified);
-			if(response == null) {
-				response = Response.ok(portrait).lastModified(lastModified).cacheControl(cc);
-			}
-			return response.build();
-		} catch (Throwable e) {
-			throw new WebApplicationException(e);
+		Date lastModified = new Date(portrait.lastModified());
+		Response.ResponseBuilder response = request.evaluatePreconditions(lastModified);
+		if(response == null) {
+			response = Response.ok(portrait).lastModified(lastModified).cacheControl(cc);
 		}
+		return response.build();
 	}
-
 }
diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
index d3c865bbd0fa6210d74f5bf85aef5575d0f42515..b050fe259f17090cfe8f314cfc239a706a40185d 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
@@ -289,7 +289,7 @@ public class PortfolioServiceImpl implements PortfolioService, DeletableGroupDat
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		List<Binder> ownedBinders = binderDao.getAllBindersAsOwner(identity);
 		for(Binder ownedBinder:ownedBinders) {
 			OLATResource resource = ((BinderImpl)ownedBinder).getOlatResource();
diff --git a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletable.java b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletable.java
index 30b0a5dd7b6328c96070eca628171816df3d64d8..cff4a59ed78e4d5e369ae7c2c3ccab73f6439a6b 100644
--- a/src/main/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletable.java
+++ b/src/main/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletable.java
@@ -19,7 +19,6 @@
  */
 package org.olat.modules.qpool.manager;
 
-import java.io.File;
 import java.util.List;
 
 import org.olat.core.id.Identity;
@@ -61,7 +60,7 @@ public class QuestionPoolUserDataDeletable implements UserDataDeletable {
 	private QuestionItemDAO questionItemDao;
 	
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		if (!qpoolModule.isDeleteQuestionsWithoutAuthor()) return;
 			
 		List<QuestionItem> itemsWithOneAuthor = questionItemDao.getItemsWithOneAuthor(identity);
diff --git a/src/main/java/org/olat/modules/taxonomy/manager/TaxonomyServiceImpl.java b/src/main/java/org/olat/modules/taxonomy/manager/TaxonomyServiceImpl.java
index 551b732f2924988a27be73cc42bda34a9da63c47..c4166f135d2fc716f348cf6ffa19fea0cafde16d 100644
--- a/src/main/java/org/olat/modules/taxonomy/manager/TaxonomyServiceImpl.java
+++ b/src/main/java/org/olat/modules/taxonomy/manager/TaxonomyServiceImpl.java
@@ -19,7 +19,6 @@
  */
 package org.olat.modules.taxonomy.manager;
 
-import java.io.File;
 import java.util.Date;
 import java.util.List;
 import java.util.UUID;
@@ -355,7 +354,7 @@ public class TaxonomyServiceImpl implements TaxonomyService, UserDataDeletable {
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		taxonomyCompetenceDao.deleteCompetences(identity);
 	}
 }
diff --git a/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java b/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java
index 425e1bc96940c56a6d371b914a55ccd15f113704..43098f739ef3e1688d4f1aa0789df8683f088136 100644
--- a/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java
+++ b/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java
@@ -161,6 +161,8 @@ public class ViteroManager implements UserDataDeletable {
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
+	private DisplayPortraitManager portraitManager;
+	@Autowired
 	private DB dbInstance;
 	
 	private XStream xStream;
@@ -686,7 +688,7 @@ public class ViteroManager implements UserDataDeletable {
 	protected boolean storePortrait(Identity identity, int userId)
 	throws VmsNotAvailableException {
 		try {
-			File portrait = DisplayPortraitManager.getInstance().getBigPortrait(identity.getName());
+			File portrait = portraitManager.getBigPortrait(identity.getName());
 			if(portrait != null && portrait.exists()) {
 				Mtom mtomWs = getMtomWebService();
 				
@@ -719,7 +721,7 @@ public class ViteroManager implements UserDataDeletable {
 	}
 	
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		if(!viteroModule.isDeleteVmsUserOnUserDelete()) return;
 		
 		try {
diff --git a/src/main/java/org/olat/modules/wiki/_content/edit.html b/src/main/java/org/olat/modules/wiki/_content/edit.html
index 10302273eb93e4f0a2b0d0dccd044b809e8326db..a03def4c09d434fec0eaf5fe19b748340d3c356a 100644
--- a/src/main/java/org/olat/modules/wiki/_content/edit.html
+++ b/src/main/java/org/olat/modules/wiki/_content/edit.html
@@ -18,7 +18,7 @@
 		</div>
 	#end
 	<h3>
-		$r.contextHelpWithWrapper("Working With Course Elements#_change_wikipage")
+		$r.contextHelpWithWrapper("Working With Course Elements#WikiWiki")
 		$r.translate("edit"): $page.getPageName().replace("_"," ")</h3>
 
 	<div class="btn-toolbar" role="toolbar">
diff --git a/src/main/java/org/olat/note/NoteManager.java b/src/main/java/org/olat/note/NoteManager.java
index fe39d28a3fa8dc9beae64617bf55edbc0d897e0f..0547850a284ab0a54a66cdf79ffcf3d92bd9572c 100644
--- a/src/main/java/org/olat/note/NoteManager.java
+++ b/src/main/java/org/olat/note/NoteManager.java
@@ -26,17 +26,30 @@
 package org.olat.note;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.Date;
-import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 
 import org.olat.basesecurity.IdentityRef;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.openxml.OpenXMLWorkbook;
+import org.olat.core.util.openxml.OpenXMLWorksheet;
+import org.olat.core.util.openxml.OpenXMLWorksheet.Row;
 import org.olat.core.util.resource.OresHelper;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.user.UserDataDeletable;
+import org.olat.user.UserDataExportable;
+import org.olat.user.manager.ManifestBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -46,7 +59,9 @@ import org.springframework.stereotype.Service;
  * @author Alexander Schneider
  */
 @Service
-public class NoteManager implements UserDataDeletable {
+public class NoteManager implements UserDataDeletable, UserDataExportable {
+	
+	private static final OLog log = Tracing.createLoggerFor(NoteManager.class);
 
 	@Autowired
 	private DB dbInstance;
@@ -107,7 +122,7 @@ public class NoteManager implements UserDataDeletable {
 	public List<Note> listUserNotes(IdentityRef owner) {
 		String query = "select n from org.olat.note.NoteImpl as n inner join fetch n.owner as noteowner where noteowner.key=:noteowner";
 		return dbInstance.getCurrentEntityManager()
-				.createQuery(query.toString(), Note.class).
+				.createQuery(query, Note.class).
 				setParameter("noteowner", owner.getKey())
 				.getResultList();
 	}
@@ -156,13 +171,61 @@ public class NoteManager implements UserDataDeletable {
 	 * @param identity  Delete notes for this identity.
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		List<Note> userNotes = listUserNotes(identity);
-		for (Iterator<Note> iter = userNotes.iterator(); iter.hasNext();) {
-			deleteNote( iter.next() );			
+		for (Note userNote:userNotes) {
+			deleteNote(userNote);			
 		}
 	}
 	
+	@Override
+	public String getExporterID() {
+		return "notes";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		File noteArchive = new File(archiveDirectory, "Notes.xlsx");
+		try(OutputStream out = new FileOutputStream(noteArchive);
+			OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1)) {
+			OpenXMLWorksheet sheet = workbook.nextWorksheet();
+			sheet.setHeaderRows(1);
+			
+			Row row = sheet.newRow();
+			row.addCell(0, "Created");
+			row.addCell(1, "Modified");
+			row.addCell(2, "Title");
+			row.addCell(3, "Content");
+			row.addCell(4, "Course");
+			row.addCell(5, "Course URL");
+			
+			List<Note> notes = listUserNotes(identity);
+			for(Note note:notes) {
+				exportNoteData(note, sheet, workbook);
+			}
+		} catch (IOException e) {
+			log.error("Unable to export xlsx", e);
+		}
+
+		manifest.appendFile("Notes.xlsx");
+	}
+
+	private void exportNoteData(Note note, OpenXMLWorksheet sheet, OpenXMLWorkbook workbook) {
+		Row row = sheet.newRow();
+		row.addCell(0, note.getCreationDate(), workbook.getStyles().getDateTimeStyle());
+		row.addCell(1, note.getLastModified(), workbook.getStyles().getDateTimeStyle());
+		row.addCell(2, note.getNoteTitle());
+		row.addCell(3, note.getNoteText());
+		if("CourseModule".equals(note.getResourceTypeName())) {
+			OLATResourceable ores = OresHelper.createOLATResourceableInstance(note.getResourceTypeName(), note.getResourceTypeId());
+			RepositoryEntry entry = RepositoryManager.getInstance().lookupRepositoryEntry(ores, false);
+			if(entry != null) {
+				row.addCell(4, entry.getDisplayname());
+				row.addCell(5, Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + entry.getKey());
+			}
+		}	
+	}
+
 	/**
 	 * Fire NoteEvent for a specific user after save/update/delete note.
 	 * @param identity
@@ -171,7 +234,6 @@ public class NoteManager implements UserDataDeletable {
 		//event this identity
 		NoteEvent noteEvent = new NoteEvent(identity.getKey());
 		OLATResourceable eventBusOres = OresHelper.createOLATResourceableInstance(Identity.class, identity.getKey());							
-		//TODO: LD: use SingleUserEventCenter
 		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(noteEvent, eventBusOres);		
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java b/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java
index 00fc2ea1b5d32c13e30e5fa496b457d81940e7fc..f6df9786248a0e47624a69290ac4f46da51fe677 100755
--- a/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java
+++ b/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java
@@ -19,7 +19,6 @@
  */
 package org.olat.portfolio.manager;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -173,7 +172,7 @@ public class EPFrontendManager implements UserDataDeletable, DeletableGroupData
 	}
 	
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		deleteUsersArtefacts(identity);
 
 		List<PortfolioStructure> userPersonalMaps = getStructureElementsForUser(identity, ElementType.DEFAULT_MAP, ElementType.STRUCTURED_MAP);
diff --git a/src/main/java/org/olat/properties/PropertyManager.java b/src/main/java/org/olat/properties/PropertyManager.java
index dc9148b5767edd0085a27548357d245302ab7561..f96a0ee8863fe58be22aa0de4afcf276dc15caec 100644
--- a/src/main/java/org/olat/properties/PropertyManager.java
+++ b/src/main/java/org/olat/properties/PropertyManager.java
@@ -25,7 +25,6 @@
 
 package org.olat.properties;
 
-import java.io.File;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
@@ -762,7 +761,7 @@ public class PropertyManager extends BasicManager implements UserDataDeletable {
 	 * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		deleteProperties(identity, null, null, null, null);
 		if(isLogDebugEnabled()) {
 			logDebug("All properties deleted for identity=" + identity);
@@ -770,8 +769,7 @@ public class PropertyManager extends BasicManager implements UserDataDeletable {
 	}
 
 	public Property createProperty() {
-		Property p = new Property();
-		return p;
+		return new Property();
 	}
 
 	private boolean and(StringBuilder sb, boolean and) {
diff --git a/src/main/java/org/olat/registration/RegistrationManager.java b/src/main/java/org/olat/registration/RegistrationManager.java
index 7981384f29fee014ebd6418f13b04e09f7092f56..d0805d8e04e3367452c57da77b4f4448dc8fb34e 100644
--- a/src/main/java/org/olat/registration/RegistrationManager.java
+++ b/src/main/java/org/olat/registration/RegistrationManager.java
@@ -25,7 +25,6 @@
 
 package org.olat.registration;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -453,7 +452,7 @@ public class RegistrationManager implements UserDataDeletable {
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		// Delete temporary keys used in change email or password workflow 
 		deleteAllTemporaryKeys(identity.getKey());
 	}
diff --git a/src/main/java/org/olat/repository/manager/CatalogManager.java b/src/main/java/org/olat/repository/manager/CatalogManager.java
index ee67e1ccd0145c5e6833d150d4578abef9fd607c..377c03bb0fbf26469dc31153756c1dca31d6766f 100644
--- a/src/main/java/org/olat/repository/manager/CatalogManager.java
+++ b/src/main/java/org/olat/repository/manager/CatalogManager.java
@@ -668,7 +668,7 @@ public class CatalogManager implements UserDataDeletable, InitializingBean {
 	 * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		// Remove as owner
 		List<CatalogEntry> catalogEntries = getCatalogEntriesOwnedBy(identity);
 		for (CatalogEntry catalogEntry:catalogEntries) {
diff --git a/src/main/java/org/olat/repository/manager/RepositoryDeletionManager.java b/src/main/java/org/olat/repository/manager/RepositoryDeletionManager.java
index ab225ae9dda99d71118a208548a4f97640716ca8..8b3ec8e3989893dbf98e25cff49ed078c8234f54 100644
--- a/src/main/java/org/olat/repository/manager/RepositoryDeletionManager.java
+++ b/src/main/java/org/olat/repository/manager/RepositoryDeletionManager.java
@@ -25,7 +25,6 @@
 
 package org.olat.repository.manager;
 
-import java.io.File;
 import java.util.List;
 
 import org.olat.basesecurity.GroupRoles;
@@ -70,7 +69,7 @@ public class RepositoryDeletionManager implements UserDataDeletable {
 	 * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		// Remove as owner
 		Identity adminIdentity = deletionModule.getAdminUserIdentity();
 		List<RepositoryEntry> ownedRepoEntries = repositoryManager.queryByOwner(identity);
diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java
index 46763178ab1230fc457044281294232a48e526cc..86ea03d8ac7884b52b221a68b5767d3b17f9153e 100644
--- a/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java
+++ b/src/main/java/org/olat/resource/accesscontrol/provider/auto/manager/AutoAccessManagerImpl.java
@@ -19,7 +19,6 @@
  */
 package org.olat.resource.accesscontrol.provider.auto.manager;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EnumMap;
@@ -222,7 +221,7 @@ public class AutoAccessManagerImpl implements AutoAccessManager, UserDataDeletab
 	}
 
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		deleteAdvanceOrders(identity);
 	}
 
diff --git a/src/main/java/org/olat/search/service/document/IdentityDocument.java b/src/main/java/org/olat/search/service/document/IdentityDocument.java
index 1d15d9e71db6a9e3c3549f42e181f2c0e57b8c36..43335961ffe827e11216d4d90b64cb07de266ae6 100644
--- a/src/main/java/org/olat/search/service/document/IdentityDocument.java
+++ b/src/main/java/org/olat/search/service/document/IdentityDocument.java
@@ -22,6 +22,7 @@ package org.olat.search.service.document;
 import java.util.List;
 
 import org.apache.lucene.document.Document;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.util.CSSHelper;
 import org.olat.core.id.Identity;
 import org.olat.core.id.User;
@@ -34,7 +35,6 @@ import org.olat.search.model.OlatDocument;
 import org.olat.search.service.SearchResourceContext;
 import org.olat.user.HomePageConfig;
 import org.olat.user.HomePageConfigManager;
-import org.olat.user.HomePageConfigManagerImpl;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
 
@@ -61,12 +61,11 @@ public class IdentityDocument extends OlatDocument {
 	 */
 	public static Document createDocument(SearchResourceContext searchResourceContext, Identity identity) {		
 
-		UserManager userMgr = UserManager.getInstance();
-		User user = identity.getUser();
-		
-		HomePageConfigManager homepageMgr = HomePageConfigManagerImpl.getInstance();
+		UserManager userMgr = CoreSpringFactory.getImpl(UserManager.class);
+		HomePageConfigManager homepageMgr = CoreSpringFactory.getImpl(HomePageConfigManager.class);
 		HomePageConfig publishConfig = homepageMgr.loadConfigFor(identity.getName());
 
+		User user = identity.getUser();
 		IdentityDocument identityDocument = new IdentityDocument();
 		identityDocument.setTitle(identity.getName());
 		identityDocument.setCreatedDate(user.getCreationDate());
diff --git a/src/main/java/org/olat/user/DisplayPortraitController.java b/src/main/java/org/olat/user/DisplayPortraitController.java
index 16e463de76309b0185bf87da3e7360bcfe435433..03a74d207e718d1e2394a610b25218dd442030eb 100644
--- a/src/main/java/org/olat/user/DisplayPortraitController.java
+++ b/src/main/java/org/olat/user/DisplayPortraitController.java
@@ -45,6 +45,7 @@ import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.user.propertyhandlers.GenderPropertyHandler;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Initial Date:  Sept 08, 2005
@@ -70,6 +71,9 @@ public class DisplayPortraitController extends BasicController implements Generi
 	private final boolean displayPortraitImage;
 	
 	private boolean forceAnonymous;	
+	
+	@Autowired
+	private DisplayPortraitManager displayPortraitManager;
 
 	
 	/**
@@ -176,7 +180,7 @@ public class DisplayPortraitController extends BasicController implements Generi
 			}
 			
 			if (useLarge) {
-				image = DisplayPortraitManager.getInstance().getBigPortrait(portraitIdent.getName());
+				image = displayPortraitManager.getBigPortrait(portraitIdent.getName());
 				if (image != null && !forceAnonymous && !isDeletedUser) {
 					myContent.contextPut("portraitCssClass", DisplayPortraitManager.AVATAR_BIG_CSS_CLASS);
 				} else if (isAnonymous || forceAnonymous || isDeletedUser) {
@@ -189,7 +193,7 @@ public class DisplayPortraitController extends BasicController implements Generi
 					myContent.contextPut("portraitCssClass", DisplayPortraitManager.DUMMY_FEMALE_BIG_CSS_CLASS);
 				}
 			} else {
-				image = DisplayPortraitManager.getInstance().getSmallPortrait(portraitIdent.getName());
+				image = displayPortraitManager.getSmallPortrait(portraitIdent.getName());
 				if (image != null && !forceAnonymous && !isDeletedUser) {
 					myContent.contextPut("portraitCssClass", DisplayPortraitManager.AVATAR_SMALL_CSS_CLASS);					
 				} else if (isAnonymous || forceAnonymous || isDeletedUser) {
diff --git a/src/main/java/org/olat/user/DisplayPortraitManager.java b/src/main/java/org/olat/user/DisplayPortraitManager.java
index d56a2732ecfa610f4cb8b70138c12b0b794360d7..6404e2e8518a31a475f48dadf1771cf87f98e697 100644
--- a/src/main/java/org/olat/user/DisplayPortraitManager.java
+++ b/src/main/java/org/olat/user/DisplayPortraitManager.java
@@ -30,6 +30,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.List;
+import java.util.Locale;
 
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.core.CoreSpringFactory;
@@ -45,20 +46,20 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
+import org.olat.core.util.io.SystemFilenameFilter;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.user.manager.ManifestBuilder;
 
 /**
  * 
  * Initial Date: Sept 08, 2005 <br>
  * @author Alexander Schneider
  */
-public class DisplayPortraitManager implements UserDataDeletable {
+public class DisplayPortraitManager implements UserDataDeletable, UserDataExportable {
 	private static final OLog log = Tracing.createLoggerFor(DisplayPortraitManager.class);
 	
-	private static DisplayPortraitManager singleton;
-	
 	private static final String LOGO_PREFIX_FILENAME = "logo";
 	private static final String LOGO_BIG_FILENAME = LOGO_PREFIX_FILENAME + "_big";
 	private static final String LOGO_SMALL_FILENAME = LOGO_PREFIX_FILENAME + "_small";
@@ -91,22 +92,6 @@ public class DisplayPortraitManager implements UserDataDeletable {
 	
 	public static final int WIDTH_LOGO_BIG = HEIGHT_BIG * 4;  // 4-8 kbytes (jpeg)
 	public static final int WIDTH_LOGO_SMALL = HEIGHT_SMALL * 4; // 2-4
-	
-	/**
-	 * [spring]
-	 */
-	private DisplayPortraitManager() {
-		singleton = this;
-	}
-	
-	/**
-	 * Singleton pattern
-	 * 
-	 * @return instance
-	 */
-	public static DisplayPortraitManager getInstance() {
-		return singleton;
-	}
 
 	public MediaResource getSmallPortraitResource(String username) {
 		return getPortraitResource(username, PORTRAIT_SMALL_FILENAME);
@@ -225,8 +210,8 @@ public class DisplayPortraitManager implements UserDataDeletable {
 	}
 	
 	public boolean hasPortrait(String username) {
-		File portraitDir = getPortraitDir(username);
-		if(portraitDir != null) {
+		File portraitDir = getPortraitDir(username, false);
+		if(portraitDir != null && portraitDir.exists()) {
 			File[] portraits = portraitDir.listFiles();
 			if(portraits.length > 0) {
 				for(File file:portraits) {
@@ -240,7 +225,7 @@ public class DisplayPortraitManager implements UserDataDeletable {
 	}
 
 	private File getPortraitFile(String username, String prefix) {
-		File portraitDir = getPortraitDir(username);
+		File portraitDir = getPortraitDir(username, true);
 		if(portraitDir != null) {
 			File[] portraits = portraitDir.listFiles();
 			if(portraits.length > 0) {
@@ -258,11 +243,9 @@ public class DisplayPortraitManager implements UserDataDeletable {
 		VFSContainer portraitDir = getPortraitFolder(username);
 		if(portraitDir != null) {
 			List<VFSItem> portraits = portraitDir.getItems();
-			if(portraits.size() > 0) {
-				for(VFSItem file:portraits) {
-					if(file.getName().startsWith(prefix) && file instanceof VFSLeaf) {
-						return (VFSLeaf)file;
-					}
+			for(VFSItem file:portraits) {
+				if(file.getName().startsWith(prefix) && file instanceof VFSLeaf) {
+					return (VFSLeaf)file;
 				}
 			}
 		}
@@ -284,7 +267,7 @@ public class DisplayPortraitManager implements UserDataDeletable {
 	private void setImage(File file, String filename, String username, String prefix,
 			String masterImagePrefix, String largeImagePrefix, String smallImagePrefix,
 			int maxBigWidth, int maxSmallWidth) {
-		File directory = getPortraitDir(username);
+		File directory = getPortraitDir(username, true);
 		if(directory != null) {
 			for(File currentImage:directory.listFiles()) {
 				if(currentImage.equals(file)) {
@@ -330,7 +313,7 @@ public class DisplayPortraitManager implements UserDataDeletable {
 	}
 	
 	private void deleteImages(Identity identity, String prefix) {
-		File directory = getPortraitDir(identity.getName());
+		File directory = getPortraitDir(identity.getName(), false);
 		if(directory != null && directory.exists()) {
 			for(File file:directory.listFiles()) {
 				String filename = file.getName();
@@ -361,11 +344,12 @@ public class DisplayPortraitManager implements UserDataDeletable {
 	 * @param identity
 	 * @return
 	 */
-	public File getPortraitDir(String identityName){
-		String portraitPath = FolderConfig.getCanonicalRoot() + 
-				FolderConfig.getUserHomePage(identityName) + "/portrait"; 
-		File portraitDir = new File(portraitPath);
-		portraitDir.mkdirs();
+	public File getPortraitDir(String identityName, boolean create) {
+		String portraitPath = FolderConfig.getCanonicalRoot() + FolderConfig.getUserHomePage(identityName); 
+		File portraitDir = new File(portraitPath, "portrait");
+		if(create) {
+			portraitDir.mkdirs();
+		}
 		return portraitDir;
 	}
 	
@@ -379,17 +363,33 @@ public class DisplayPortraitManager implements UserDataDeletable {
 
 	@Override
 	public int deleteUserDataPriority() {
-		// must have higher priority than HomePageConfigManagerImpl
+		// must have higher priority than HomePageConfigManager
 		return 650;
 	}
 		
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
-		String userHomePage = FolderConfig.getCanonicalRoot() + FolderConfig.getUserHomePage(identity.getName()); 
-		File portraitDir = new File(userHomePage, "portrait");
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
+		File portraitDir = getPortraitDir(identity.getName(), false);
 		if(portraitDir.exists()) {
 			FileUtils.deleteDirsAndFiles(portraitDir, true, true);
 		}
 		log.debug("Homepage-config file deleted for identity=" + identity);
 	}
+	@Override
+	public String getExporterID() {
+		return "display.portrait";
+	}
+	
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		File portraitDir = getPortraitDir(identity.getName(), false);
+		if(portraitDir.exists()) {
+			File archivePortrait = new File(archiveDirectory, "portrait");
+			File[] portraits = portraitDir.listFiles(new SystemFilenameFilter(true, false));
+			for(File portrait:portraits) {
+				manifest.appendFile("portrait/" + portrait.getName());
+				FileUtils.copyFileToDir(portrait, archivePortrait, false, null, "Archive portrait");
+			}
+		}
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java b/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java
index cff2ce7041b88a12997640365fd89e2f2c55276b..31cf2eec654272d254dd64fc3fe535ba2a1c1ba8 100644
--- a/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java
+++ b/src/main/java/org/olat/user/HomePageContextEntryControllerCreator.java
@@ -71,7 +71,7 @@ public class HomePageContextEntryControllerCreator extends DefaultContextEntryCo
 	public String getTabName(ContextEntry ce, UserRequest ureq) {
 		Identity identity = extractIdentity(ce);
 		if (identity == null) return null;
-		return UserManagerImpl.getInstance().getUserDisplayName(identity);
+		return UserManager.getInstance().getUserDisplayName(identity);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/user/HomePageDisplayController.java b/src/main/java/org/olat/user/HomePageDisplayController.java
index 2dea9df48b8fbcb3c4aec9992a9edd269b83db11..960e7863aaf63dfbb133d27d1c7fba68f67727ec 100644
--- a/src/main/java/org/olat/user/HomePageDisplayController.java
+++ b/src/main/java/org/olat/user/HomePageDisplayController.java
@@ -82,6 +82,8 @@ public class HomePageDisplayController extends BasicController {
 	private OrganisationModule organisationModule;
 	@Autowired
 	private OrganisationService organisationService;
+	@Autowired
+	private DisplayPortraitManager displayPortraitManager;
 
 	/**
 	 * @param ureq
@@ -156,7 +158,7 @@ public class HomePageDisplayController extends BasicController {
 	
 	private void exposeLogo(UserSession usess, Identity homeIdentity, VelocityContainer mainVC) {
 		if(userModule.isLogoByProfileEnabled()) {
-			File logo = DisplayPortraitManager.getInstance().getBigLogo(homeIdentity.getName());
+			File logo = displayPortraitManager.getBigLogo(homeIdentity.getName());
 			if (logo != null) {
 				ImageComponent logoCmp = new ImageComponent(usess, "logo");
 				logoCmp.setMedia(logo);
diff --git a/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java b/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
index ee7c9b5ca001646ce1445fa2b198508c7f3d73d9..549b35806c9c26d4999c65b74dd9556de4e7aefc 100644
--- a/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
+++ b/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
@@ -105,7 +105,7 @@ public class IdentityContextEntryControllerCreator extends DefaultContextEntryCo
 	public String getTabName(ContextEntry ce, UserRequest ureq) {
 		Identity id = getIdentity(ce, ureq);
 		if (id == null) return null;
-		return UserManagerImpl.getInstance().getUserDisplayName(id);
+		return UserManager.getInstance().getUserDisplayName(id);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/user/PersonalFolderManager.java b/src/main/java/org/olat/user/PersonalFolderManager.java
index 0fff17749cd8d129b0d24380e50cc079104badf1..ce8911ff444c3f93d479b38c91da4f7b3c83d869 100644
--- a/src/main/java/org/olat/user/PersonalFolderManager.java
+++ b/src/main/java/org/olat/user/PersonalFolderManager.java
@@ -26,44 +26,80 @@
 package org.olat.user;
 
 import java.io.File;
+import java.util.Locale;
 
 import org.olat.core.commons.modules.bc.BriefcaseWebDAVProvider;
+import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.FileUtils;
+import org.olat.user.manager.ManifestBuilder;
 
 /**
  * Manager for the personal-folder of a user.
  */
-public class PersonalFolderManager extends BriefcaseWebDAVProvider implements UserDataDeletable {
+public class PersonalFolderManager extends BriefcaseWebDAVProvider implements UserDataDeletable, UserDataExportable {
 	
 	private static final OLog log = Tracing.createLoggerFor(PersonalFolderManager.class);
 
-	private static PersonalFolderManager instance;
-
-	/**
-	 * [spring only]
-	 * @param userDeletionManager
-	 */
-	private PersonalFolderManager() {
-		instance = this;
+	@Override
+	public String getExporterID() {
+		return "personal.folders";
 	}
 
-	/**
-	 * @return Instance of a UserManager
-	 */
-	public static PersonalFolderManager getInstance() {
-		return instance;
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale lcoale) {
+		File folder = new File(archiveDirectory, "PersonalFolders");
+		String rootPath = FolderConfig.getCanonicalRoot() + FolderConfig.getUserHomes() + "/" + identity.getName();
+		export("PersonalFolders", new File(rootPath, "private"), manifest, new File(folder, "private"));
+		export("PersonalFolders", new File(rootPath, "public"), manifest, new File(folder, "public"));
+	}
+	
+	public void export(String path, File directory, ManifestBuilder manifest, File archive) {
+		File[] files = directory.listFiles();
+		if(files != null && files.length > 0) {
+			String currentPath = path + "/" + directory.getName();
+			for(File file:files) {
+				if(file.isHidden()) {
+					continue;
+				}
+				if(file.isDirectory()) {
+					File nextArchiveDir = new File(archive, file.getName());
+					nextArchiveDir.mkdirs();
+					export(currentPath, file, manifest, nextArchiveDir);
+				} else if(file.isFile()) {
+					FileUtils.copyFileToDir(file, archive, false, "Copy personal folder");
+					manifest.appendFile(currentPath + "/" + file.getName());
+				}
+			}
+		}
 	}
 
 	/**
 	 * Delete personal-folder homes/<username> (private & public) of an user.
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		new OlatRootFolderImpl(getRootPathFor(identity), null).deleteSilently();
-		log.debug("Personal-folder deleted for identity=" + identity);
-	}
+		log.audit("Personal-folder deleted for identity=" + identity.getKey());
+		
+		String userHome =  FolderConfig.getUserHomes().substring(1);
+		File metaHomeDir = new File(FolderConfig.getCanonicalMetaRoot(), userHome);
+		File metaHomeUserDir = new File(metaHomeDir, identity.getName());
+		if(metaHomeUserDir.exists()) {
+			// the meta-data under home/<USER> can be deleted and must not be renamed
+			FileUtils.deleteDirsAndFiles(metaHomeUserDir, true, true); 			
+			log.audit("User-Deletion: Delete meta-data homes directory for identity=" + identity.getKey() + " directory=" + metaHomeUserDir.getAbsolutePath());
+		}
 
+		File versionHomeDir = new File(FolderConfig.getCanonicalVersionRoot(), userHome);
+		File versionHomeUserDir = new File(versionHomeDir, identity.getName());
+		if(versionHomeUserDir.exists()) {
+			// the meta-data under home/<USER> can be deleted and must not be renamed
+			FileUtils.deleteDirsAndFiles(versionHomeUserDir, true, true); 			
+			log.audit("User-Deletion: Delete meta-data homes directory for identity=" + identity.getKey() + " directory=" + metaHomeUserDir.getAbsolutePath());
+		}
+	}
 }
diff --git a/src/main/java/org/olat/user/UserAvatarMapper.java b/src/main/java/org/olat/user/UserAvatarMapper.java
index a02d9626201ceccf9e5b5ec15a0800308a8833f0..bb01715f5d6a623d2af6c494164475ecfc750ced 100644
--- a/src/main/java/org/olat/user/UserAvatarMapper.java
+++ b/src/main/java/org/olat/user/UserAvatarMapper.java
@@ -42,7 +42,7 @@ public class UserAvatarMapper implements Mapper {
 
 	public UserAvatarMapper(boolean useLargePortrait) {
 		useLarge = useLargePortrait;
-		portraitManager = DisplayPortraitManager.getInstance();
+		portraitManager = CoreSpringFactory.getImpl(DisplayPortraitManager.class);
 		userManager = CoreSpringFactory.getImpl(UserManager.class);
 	}
 
diff --git a/src/main/java/org/olat/user/UserDataDeletable.java b/src/main/java/org/olat/user/UserDataDeletable.java
index 7a2f953046418f61d3ed2999e4de8322f130f286..ffac35a9cc0047d743ec559340be4f85619b9717 100644
--- a/src/main/java/org/olat/user/UserDataDeletable.java
+++ b/src/main/java/org/olat/user/UserDataDeletable.java
@@ -25,8 +25,6 @@
 
 package org.olat.user;
 
-import java.io.File;
-
 import org.olat.core.id.Identity;
 
 
@@ -38,7 +36,7 @@ import org.olat.core.id.Identity;
  */
 public interface UserDataDeletable {
 	
-	default public int deleteUserDataPriority() {
+	public default int deleteUserDataPriority() {
 		// default is to delete with medium priority (0=very low, 1000=very high)
 		return 500;
 	}
@@ -47,5 +45,5 @@ public interface UserDataDeletable {
 	 * Delete user data for certain user
 	 * @param identity  Data for this identity will be deleted 
 	 */
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath);
+	public void deleteUserData(Identity identity, String newDeletedUserName);
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/user/UserDataExport.java b/src/main/java/org/olat/user/UserDataExport.java
new file mode 100644
index 0000000000000000000000000000000000000000..818f275b221dbff801047ff14a95fd4214c2c89b
--- /dev/null
+++ b/src/main/java/org/olat/user/UserDataExport.java
@@ -0,0 +1,39 @@
+package org.olat.user;
+
+import java.util.Set;
+
+import org.olat.core.id.CreateInfo;
+import org.olat.core.id.Identity;
+import org.olat.core.id.ModifiedInfo;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface UserDataExport extends ModifiedInfo, CreateInfo {
+	
+	public Long getKey();
+	
+	public String getDirectory();
+	
+	public ExportStatus getStatus();
+	
+	public void setStatus(ExportStatus status);
+	
+	public Identity getIdentity();
+	
+	public Set<String> getExportIds();
+	
+	
+	public enum ExportStatus {
+		
+		none,
+		requested,
+		processing,
+		ready
+		
+	}
+
+}
diff --git a/src/main/java/org/olat/user/UserDataExportService.java b/src/main/java/org/olat/user/UserDataExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ddd4e0f8080c162c23f0b02ba4d378460ee8ca7f
--- /dev/null
+++ b/src/main/java/org/olat/user/UserDataExportService.java
@@ -0,0 +1,28 @@
+package org.olat.user;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.olat.basesecurity.IdentityRef;
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface UserDataExportService {
+	
+	public List<String> getExporterIds();
+
+	public void requestExportData(Identity identity, Collection<String> eporterIds);
+	
+	public void exportData(Long requestKey);
+	
+	public UserDataExport getCurrentData(IdentityRef identity);
+	
+	public MediaResource getDownload(IdentityRef identity);
+
+}
diff --git a/src/main/java/org/olat/user/UserDataExportable.java b/src/main/java/org/olat/user/UserDataExportable.java
new file mode 100644
index 0000000000000000000000000000000000000000..766a202d1c59583d59991ce92c303e034f1eee6c
--- /dev/null
+++ b/src/main/java/org/olat/user/UserDataExportable.java
@@ -0,0 +1,40 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.user;
+
+import java.io.File;
+import java.util.Locale;
+
+import org.olat.core.id.Identity;
+import org.olat.user.manager.ManifestBuilder;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface UserDataExportable {
+	
+	public String getExporterID();
+	
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale);
+
+}
diff --git a/src/main/java/org/olat/user/UserInfoMainController.java b/src/main/java/org/olat/user/UserInfoMainController.java
index edc5831dfe8baa3cbb4831dbae5ceeb76f5cf32f..fb782dc85c1f7ddd96403acbc107308b7f7aaca4 100644
--- a/src/main/java/org/olat/user/UserInfoMainController.java
+++ b/src/main/java/org/olat/user/UserInfoMainController.java
@@ -120,6 +120,8 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 	private CalendarModule calendarModule;
 	@Autowired
 	private CalendarManager calendarManager;
+	@Autowired
+	private HomePageConfigManager homePageConfigManager;
 
 	/**
 	 * @param ureq
@@ -317,8 +319,7 @@ public class UserInfoMainController extends MainLayoutBasicController implements
 	private HomePageDisplayController doOpenHomepage(UserRequest ureq) {
 		removeAsListenerAndDispose(homePageDisplayController);
 		
-		HomePageConfigManager hpcm = HomePageConfigManagerImpl.getInstance();
-		HomePageConfig homePageConfig = hpcm.loadConfigFor(chosenIdentity.getName());
+		HomePageConfig homePageConfig = homePageConfigManager.loadConfigFor(chosenIdentity.getName());
 		removeAsListenerAndDispose(homePageDisplayController);
 		homePageDisplayController = new HomePageDisplayController(ureq, getWindowControl(), chosenIdentity, homePageConfig);
 		listenTo(homePageDisplayController);
diff --git a/src/main/java/org/olat/user/UserManagerImpl.java b/src/main/java/org/olat/user/UserManagerImpl.java
index 62a2c4aac45565c5468ee143c6148ac9f1eb7277..903f10c75adefaf3b7fbc48a40ff75fc6f557887 100644
--- a/src/main/java/org/olat/user/UserManagerImpl.java
+++ b/src/main/java/org/olat/user/UserManagerImpl.java
@@ -19,7 +19,6 @@
  */
 package org.olat.user;
 
-import java.io.File;
 import java.io.Serializable;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -564,7 +563,7 @@ public class UserManagerImpl extends UserManager implements UserDataDeletable {
 	}
 	
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		identity = securityManager.loadIdentityByKey(identity.getKey());
 		
 		String roles = ((IdentityImpl)identity).getDeletedRoles();
diff --git a/src/main/java/org/olat/user/UserSettingsController.java b/src/main/java/org/olat/user/UserSettingsController.java
index d4ed5343b02b8cb1535b453470212b96e3a3df85..69bd137e5223c0ec35bf5c27f9ac021f1e86f09c 100644
--- a/src/main/java/org/olat/user/UserSettingsController.java
+++ b/src/main/java/org/olat/user/UserSettingsController.java
@@ -21,7 +21,6 @@ package org.olat.user;
 
 import java.util.List;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.webdav.WebDAVModule;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -41,6 +40,8 @@ import org.olat.instantMessaging.InstantMessagingModule;
 import org.olat.instantMessaging.ui.IMPreferenceController;
 import org.olat.registration.DisclaimerController;
 import org.olat.registration.RegistrationModule;
+import org.olat.user.ui.data.UserDataController;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -52,9 +53,11 @@ import org.olat.registration.RegistrationModule;
  */
 public class UserSettingsController extends BasicController implements Activateable2 {
 	
-
+	private Link webdavLink;
+	private Link imLink;
+	private Link disclaimerLink;
+	private final Link userDataLink;
 	private final Link preferencesLink;
-	private Link webdavLink, imLink, disclaimerLink;
 	private final SegmentViewComponent segmentView;
 	private final VelocityContainer mainVC;
 
@@ -62,6 +65,14 @@ public class UserSettingsController extends BasicController implements Activatea
 	private DisclaimerController disclaimerCtrl;
 	private WebDAVPasswordController webdavCtrl;
 	private ChangePrefsController preferencesCtrl;
+	private UserDataController userDataCtrl;
+	
+	@Autowired
+	private WebDAVModule webDAVModule;
+	@Autowired
+	private InstantMessagingModule imModule;
+	@Autowired
+	private RegistrationModule registrationModule;
 
 	/**
 	 * @param ureq
@@ -76,21 +87,26 @@ public class UserSettingsController extends BasicController implements Activatea
 		preferencesLink = LinkFactory.createLink("tab.prefs", mainVC, this);
 		preferencesLink.setElementCssClass("o_sel_user_settings_prefs");
 		segmentView.addSegment(preferencesLink, true);
-		if(CoreSpringFactory.getImpl(WebDAVModule.class).isEnabled()) {
+		if(webDAVModule.isEnabled()) {
 			webdavLink = LinkFactory.createLink("tab.pwdav", mainVC, this);
 			webdavLink.setElementCssClass("o_sel_user_settings_webdav");
 			segmentView.addSegment(webdavLink, false);
 		}
-		if(CoreSpringFactory.getImpl(InstantMessagingModule.class).isEnabled()){
+		if(imModule.isEnabled()) {
 			imLink = LinkFactory.createLink("tab.im", mainVC, this);
 			imLink.setElementCssClass("o_sel_user_settings_im");
 			segmentView.addSegment(imLink, false);
 		}
-		if (CoreSpringFactory.getImpl(RegistrationModule.class).isDisclaimerEnabled()) {
+		if (registrationModule.isDisclaimerEnabled()) {
 			disclaimerLink = LinkFactory.createLink("tab.disclaimer", mainVC, this);
 			disclaimerLink.setElementCssClass("o_sel_user_settings_disclaimer");
 			segmentView.addSegment(disclaimerLink, false);
 		}
+		userDataLink = LinkFactory.createLink("tab.user.data", mainVC, this);
+		userDataLink.setElementCssClass("o_sel_user_data_download");
+		segmentView.addSegment(userDataLink, false);
+		
+		
 		mainVC.put("segments", segmentView);
 		doOpenPreferences(ureq);
 		putInitialPanel(mainVC);
@@ -101,9 +117,11 @@ public class UserSettingsController extends BasicController implements Activatea
 		//
 	}
 
-	/**
-	 * @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)
-	 */
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		//
+	}
+	
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if(source == segmentView) {
@@ -119,6 +137,8 @@ public class UserSettingsController extends BasicController implements Activatea
 					doOpenIM(ureq);
 				} else if (clickedLink == disclaimerLink) {
 					doOpenDisclaimer(ureq);
+				} else if (clickedLink == userDataLink) {
+					doOpenUserData(ureq);
 				}
 			}
 		}
@@ -155,9 +175,13 @@ public class UserSettingsController extends BasicController implements Activatea
 		}
 		mainVC.put("segmentCmp", disclaimerCtrl.getInitialComponent());
 	}
-
-	@Override
-	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
-		//
+	
+	private void doOpenUserData(UserRequest ureq) {
+		if(userDataCtrl == null) {
+			userDataCtrl = new UserDataController(ureq, getWindowControl(), getIdentity());
+			listenTo(userDataCtrl);
+		}
+		mainVC.put("segmentCmp", userDataCtrl.getInitialComponent());
 	}
+	
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties
index d806d96760e232fbb1819e9ffbf43634dde25682..e390a00bc6afb3404243cfba949af0e5e5fa401d 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_de.properties
@@ -129,6 +129,7 @@ tab.pwd=Passwort
 tab.pwdav=WebDAV
 tab.roles=Rollen
 tab.settings=Einstellungen
+tab.user.data=Benutzerdaten
 table.header.action=Aktion
 table.prop.category=Kategorie
 table.prop.creatdat=Erstellt
@@ -148,6 +149,7 @@ ul.header=Publiziertes Bild (Formate .jpg .jpeg .png .gif)
 ul.select.fhelp=Das Bild wird von OpenOLAT auf eine Breite von 100 Pixel zugeschnitten.
 ul.select=Datei w\u00E4hlen
 ul.upload=Hochladen
+user.data.download.explain=Download Benutzerdaten
 user.deleted=Dieser Benutzer ist aus OpenOLAT gel\u00F6scht
 user.email.admin.description=Konfiguration der E-Mail Adresse der/des Benutzenden. Wenn die E-Mail Adresse oder die Eindeutigkeit optional sind, stehen einige OpenOLAT Funktionen nicht zur Verf\u00FCgung, z.B. Selbstregistrierung, Vitero, WebDAV.
 user.email.admin.title=E-Mail Adresse
diff --git a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties
index e4a988e16a5a2e7cbe434900a991aba6c04e0048..0160f5d573a56bc8833315589bc4fd39a7a0ed3e 100644
--- a/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/user/_i18n/LocalStrings_en.properties
@@ -129,6 +129,7 @@ tab.pwd=Password
 tab.pwdav=WebDAV
 tab.roles=Roles
 tab.settings=System settings
+tab.user.data=User data
 table.header.action=Action
 table.prop.category=Category
 table.prop.creatdat=Created
@@ -148,6 +149,7 @@ ul.header=Published image (Formats .jpg .jpeg .png .gif only)
 ul.select=Select file
 ul.select.fhelp=OpenOLAT will crop this image to the width of 100 pixel.
 ul.upload=Upload
+user.data.download.explain=Download user data
 user.deleted=This user has been deleted in OpenOLAT
 user.email.admin.description=Configuration of the user email address. If the email address or the uniqueness are optional, several OpenOLAT features are disabled e.g. self registration, Vitero, WebDAV.
 user.email.admin.title=User email address
diff --git a/src/main/java/org/olat/user/_spring/userContext.xml b/src/main/java/org/olat/user/_spring/userContext.xml
index 941e9f33fa346899d59a7a99a31c23f00987a3b4..6e2710bdad29d4be8f8fa1fac890288758e5999d 100644
--- a/src/main/java/org/olat/user/_spring/userContext.xml
+++ b/src/main/java/org/olat/user/_spring/userContext.xml
@@ -269,7 +269,6 @@
 
 	<bean id="personalFolderManager" class="org.olat.user.PersonalFolderManager"/>
 	<bean class="org.olat.user.DisplayPortraitManager"/>
-	<bean class="org.olat.user.HomePageConfigManagerImpl"/>
 	
 	<!-- Organisation admin. panel -->
 	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints">
diff --git a/src/main/java/org/olat/user/HomePageConfigManagerImpl.java b/src/main/java/org/olat/user/manager/HomePageConfigManagerImpl.java
similarity index 83%
rename from src/main/java/org/olat/user/HomePageConfigManagerImpl.java
rename to src/main/java/org/olat/user/manager/HomePageConfigManagerImpl.java
index 384ee5244b6e09437d8a375a257a4b46af7d4d28..11fa36c56d73808c5dce4ba6140544101165b4b9 100644
--- a/src/main/java/org/olat/user/HomePageConfigManagerImpl.java
+++ b/src/main/java/org/olat/user/manager/HomePageConfigManagerImpl.java
@@ -23,7 +23,7 @@
 * under the Apache 2.0 license as the original file.
 */
 
-package org.olat.user;
+package org.olat.user.manager;
 
 import java.io.File;
 
@@ -31,39 +31,22 @@ import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
-import org.olat.core.manager.BasicManager;
 import org.olat.core.util.CodeHelper;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.xml.XStreamHelper;
+import org.olat.user.HomePageConfig;
+import org.olat.user.HomePageConfigManager;
+import org.springframework.stereotype.Service;
 
 /**
- * Description: <br>
- * TODO: alex Class Description for HomePageConfigManagerImpl
- * <P>
  * 
  * Initial Date: Jun 3, 2005 <br>
  * @author Alexander Schneider
  */
-public class HomePageConfigManagerImpl extends BasicManager implements HomePageConfigManager {
+@Service
+public class HomePageConfigManagerImpl implements HomePageConfigManager {
 
-	private static OLog log = Tracing.createLoggerFor(HomePageConfigManagerImpl.class);
-	private static HomePageConfigManagerImpl singleton;
-
-	/**
-	 * [spring]
-	 * @param userDeletionManager
-	 */
-	private HomePageConfigManagerImpl() {
-		singleton = this;
-	}
-	/**
-	 * Singleton pattern
-	 * 
-	 * @return instance
-	 */
-	public static HomePageConfigManager getInstance() {
-		return singleton;
-	}
+	private static final OLog log = Tracing.createLoggerFor(HomePageConfigManagerImpl.class);
 
 	/**
 	 * 
@@ -85,7 +68,7 @@ public class HomePageConfigManagerImpl extends BasicManager implements HomePageC
 					retVal = (HomePageConfig) tmp;
 					retVal.resolveVersionIssues();
 					if (!retVal.hasResourceableId()) {
-						retVal.setResourceableId(new Long(CodeHelper.getForeverUniqueID()));
+						retVal.setResourceableId(Long.valueOf(CodeHelper.getForeverUniqueID()));
 					}
 					configFile = null;
 					saveConfigTo(userName, retVal);
@@ -158,12 +141,12 @@ public class HomePageConfigManagerImpl extends BasicManager implements HomePageC
 	 * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
 	 */
 	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) {
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		String pathHomePage = FolderConfig.getCanonicalRoot() + FolderConfig.getUserHomePage(identity.getName());
 		File userHomePage = new File(pathHomePage);
 		if(userHomePage.exists()) {
 			FileUtils.deleteDirsAndFiles(userHomePage, true, true);
 		}
-		logAudit("Homepage-config file and homepage-dir deleted for identity=" + identity);
+		log.audit("Homepage-config file and homepage-dir deleted for identity=" + identity);
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/user/manager/ManifestBuilder.java b/src/main/java/org/olat/user/manager/ManifestBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b3c15bcf0cdbaf3ab5e9f7f03518d341735c985
--- /dev/null
+++ b/src/main/java/org/olat/user/manager/ManifestBuilder.java
@@ -0,0 +1,134 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.user.manager;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.UUID;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.imscp.xml.manifest.FileType;
+import org.olat.imscp.xml.manifest.ManifestMetadataType;
+import org.olat.imscp.xml.manifest.ManifestType;
+import org.olat.imscp.xml.manifest.MetadataType;
+import org.olat.imscp.xml.manifest.ResourceType;
+import org.olat.imscp.xml.manifest.ResourcesType;
+
+/**
+ * 
+ * Initial date: 24 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ManifestBuilder {
+	
+	private static final OLog log = Tracing.createLoggerFor(ManifestBuilder.class);
+	private static final org.olat.imscp.xml.manifest.ObjectFactory objectFactory = new org.olat.imscp.xml.manifest.ObjectFactory();
+
+	public static final String SCHEMA_LOCATIONS = "http://www.imsglobal.org/xsd/imscp_v1p1 http://www.imsglobal.org/xsd/imscp_v1p2.xsd http://www.imsglobal.org/xsd/imsmd_v1p2 http://www.imsglobal.org/xsd/imsmd_v1p2p4.xsd";
+
+	private static JAXBContext context;
+	static {
+		try {
+			context = JAXBContext.newInstance("org.olat.imscp.xml.manifest:org.olat.imsmd.xml.manifest");
+		} catch (JAXBException e) {
+			log.error("", e);
+		}
+	}
+
+	private final ManifestType manifest;
+
+	public ManifestBuilder() {
+		manifest = objectFactory.createManifestType();
+	}
+	
+	/**
+	 * Create a manifest.
+	 * 
+	 * @return The builder
+	 */
+	public static ManifestBuilder createBuilder() {
+		ManifestBuilder builder = new ManifestBuilder();
+		ManifestMetadataType metadataType = objectFactory.createManifestMetadataType();
+		metadataType.setSchema("IMS Content");
+        metadataType.setSchemaversion("1.1");
+        builder.manifest.setMetadata(metadataType);
+        return builder;
+	}
+	
+	public MetadataType getMetadata(ResourceType resourceType) {
+		if(resourceType == null) return null;
+		MetadataType metadata = resourceType.getMetadata();
+		if(metadata == null) {
+			metadata = objectFactory.createMetadataType();
+			resourceType.setMetadata(metadata);
+		}
+		return metadata;
+	}
+	
+	public List<ResourceType> getResourceList() {
+		ResourcesType resources = manifest.getResources();
+		if(resources == null) {
+			resources = objectFactory.createResourcesType();
+			manifest.setResources(resources);
+		}
+		return resources.getResource();
+	}
+	
+	public void appendFile(String href) {
+		ResourceType fileResourceType = objectFactory.createResourceType();
+        fileResourceType.setIdentifier(UUID.randomUUID().toString());
+        fileResourceType.setHref(href);
+        getResourceList().add(fileResourceType);
+		FileType itemFileType = objectFactory.createFileType();
+        itemFileType.setHref(href);
+        fileResourceType.getFile().add(itemFileType);
+	}
+	
+	public MetadataType getMetadataType(ResourceType resource, boolean create) {
+		if(resource == null) return null;
+		
+		MetadataType metadata = resource.getMetadata();
+		if(metadata == null && create) {
+			metadata = objectFactory.createMetadataType();
+			resource.setMetadata(metadata);
+		}
+		return metadata;
+	}
+
+	public final void write(File file) {
+        try(OutputStream out = new FileOutputStream(file)) {
+			Marshaller marshaller = context.createMarshaller();
+			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+			marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, SCHEMA_LOCATIONS);
+			marshaller.marshal(objectFactory.createManifest(manifest), out);
+		} catch (JAXBException | IOException e) {
+			log.error("", e);
+		}
+	}
+}
diff --git a/src/main/java/org/olat/user/manager/UserDataExportDAO.java b/src/main/java/org/olat/user/manager/UserDataExportDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..8931608dae94cba4e5c8de325e966497420b1b7f
--- /dev/null
+++ b/src/main/java/org/olat/user/manager/UserDataExportDAO.java
@@ -0,0 +1,100 @@
+package org.olat.user.manager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.olat.basesecurity.IdentityRef;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.core.util.CodeHelper;
+import org.olat.user.UserDataExport;
+import org.olat.user.model.UserDataExportImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class UserDataExportDAO {
+	
+	@Autowired
+	private DB dbInstance;
+	
+	public UserDataExport createExport(Identity identity, Collection<String> exportIds, UserDataExport.ExportStatus status) {
+		UserDataExportImpl data = new UserDataExportImpl();
+		data.setCreationDate(new Date());
+		data.setLastModified(data.getCreationDate());
+		data.setIdentity(identity);
+		data.setStatus(status);
+		data.setDirectory(identity.getKey() + "-" + CodeHelper.getForeverUniqueID());
+		StringBuilder sb = new StringBuilder(256);
+		for(String exportId:exportIds) {
+			if(sb.length() > 0) sb.append(",");
+			sb.append(exportId);
+		}
+		data.setExporterIdList(sb.toString());
+		dbInstance.getCurrentEntityManager().persist(data);
+		return data;
+	}
+	
+	public UserDataExport update(UserDataExport exportData) {
+		((UserDataExportImpl)exportData).setLastModified(new Date());
+		return dbInstance.getCurrentEntityManager().merge(exportData);
+	}
+	
+	public UserDataExport loadByKey(Long key) {
+		String query = "select data from userdataexport data where data.key=:dataKey";
+		List<UserDataExport> datas = dbInstance.getCurrentEntityManager()
+				.createQuery(query, UserDataExport.class)
+				.setParameter("dataKey", key)
+				.getResultList();
+		return datas == null || datas.isEmpty() ? null : datas.get(0);
+	}
+	
+	public List<UserDataExport> getUserDataExport(IdentityRef identity, List<UserDataExport.ExportStatus> status) {
+		StringBuilder sb = new StringBuilder(128);
+		sb.append("select data from userdataexport data")
+		  .append(" where data.identity.key=:identityKey and data.statusString in (:status)");
+		
+		List<String> statusString = status.stream()
+				.map(UserDataExport.ExportStatus::name)
+				.collect(Collectors.toList());
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), UserDataExport.class)
+				.setParameter("identityKey", identity.getKey())
+				.setParameter("status", statusString)
+				.getResultList();
+	}
+	
+	public UserDataExport getLastUserDataExport(IdentityRef identity) {
+		StringBuilder sb = new StringBuilder(128);
+		sb.append("select data from userdataexport data")
+		  .append(" where data.identity.key=:identityKey and data.statusString in (:status)")
+		  .append(" order by data.creationDate desc");
+		
+		List<String> statusString = new ArrayList<>();
+		statusString.add(UserDataExport.ExportStatus.requested.name());
+		statusString.add(UserDataExport.ExportStatus.processing.name());
+		statusString.add(UserDataExport.ExportStatus.ready.name());
+		List<UserDataExport> datas = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), UserDataExport.class)
+				.setParameter("identityKey", identity.getKey())
+				.setParameter("status", statusString)
+				.setFirstResult(0)
+				.setMaxResults(1)
+				.getResultList();
+		return datas == null || datas.isEmpty() ? null : datas.get(0);
+	}
+	
+
+	
+	
+
+}
diff --git a/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java b/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..2895cd8e23b8ba652cd06fb148493bfebc9168cf
--- /dev/null
+++ b/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java
@@ -0,0 +1,198 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.user.manager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.olat.basesecurity.IdentityRef;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.taskexecutor.TaskExecutorManager;
+import org.olat.core.gui.media.FileMediaResource;
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.gui.media.NotFoundMediaResource;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Preferences;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.WebappHelper;
+import org.olat.core.util.ZipUtil;
+import org.olat.core.util.i18n.I18nManager;
+import org.olat.user.UserDataExport;
+import org.olat.user.UserDataExportService;
+import org.olat.user.UserDataExportable;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class UserDataExportServiceImpl implements UserDataExportService {
+	
+	private static final OLog log = Tracing.createLoggerFor(UserDataExportServiceImpl.class);
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private I18nManager i18nManager;
+	@Autowired
+	private UserDataExportDAO userDataExportDao;
+	@Autowired
+	private TaskExecutorManager taskExecutorManager;
+	
+	@Override
+	public List<String> getExporterIds() {
+		Map<String,UserDataExportable> exporters = CoreSpringFactory.getBeansOfType(UserDataExportable.class);
+		return exporters.values().stream()
+				.map(UserDataExportable::getExporterID)
+				.collect(Collectors.toList());
+	}
+
+	@Override
+	public void requestExportData(Identity identity, Collection<String> exportIds) {
+		List<UserDataExport.ExportStatus> runningStatus = new ArrayList<>();
+		runningStatus.add(UserDataExport.ExportStatus.requested);
+		runningStatus.add(UserDataExport.ExportStatus.processing);
+		List<UserDataExport> currentExport = userDataExportDao.getUserDataExport(identity, runningStatus);
+		if(currentExport.isEmpty()) {
+			UserDataExport dataExport = userDataExportDao.createExport(identity, exportIds, UserDataExport.ExportStatus.requested);
+			dbInstance.commit();
+			taskExecutorManager.execute(new UserDataExportTask(dataExport.getKey()));
+		}
+	}
+
+	@Override
+	public void exportData(Long requestKey) {
+		UserDataExport dataExport = userDataExportDao.loadByKey(requestKey);
+		if(dataExport == null) return;
+		
+		if(dataExport.getStatus() != UserDataExport.ExportStatus.requested) {
+			return;
+		}
+		
+		// start processing
+		dataExport.setStatus(UserDataExport.ExportStatus.processing);
+		dataExport = userDataExportDao.update(dataExport);
+		dbInstance.commit();
+		
+		// make sure we doesn't double down the export
+		File archiveDirectory = getArchiveDirectory(dataExport);
+		File archive = new File(archiveDirectory, "data.zip");
+		if(archive.exists()) {
+			dataExport.setStatus(UserDataExport.ExportStatus.ready);
+			userDataExportDao.update(dataExport);
+			return; // already done
+		}
+		
+		// export datas
+		Identity identity = dataExport.getIdentity();
+		Preferences preferences = identity.getUser().getPreferences();
+		Locale locale = i18nManager.getLocaleOrDefault(preferences.getLanguage());
+
+		ManifestBuilder manifest = ManifestBuilder.createBuilder();
+		Set<String> exportIds = dataExport.getExportIds();
+		Map<String,UserDataExportable> exporters = CoreSpringFactory.getBeansOfType(UserDataExportable.class);
+		for(UserDataExportable exporter:exporters.values()) {
+			if(exportIds.contains(exporter.getExporterID())) {
+				try {
+					exporter.export(identity, manifest, archiveDirectory, locale);
+					dbInstance.commitAndCloseSession();
+				} catch (Exception e) {
+					log.error("Cannot export " + exporter.getClass().getSimpleName() + " for identity=" + identity.getKey(), e);
+					dbInstance.rollbackAndCloseSession();
+				}
+			}
+		}
+		
+		// save manifest
+		manifest.write(new File(archiveDirectory, "imsmanifest.xml"));
+		
+		// make zip
+		String[] files = archiveDirectory.list();
+		Set<String> filenames = Arrays.stream(files).collect(Collectors.toSet());
+		ZipUtil.zip(filenames, archiveDirectory, archive);
+		
+		UserDataExport reloadedDataExport = userDataExportDao.loadByKey(requestKey);
+		reloadedDataExport.setStatus(UserDataExport.ExportStatus.ready);
+		userDataExportDao.update(reloadedDataExport);
+		dbInstance.commitAndCloseSession();
+	}
+	
+	@Override
+	public UserDataExport getCurrentData(IdentityRef identity) {
+		return userDataExportDao.getLastUserDataExport(identity);
+	}
+
+	@Override
+	public MediaResource getDownload(IdentityRef identity) {
+		UserDataExport dataExport = getCurrentData(identity);
+		if(dataExport.getStatus() == UserDataExport.ExportStatus.ready) {
+			File archiveDirectory = getArchiveDirectory(dataExport);
+			File archive = new File(archiveDirectory, "data.zip");
+			if(archive.exists()) {
+				return new ArchiveMediaResource(archive);
+			}
+		}
+		return new NotFoundMediaResource();
+	}
+	
+	private File getArchiveDirectory(UserDataExport dataExport) {
+		File archivesDirectory = new File(WebappHelper.getUserDataRoot(), "export_usersdata");
+		File archiveDirectory = new File(archivesDirectory, dataExport.getDirectory());
+		if(!archiveDirectory.exists()) {
+			archiveDirectory.mkdirs();
+		}
+		return archiveDirectory;
+	}
+	
+	private static class ArchiveMediaResource extends FileMediaResource {
+		
+		public ArchiveMediaResource(File file) {
+			super(file, true);
+		}
+
+		@Override
+		public String getContentType() {
+			return "application/zip";
+		}
+
+		@Override
+		public void prepare(HttpServletResponse hres) {
+			// encode filename in ISO8859-1; does not really help but prevents from filename not being displayed at all
+			// if it contains non-US-ASCII characters which are not allowed in header fields.
+			hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''Archive.zip");
+			hres.setHeader("Content-Description", "Archive.zip");
+		}
+	}
+}
diff --git a/src/main/java/org/olat/user/manager/UserDataExportTask.java b/src/main/java/org/olat/user/manager/UserDataExportTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d7ad0575bfa482ad3d4cf1a3f04b2b5f80769b5
--- /dev/null
+++ b/src/main/java/org/olat/user/manager/UserDataExportTask.java
@@ -0,0 +1,33 @@
+package org.olat.user.manager;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.user.UserDataExportService;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserDataExportTask implements /* Long */ Runnable {
+
+	private static final long serialVersionUID = 6931074116105090545L;
+
+	private static final OLog log = Tracing.createLoggerFor(UserDataExportTask.class);
+	
+	private final Long exportKey;
+	
+	public UserDataExportTask(Long exportKey) {
+		this.exportKey = exportKey;
+	}
+	
+	@Override
+	public void run() {
+		long startTime = System.currentTimeMillis();
+		UserDataExportService exportService = CoreSpringFactory.getImpl(UserDataExportService.class);
+		exportService.exportData(exportKey);
+		log.info("Finished data export thread for=" + exportKey + " in " + (System.currentTimeMillis() - startTime) + " (ms)");
+	}
+}
diff --git a/src/main/java/org/olat/user/model/UserDataExportImpl.java b/src/main/java/org/olat/user/model/UserDataExportImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c41546dadea6658efb25d1ef61c685f0badc147
--- /dev/null
+++ b/src/main/java/org/olat/user/model/UserDataExportImpl.java
@@ -0,0 +1,174 @@
+package org.olat.user.model;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
+import org.olat.core.util.StringHelper;
+import org.olat.user.UserDataExport;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="userdataexport")
+@Table(name="o_user_data_export")
+public class UserDataExportImpl implements UserDataExport, Persistable {
+
+	private static final long serialVersionUID = 3359965105813614815L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date lastModified;
+	
+	@Column(name="u_directory", nullable=true, insertable=true, updatable=false)
+	private String directory;
+	@Column(name="u_status", nullable=true, insertable=true, updatable=true)
+	private String statusString;
+	@Column(name="u_export_ids", nullable=true, insertable=true, updatable=true)
+	private String exporterIdList;
+	
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=true)
+	@JoinColumn(name="fk_identity", nullable=true, insertable=true, updatable=false)
+    private Identity identity;
+
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date date) {
+		lastModified = date;
+	}
+
+	@Override
+	public String getDirectory() {
+		return directory;
+	}
+
+	public void setDirectory(String directory) {
+		this.directory = directory;
+	}
+
+	public String getStatusString() {
+		return statusString;
+	}
+
+	public void setStatusString(String statusString) {
+		this.statusString = statusString;
+	}
+
+	@Override
+	public ExportStatus getStatus() {
+		return StringHelper.containsNonWhitespace(statusString)
+				? ExportStatus.valueOf(statusString) : ExportStatus.none;
+	}
+
+	@Override
+	public void setStatus(ExportStatus status) {
+		if(status == null) {
+			statusString = ExportStatus.none.name();
+		} else {
+			statusString = status.name();
+		}
+	}
+
+	@Override
+	@Transient
+	public Set<String> getExportIds() {
+		if(StringHelper.containsNonWhitespace(exporterIdList)) {
+			String[] ids = exporterIdList.split("[,]");
+			Set<String> idSet = new HashSet<>();
+			for(String id:ids) {
+				idSet.add(id);
+			}
+			return idSet;
+		}
+		return Collections.emptySet();
+	}
+
+	public String getExporterIdList() {
+		return exporterIdList;
+	}
+
+	public void setExporterIdList(String exporterIdList) {
+		this.exporterIdList = exporterIdList;
+	}
+
+	@Override
+	public Identity getIdentity() {
+		return identity;
+	}
+
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 2387646 : getKey().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof UserDataExportImpl) {
+			UserDataExportImpl data = (UserDataExportImpl)obj;
+			return getKey() != null && getKey().equals(data.getKey());
+		}
+		return super.equals(obj);
+	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+}
diff --git a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
index d305f7bbf211a97cf35d116457a44cac28c9c1ee..6cd50adbbf21c9bb0547a8c13badb0f1ea7b6a4b 100644
--- a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
+++ b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml
@@ -980,7 +980,7 @@
 					</bean>
 				</entry>
 
-				<entry key="org.olat.course.assessment.EfficiencyStatementArchiver">
+				<entry key="org.olat.course.assessment.manager.EfficiencyStatementArchiver">
 					<bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext">
 						<property name="propertyHandlers">
 							<list>
diff --git a/src/main/java/org/olat/user/restapi/UserVOFactory.java b/src/main/java/org/olat/user/restapi/UserVOFactory.java
index 50e028b1b5d15d0fe5fd492265cac6c570c6f5de..e24f54240d5549f2311307151a5738960d77fc51 100644
--- a/src/main/java/org/olat/user/restapi/UserVOFactory.java
+++ b/src/main/java/org/olat/user/restapi/UserVOFactory.java
@@ -33,6 +33,7 @@ import java.util.Locale;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.User;
@@ -46,7 +47,7 @@ import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nModule;
 import org.olat.user.DisplayPortraitManager;
 import org.olat.user.HomePageConfig;
-import org.olat.user.HomePageConfigManagerImpl;
+import org.olat.user.HomePageConfigManager;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.DatePropertyHandler;
 import org.olat.user.propertyhandlers.GenderPropertyHandler;
@@ -64,7 +65,7 @@ public class UserVOFactory {
 	
 	private static final OLog log = Tracing.createLoggerFor(UserVOFactory.class);
 	
-	public static final String[] keys = new String[] { "male", "female", "-" };
+	private static final String[] keys = new String[] { "male", "female", "-" };
 	
 	public static UserVO get(Identity identity) {
 		return get(identity, I18nModule.getDefaultLocale(), false, false, false);
@@ -95,7 +96,7 @@ public class UserVOFactory {
 		userVO.setEmail(user.getProperty(UserConstants.EMAIL, null));
 		
 		if(withPortrait) {
-			File portrait = DisplayPortraitManager.getInstance().getSmallPortrait(identity.getName());
+			File portrait = CoreSpringFactory.getImpl(DisplayPortraitManager.class).getSmallPortrait(identity.getName());
 			if(portrait != null && portrait.exists()) {
 				try {
 					InputStream input = new FileInputStream(portrait);
@@ -112,7 +113,7 @@ public class UserVOFactory {
 		
 		if(allProperties) {
 			UserManager um = UserManager.getInstance();
-			HomePageConfig hpc = isAdmin ? null : HomePageConfigManagerImpl.getInstance().loadConfigFor(identity.getName());
+			HomePageConfig hpc = isAdmin ? null : CoreSpringFactory.getImpl(HomePageConfigManager.class).loadConfigFor(identity.getName());
 			List<UserPropertyHandler> propertyHandlers = um.getUserPropertyHandlersFor(UserWebService.PROPERTY_HANDLER_IDENTIFIER, false);
 			for (UserPropertyHandler propertyHandler : propertyHandlers) {
 				String propName = propertyHandler.getName();
diff --git a/src/main/java/org/olat/user/restapi/UserWebService.java b/src/main/java/org/olat/user/restapi/UserWebService.java
index e9b3660c554d0f2edb7635df0ac027d166331ad7..217051ed42bbe7ba22c8ad417c645d1e100a206f 100644
--- a/src/main/java/org/olat/user/restapi/UserWebService.java
+++ b/src/main/java/org/olat/user/restapi/UserWebService.java
@@ -555,12 +555,12 @@ public class UserWebService {
 	@Path("{identityKey}/portrait")
 	@Produces({"image/jpeg","image/jpg",MediaType.APPLICATION_OCTET_STREAM})
 	public Response getPortraitHead(@PathParam("identityKey") Long identityKey) {
-		IdentityShort identity = BaseSecurityManager.getInstance().loadIdentityShortByKey(identityKey);
+		IdentityShort identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityShortByKey(identityKey);
 		if(identity == null) {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		}
 		
-		File portrait = DisplayPortraitManager.getInstance().getBigPortrait(identity.getName());
+		File portrait = CoreSpringFactory.getImpl(DisplayPortraitManager.class).getBigPortrait(identity.getName());
 		if(portrait == null || !portrait.exists()) {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		}
@@ -581,12 +581,12 @@ public class UserWebService {
 	@Path("{identityKey}/portrait/{size}")
 	@Produces({"image/jpeg","image/jpg",MediaType.APPLICATION_OCTET_STREAM})
 	public Response getOriginalPortraitHead(@PathParam("identityKey") Long identityKey, @PathParam("size") String size) {
-		IdentityShort identity = BaseSecurityManager.getInstance().loadIdentityShortByKey(identityKey);
+		IdentityShort identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityShortByKey(identityKey);
 		if(identity == null) {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		}
 		
-		DisplayPortraitManager portraitManager = DisplayPortraitManager.getInstance();
+		DisplayPortraitManager portraitManager = CoreSpringFactory.getImpl(DisplayPortraitManager.class);
 		
 		File portrait = null;
 		if("master".equals(size)) {
@@ -617,12 +617,12 @@ public class UserWebService {
 	@Path("{identityKey}/portrait")
 	@Produces({"image/jpeg","image/jpg",MediaType.APPLICATION_OCTET_STREAM})
 	public Response getPortrait(@PathParam("identityKey") Long identityKey, @Context Request request) {
-		IdentityShort identity = BaseSecurityManager.getInstance().loadIdentityShortByKey(identityKey);
+		IdentityShort identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityShortByKey(identityKey);
 		if(identity == null) {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		}
 		
-		File portrait = DisplayPortraitManager.getInstance().getBigPortrait(identity.getName());
+		File portrait = CoreSpringFactory.getImpl(DisplayPortraitManager.class).getBigPortrait(identity.getName());
 		if(portrait == null || !portrait.exists()) {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		}
@@ -652,7 +652,7 @@ public class UserWebService {
 	public Response postPortrait(@PathParam("identityKey") Long identityKey, @Context HttpServletRequest request) {
 		MultipartReader partsReader = null;
 		try {
-			IdentityShort identity = BaseSecurityManager.getInstance().loadIdentityShortByKey(identityKey);
+			IdentityShort identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityShortByKey(identityKey);
 			if(identity == null) {
 				return Response.serverError().status(Status.NOT_FOUND).build();
 			}
@@ -664,7 +664,7 @@ public class UserWebService {
 			partsReader = new MultipartReader(request);
 			File tmpFile = partsReader.getFile();
 			String filename = partsReader.getFilename();
-			DisplayPortraitManager.getInstance().setPortrait(tmpFile, filename, identity.getName());
+			CoreSpringFactory.getImpl(DisplayPortraitManager.class).setPortrait(tmpFile, filename, identity.getName());
 			return Response.ok().build();
 		} catch (Exception e) {
 			throw new WebApplicationException(e);
@@ -685,14 +685,14 @@ public class UserWebService {
 	@Path("{identityKey}/portrait")
 	public Response deletePortrait(@PathParam("identityKey") Long identityKey, @Context HttpServletRequest request) {
 		Identity authIdentity = getUserRequest(request).getIdentity();
-		Identity identity = BaseSecurityManager.getInstance().loadIdentityByKey(identityKey, false);
+		Identity identity = CoreSpringFactory.getImpl(BaseSecurity.class).loadIdentityByKey(identityKey, false);
 		if(identity == null) {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		} else if(!isUserManager(request) && !identity.equalsByPersistableKey(authIdentity)) {
 			return Response.serverError().status(Status.UNAUTHORIZED).build();
 		}
 	
-		DisplayPortraitManager.getInstance().deletePortrait(identity);
+		CoreSpringFactory.getImpl(DisplayPortraitManager.class).deletePortrait(identity);
 		return Response.ok().build();
 	}
 
diff --git a/src/main/java/org/olat/user/ui/data/UserDataController.java b/src/main/java/org/olat/user/ui/data/UserDataController.java
new file mode 100644
index 0000000000000000000000000000000000000000..a48d02b8e282f8bf0431f98549fd314e47d2a1c3
--- /dev/null
+++ b/src/main/java/org/olat/user/ui/data/UserDataController.java
@@ -0,0 +1,81 @@
+package org.olat.user.ui.data;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.id.Identity;
+import org.olat.user.UserDataExport;
+import org.olat.user.UserDataExportService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserDataController extends FormBasicController {
+	
+	private final Identity dataIdentity;
+	
+	private FormLink downloadButton;
+	
+	@Autowired
+	private UserDataExportService userDataExportService;
+	
+	public UserDataController(UserRequest ureq, WindowControl wControl, Identity dataIdentity) {
+		super(ureq, wControl, "user_data");
+		this.dataIdentity = dataIdentity;
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		if(formLayout instanceof FormLayoutContainer) {
+			FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
+			
+			UserDataExport data = userDataExportService.getCurrentData(dataIdentity);
+			layoutCont.contextPut("data", Boolean.valueOf(data != null));
+			if(data == null) {
+				layoutCont.contextPut("dataStatus", UserDataExport.ExportStatus.none.name());
+			} else {
+				layoutCont.contextPut("dataStatus", data.getStatus().name());
+			}
+			
+			downloadButton = uifactory.addFormLink("download.data", layoutCont, Link.BUTTON);
+			downloadButton.setIconLeftCSS("o_icon o_icon_download");
+			downloadButton.setVisible(data != null && data.getStatus() == UserDataExport.ExportStatus.ready);
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(downloadButton == source) {
+			doDownload(ureq);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+	
+	private void doDownload(UserRequest ureq) {
+		MediaResource resource = userDataExportService.getDownload(dataIdentity);
+		ureq.getDispatchResult().setResultingMediaResource(resource);
+	}
+}
diff --git a/src/main/java/org/olat/user/ui/data/UserDataExportController.java b/src/main/java/org/olat/user/ui/data/UserDataExportController.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b4681c7974bf5bd890020bab44e070b17782c8f
--- /dev/null
+++ b/src/main/java/org/olat/user/ui/data/UserDataExportController.java
@@ -0,0 +1,107 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.user.ui.data;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.user.UserDataExportService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserDataExportController extends FormBasicController {
+	
+	private MultipleSelectionElement exportEl;
+	
+	private final Identity identity;
+	
+	@Autowired
+	private UserDataExportService exportService;
+	
+	public UserDataExportController(UserRequest ureq, WindowControl wControl, Identity identity) {
+		super(ureq, wControl);
+		this.identity = identity;
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormDescription("export.user.data.explain");
+		
+		List<String> exportIds = exportService.getExporterIds();
+		String[] keys = new String[exportIds.size()];
+		String[] values = new String[exportIds.size()];
+		for(int i=exportIds.size(); i-->0; ) {
+			String exportId = exportIds.get(i);
+			keys[i] = exportId;
+			values[i] = translate(exportId);
+		}
+		exportEl = uifactory.addCheckboxesVertical("export.options", formLayout, keys, values, 1);
+		exportEl.setMandatory(true);
+		
+		FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonCont);
+		uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("export.start", buttonCont);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
+		if(!exportEl.isAtLeastSelected(1)) {
+			exportEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		}
+		
+		return allOk;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		Collection<String> exportIds = exportEl.getSelectedKeys();
+		exportService.requestExportData(identity, exportIds);
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/user/ui/data/_content/user_data.html b/src/main/java/org/olat/user/ui/data/_content/user_data.html
new file mode 100644
index 0000000000000000000000000000000000000000..e0797b17c2443f6096c246b7c328b91a3e9fbd42
--- /dev/null
+++ b/src/main/java/org/olat/user/ui/data/_content/user_data.html
@@ -0,0 +1,8 @@
+#if($dataStatus == "none")
+	<div class="o_info">$r.translate("export.user.data.none")</div>
+#elseif($dataStatus == "requested" || $dataStatus == "processing")
+	<div class="o_info">$r.translate("export.user.data.processing")</div>
+#elseif($dataStatus == "ready")
+	<div class="o_info">$r.translate("export.user.data.ready")</div>
+	<div class="o_button_group">$r.render("download.data")</div>
+#end
\ No newline at end of file
diff --git a/src/main/java/org/olat/user/ui/data/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/ui/data/_i18n/LocalStrings_de.properties
new file mode 100644
index 0000000000000000000000000000000000000000..e7fee9d06e3cdbca16255b72f5847647a445f7a9
--- /dev/null
+++ b/src/main/java/org/olat/user/ui/data/_i18n/LocalStrings_de.properties
@@ -0,0 +1,15 @@
+#Thu Aug 21 16:31:01 CEST 2014
+calendars=Kalendareinträge
+display.portrait=Profilbild
+download.data=Dateien herunterladen
+efficiency.statements=Leistungnachweise
+notifications=Abonnements
+export.options=Export Elemente
+export.start=Start export
+export.user.data.explain=W\u00E4hlen Sie die Elemente, welche f\u00FCr diesen Benutzer exportiert werden sollen. Der Export kann mehrere Stunde in Anspruch nehmen. Sobald der Export beendet ist werden Sie per Email informiert.
+export.user.data.none=Datenschutz Erkl\u00E4rung
+export.user.data.ready=Sie können es herunterladen
+export.user.data.processing=Ihr Export ist gerade am bauen
+notes=Persönliche Notizen
+personal.folders=Alle Dokumente im private / public Ordner
+
diff --git a/src/main/java/org/olat/user/ui/data/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/user/ui/data/_i18n/LocalStrings_en.properties
new file mode 100644
index 0000000000000000000000000000000000000000..044144e2c290311ee8a33ce1278a63f7cd3e8f60
--- /dev/null
+++ b/src/main/java/org/olat/user/ui/data/_i18n/LocalStrings_en.properties
@@ -0,0 +1,5 @@
+#Wed Nov 20 11:20:19 CET 2013
+download.data=Download the data
+export.options=Export elements
+export.start=Start export
+notifications=Subscriptions
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index f805e6f8f68c6eb52e941686306dcc3c3d85b347..08b33d7c3892b0f790b6a2ac72ef92ca77e5b1a9 100644
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -233,6 +233,7 @@
 		<class>org.olat.portfolio.model.structel.EPStructureElementToGroupRelation</class>
 		<class>org.olat.shibboleth.manager.ShibbolethAutoAccessMethod</class>
 		<class>org.olat.user.UserImpl</class>
+		<class>org.olat.user.model.UserDataExportImpl</class>
 		<properties>
 			<property name="hibernate.generate_statistics" value="true"/>
 			<property name="hibernate.archive.autodetection" value=""/>
diff --git a/src/main/resources/database/mysql/alter_12_4_x_to_12_5_0.sql b/src/main/resources/database/mysql/alter_12_4_x_to_12_5_0.sql
index 36c1baa887b58b96db03eb96d6159906a33c0257..05b4d47a73ce47e22906a1a77c4b89af59af9de2 100644
--- a/src/main/resources/database/mysql/alter_12_4_x_to_12_5_0.sql
+++ b/src/main/resources/database/mysql/alter_12_4_x_to_12_5_0.sql
@@ -77,3 +77,23 @@ update o_user inner join o_bs_identity on (id=fk_identity) set u_organizationalu
 update o_user inner join o_bs_identity on (id=fk_identity) set u_swissedupersonstudybranch1=null where status=199;
 update o_user inner join o_bs_identity on (id=fk_identity) set u_swissedupersonstudybranch2=null where status=199;
 update o_user inner join o_bs_identity on (id=fk_identity) set u_swissedupersonstudybranch3=null where status=199;
+
+
+-- user data export
+create table o_user_data_export (
+   id bigint not null auto_increment,
+   creationdate datetime,
+   lastmodifed datetime,
+   u_directory varchar(255),
+   u_status varchar(16),
+   u_export_ids varchar(2000),
+   fk_identity bigint not null,
+   primary key (id)
+);
+alter table o_user_data_export ENGINE = InnoDB;
+
+alter table o_user_data_export add constraint usr_dataex_to_ident_idx foreign key (fk_identity) references o_bs_identity (id);
+
+
+
+
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 23d89423ba5819731019e18a0856b4a63a8df9df..d07021fa0b2c9a0443190fc2a7f02d94b7efbc10 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -340,6 +340,17 @@ create table if not exists o_userproperty (
    propvalue varchar(255),
    primary key (fk_user_id, propname)
 );
+create table o_user_data_export (
+   id bigint not null auto_increment,
+   creationdate datetime,
+   lastmodified datetime,
+   u_directory varchar(255),
+   u_status varchar(16),
+   u_export_ids varchar(2000),
+   fk_identity bigint not null,
+   primary key (id)
+);
+
 create table if not exists o_message (
    message_id bigint not null,
    version mediumint unsigned not null,
@@ -2716,6 +2727,7 @@ alter table o_repositoryentry_cycle ENGINE = InnoDB;
 alter table o_lti_outcome ENGINE = InnoDB;
 alter table o_user ENGINE = InnoDB;
 alter table o_userproperty ENGINE = InnoDB;
+alter table o_user_data_export ENGINE = InnoDB;
 alter table o_message ENGINE = InnoDB;
 alter table o_temporarykey ENGINE = InnoDB;
 alter table o_bs_authentication ENGINE = InnoDB;
@@ -2957,6 +2969,8 @@ create index idx_user_creationdate_idx on o_user (creationdate);
 alter table o_user add constraint user_to_ident_idx foreign key (fk_identity) references o_bs_identity(id);
 alter table o_user add constraint idx_un_user_to_ident_idx UNIQUE (fk_identity);
 
+alter table o_user_data_export add constraint usr_dataex_to_ident_idx foreign key (fk_identity) references o_bs_identity (id);
+
 -- csp
 create index idx_csp_log_to_ident_idx on o_csp_log (fk_identity);
 
diff --git a/src/main/resources/database/oracle/alter_12_4_x_to_12_5_0.sql b/src/main/resources/database/oracle/alter_12_4_x_to_12_5_0.sql
index 863a3fd6e082ecb209e2e0208e36e81e879170ed..ac0b3dd83b18785f85cdb9e2092bd5199dc8a13c 100644
--- a/src/main/resources/database/oracle/alter_12_4_x_to_12_5_0.sql
+++ b/src/main/resources/database/oracle/alter_12_4_x_to_12_5_0.sql
@@ -78,3 +78,23 @@ update o_user set u_organizationalunit=null where exists (select id from o_bs_id
 update o_user set u_swissedupersonstudybranch1=null where exists (select id from o_bs_identity where id=fk_identity and status=199);
 update o_user set u_swissedupersonstudybranch2=null where exists (select id from o_bs_identity where id=fk_identity and status=199);
 update o_user set u_swissedupersonstudybranch3=null where exists (select id from o_bs_identity where id=fk_identity and status=199);
+
+
+-- user data export
+create table o_user_data_export (
+  id number(20) generated always as identity,
+   creationdate date,
+   lastmodified date,
+   u_directory varchar(255),
+   u_status varchar(16),
+   u_export_ids varchar(2000),
+   fk_identity number(20) not null,
+   primary key (id)
+);
+
+alter table o_user_data_export add constraint usr_dataex_to_ident_idx foreign key (fk_identity) references o_bs_identity (id);
+create index idx_usr_dataex_to_ident_idx on o_user_data_export (fk_identity);
+
+
+
+
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 1cf06d614888984e4cf9f4869b83c050ed47df57..f3cf2d0a6c8522f54b3f207d83c2c9aac9f87d8a 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -375,6 +375,16 @@ CREATE TABLE o_userproperty (
   PRIMARY KEY (fk_user_id, propname)
 );
 
+CREATE TABLE o_user_data_export (
+  id number(20) generated always as identity,
+   creationdate date,
+   lastmodified date,
+   u_directory varchar(255),
+   u_status varchar(16),
+   u_export_ids varchar(2000),
+   fk_identity number(20) not null,
+   PRIMARY KEY (id)
+);
 
 CREATE TABLE o_message (
   message_id number(20) NOT NULL,
@@ -2974,6 +2984,9 @@ alter table o_user add constraint user_to_ident_idx foreign key (fk_identity) re
 create index idx_user_to_ident_idx on o_user (fk_identity);
 alter table o_user add constraint idx_un_user_to_ident_idx UNIQUE (fk_identity);
 
+alter table o_user_data_export add constraint usr_dataex_to_ident_idx foreign key (fk_identity) references o_bs_identity (id);
+create index idx_usr_dataex_to_ident_idx on o_user_data_export (fk_identity);
+
 -- csp
 create index idx_csp_log_to_ident_idx on o_csp_log (fk_identity);
 
diff --git a/src/main/resources/database/postgresql/alter_12_4_x_to_12_5_0.sql b/src/main/resources/database/postgresql/alter_12_4_x_to_12_5_0.sql
index 59968f8bfe02e34bfc3d41ff6545fdea08b9bb62..02177e3beceb67e2a451e003b2b72ca8a2f4aaa0 100644
--- a/src/main/resources/database/postgresql/alter_12_4_x_to_12_5_0.sql
+++ b/src/main/resources/database/postgresql/alter_12_4_x_to_12_5_0.sql
@@ -77,3 +77,20 @@ update o_user set u_organizationalunit=null from o_bs_identity where id=fk_ident
 update o_user set u_swissedupersonstudybranch1=null from o_bs_identity where id=fk_identity and status=199;
 update o_user set u_swissedupersonstudybranch2=null from o_bs_identity where id=fk_identity and status=199;
 update o_user set u_swissedupersonstudybranch3=null from o_bs_identity where id=fk_identity and status=199;
+
+
+-- user data export
+create table o_user_data_export (
+   id bigserial,
+   creationdate timestamp,
+   lastmodified timestamp,
+   u_directory varchar(255),
+   u_status varchar(16),
+   u_export_ids varchar(2000),
+   fk_identity int8 not null,
+   primary key (id)
+);
+
+alter table o_user_data_export add constraint usr_dataex_to_ident_idx foreign key (fk_identity) references o_bs_identity (id);
+create index idx_usr_dataex_to_ident_idx on o_user_data_export (fk_identity);
+
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 21201729d109240b0bf4c56855476a2b1cf945d8..27e6f87e1f1724cf231e8a9ae5bdae8431740d30 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -338,6 +338,17 @@ create table o_userproperty (
    propvalue varchar(255),
    primary key (fk_user_id, propname)
 );
+create table o_user_data_export (
+   id bigserial,
+   creationdate timestamp,
+   lastmodified timestamp,
+   u_directory varchar(255),
+   u_status varchar(16),
+   u_export_ids varchar(2000),
+   fk_identity int8 not null,
+   primary key (id)
+);
+
 create table o_message (
    message_id int8 not null,
    version int4 not null,
@@ -2819,6 +2830,9 @@ alter table o_user add constraint user_to_ident_idx foreign key (fk_identity) re
 create index idx_user_to_ident_idx on o_user (fk_identity);
 alter table o_user add constraint idx_un_user_to_ident_idx UNIQUE (fk_identity);
 
+alter table o_user_data_export add constraint usr_dataex_to_ident_idx foreign key (fk_identity) references o_bs_identity (id);
+create index idx_usr_dataex_to_ident_idx on o_user_data_export (fk_identity);
+
 -- csp
 create index idx_csp_log_to_ident_idx on o_csp_log (fk_identity);
 
diff --git a/src/test/java/org/olat/core/util/coordinate/DBPersistentLockManagerTest.java b/src/test/java/org/olat/core/util/coordinate/DBPersistentLockManagerTest.java
index ed8f4a7b792c59eccc1045d14ea2a04a3d758fb8..78f212c649ca6cec9c68de0d9f663c0a317cea75 100644
--- a/src/test/java/org/olat/core/util/coordinate/DBPersistentLockManagerTest.java
+++ b/src/test/java/org/olat/core/util/coordinate/DBPersistentLockManagerTest.java
@@ -91,7 +91,7 @@ public class DBPersistentLockManagerTest extends OlatTestCase {
 		Assert.assertTrue(lock.isSuccess());
 		
 		//delete the owner
-		lockManager.deleteUserData(owner, "", null);
+		lockManager.deleteUserData(owner, "");
 		dbInstance.commit();
 		
 		//next can acquire the lock
diff --git a/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java b/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java
index 152bcb9941ba24ca13462339c23b89bfb6629833..3ec0bd08079d91bfd65e723d7b09761d7e4867ab 100644
--- a/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java
+++ b/src/test/java/org/olat/core/util/mail/manager/MailManagerTest.java
@@ -258,10 +258,10 @@ public class MailManagerTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 
 		//delete the 4 users datas
-		mailBoxExtension.deleteUserData(toId_1, "lalala", null);
-		mailBoxExtension.deleteUserData(toId_2, "lalala", null);
-		mailBoxExtension.deleteUserData(toId_3, "lalala", null);
-		mailBoxExtension.deleteUserData(fromId, "lalala", null);
+		mailBoxExtension.deleteUserData(toId_1, "lalala");
+		mailBoxExtension.deleteUserData(toId_2, "lalala");
+		mailBoxExtension.deleteUserData(toId_3, "lalala");
+		mailBoxExtension.deleteUserData(fromId, "lalala");
 		dbInstance.commitAndCloseSession();
 		
 		//check inbox / outbox
@@ -324,10 +324,10 @@ public class MailManagerTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 
 		//delete the 4 users datas
-		mailBoxExtension.deleteUserData(fromId, "lalala", null);
-		mailBoxExtension.deleteUserData(toId_1, "lalala", null);
-		mailBoxExtension.deleteUserData(toId_2, "lalala", null);
-		mailBoxExtension.deleteUserData(toId_3, "lalala", null);
+		mailBoxExtension.deleteUserData(fromId, "lalala");
+		mailBoxExtension.deleteUserData(toId_1, "lalala");
+		mailBoxExtension.deleteUserData(toId_2, "lalala");
+		mailBoxExtension.deleteUserData(toId_3, "lalala");
 		dbInstance.commitAndCloseSession();
 
 		//check mail by meta id
diff --git a/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java b/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java
index 5d2322c165c850b2925be1eb4c7409c63a2489d2..30a4c47c9e59ee914cd42e689d40ffa1792844eb 100644
--- a/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java
+++ b/src/test/java/org/olat/course/assessment/AssessmentManagerTest.java
@@ -37,6 +37,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import org.junit.Assert;
@@ -63,6 +64,7 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
+import org.olat.user.manager.ManifestBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -221,8 +223,9 @@ public class AssessmentManagerTest extends OlatTestCase  {
 			if(archiveDir.exists()) {
 				archiveDir.delete();
 				if(archiveDir.mkdir()) {
-				  efficiencyStatementManager.archiveUserData(student, archiveDir);
-				  log.info("Archived EfficiencyStatement path: " + archiveDir.getAbsolutePath());
+					ManifestBuilder manifest = ManifestBuilder.createBuilder();
+					efficiencyStatementManager.export(student, manifest, archiveDir, Locale.GERMAN);
+					log.info("Archived EfficiencyStatement path: " + archiveDir.getAbsolutePath());
 				}
 			}
 		} catch (IOException e) {
diff --git a/src/test/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletableTest.java b/src/test/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletableTest.java
index a7dcc79fbde55a4e852335d8a4e2cb6704497514..3b9da3ecf67a4a87b92a7fefdded05f618ae156c 100644
--- a/src/test/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletableTest.java
+++ b/src/test/java/org/olat/modules/qpool/manager/QuestionPoolUserDataDeletableTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.io.File;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -58,8 +57,6 @@ public class QuestionPoolUserDataDeletableTest {
 	@Mock
 	private QuestionItemAuditLogBuilder auditLogBuilderMock;
 	
-	@Mock
-	private File archivePathDummy;
 	@Mock
 	private Identity identityDummy;
 	@Mock
@@ -86,7 +83,7 @@ public class QuestionPoolUserDataDeletableTest {
 	public void shouldDeleteQuestionsOfUserIfEnabled() {
 		when(qpoolModuleMock.isDeleteQuestionsWithoutAuthor()).thenReturn(true);
 
-		sut.deleteUserData(identityDummy, newDeletedUserName, archivePathDummy);
+		sut.deleteUserData(identityDummy, newDeletedUserName);
 		
 		verify(qpoolServiceMock).deleteItems(itemsDummy);
 	}
@@ -95,7 +92,7 @@ public class QuestionPoolUserDataDeletableTest {
 	public void shouldNotDeleteQuestionsOfUserIfNotEnabled() {
 		when(qpoolModuleMock.isDeleteQuestionsWithoutAuthor()).thenReturn(false);
 
-		sut.deleteUserData(identityDummy, newDeletedUserName, archivePathDummy);
+		sut.deleteUserData(identityDummy, newDeletedUserName);
 		
 		verify(qpoolServiceMock, never()).deleteItems(itemsDummy);
 	}
diff --git a/src/test/java/org/olat/properties/PropertyTest.java b/src/test/java/org/olat/properties/PropertyTest.java
index aef24041b8ecf430d10653b678313ee084c63960..e03e754e8876ea8c31a0023a19e96a10f37efceb 100644
--- a/src/test/java/org/olat/properties/PropertyTest.java
+++ b/src/test/java/org/olat/properties/PropertyTest.java
@@ -237,7 +237,7 @@ public class PropertyTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 		
 		//delete user 1 datas
-		pm.deleteUserData(id1, "del-" + id1.getName(), null);
+		pm.deleteUserData(id1, "del-" + id1.getName());
 		dbInstance.commitAndCloseSession();
 		
 		//check if really deleted
diff --git a/src/test/java/org/olat/restapi/UserMgmtTest.java b/src/test/java/org/olat/restapi/UserMgmtTest.java
index 44eba95c7054327aa7fed3e33ae642a377a24f43..dafd34b8418621d60a6ef114335d27fc29654c0e 100644
--- a/src/test/java/org/olat/restapi/UserMgmtTest.java
+++ b/src/test/java/org/olat/restapi/UserMgmtTest.java
@@ -152,6 +152,8 @@ public class UserMgmtTest extends OlatJerseyTestCase {
 	private RepositoryService repositoryService;
 	@Autowired
 	private UserManager userManager;
+	@Autowired
+	private DisplayPortraitManager portraitManager;
 	
 	@Before
 	@Override
@@ -1608,8 +1610,7 @@ public class UserMgmtTest extends OlatJerseyTestCase {
 
 		
 		//check if big and small portraits exist
-		DisplayPortraitManager dps = DisplayPortraitManager.getInstance();
-		File bigPortrait = dps.getBigPortrait(id1.getName());
+		File bigPortrait = portraitManager.getBigPortrait(id1.getName());
 		assertNotNull(bigPortrait);
 		assertTrue(bigPortrait.exists());
 		assertTrue(bigPortrait.exists());
@@ -1628,7 +1629,7 @@ public class UserMgmtTest extends OlatJerseyTestCase {
 		
 		assertEquals(-1, b);//up to end of file
 		assertTrue(count > 1000);//enough bytes
-		bigPortrait = dps.getBigPortrait(id1.getName());
+		bigPortrait = portraitManager.getBigPortrait(id1.getName());
 		assertNotNull(bigPortrait);
 		assertEquals(count, bigPortrait.length());
 
@@ -1644,7 +1645,7 @@ public class UserMgmtTest extends OlatJerseyTestCase {
 		assertNotNull(datas);
 		assertTrue(datas.length > 0);
 		
-		File smallPortrait = dps.getSmallPortrait(id1.getName());
+		File smallPortrait = portraitManager.getSmallPortrait(id1.getName());
 		assertNotNull(smallPortrait);
 		assertEquals(datas.length, smallPortrait.length());
 		
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 54a89849007cc1404f1e69afda96d298a83d7457..ec92a61f72027198d59534adfec89a845b743138 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -131,6 +131,8 @@ import org.junit.runners.Suite;
 	org.olat.user.UserDAOTest.class,
 	org.olat.user.UserManagerTest.class,
 	org.olat.user.UserNameAndPasswordSyntaxCheckerWithRegexpTest.class,
+	org.olat.user.manager.UserDataExportDAOTest.class,
+	org.olat.user.manager.UserDataExportServiceTest.class,
 	org.olat.repository.manager.RepositoryEntryDAOTest.class,
 	org.olat.repository.manager.RepositoryEntryLifecycleDAOTest.class,
 	org.olat.repository.manager.RepositoryEntryRelationDAOTest.class,
diff --git a/src/test/java/org/olat/user/manager/UserDataExportDAOTest.java b/src/test/java/org/olat/user/manager/UserDataExportDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a779371e2f18fc4a35342687d81f90fe39372602
--- /dev/null
+++ b/src/test/java/org/olat/user/manager/UserDataExportDAOTest.java
@@ -0,0 +1,86 @@
+package org.olat.user.manager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.olat.user.UserDataExport;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserDataExportDAOTest extends OlatTestCase {
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private UserDataExportDAO userDataExportDao;
+	
+	@Test
+	public void createExport() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("exp-1");
+		Collection<String> exporters = Collections.singletonList("test");
+		UserDataExport data = userDataExportDao.createExport(identity, exporters, UserDataExport.ExportStatus.requested);
+		dbInstance.commit();
+		
+		Assert.assertNotNull(data);
+		Assert.assertNotNull(data.getKey());
+		Assert.assertNotNull(data.getCreationDate());
+		Assert.assertNotNull(data.getLastModified());
+		Assert.assertNotNull(data.getDirectory());
+		Assert.assertEquals(identity, data.getIdentity());
+		Assert.assertEquals(1, data.getExportIds().size());
+		Assert.assertEquals("test", data.getExportIds().iterator().next());
+		Assert.assertEquals(UserDataExport.ExportStatus.requested, data.getStatus());
+	}
+	
+	@Test
+	public void loadByKey() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("exp-1");
+		Collection<String> exporters = Collections.singletonList("test");
+		UserDataExport data = userDataExportDao.createExport(identity, exporters, UserDataExport.ExportStatus.requested);
+		dbInstance.commitAndCloseSession();
+		
+		UserDataExport reloadedData = userDataExportDao.loadByKey(data.getKey());
+		
+		Assert.assertNotNull(reloadedData);
+		Assert.assertEquals(data, reloadedData);
+		Assert.assertNotNull(reloadedData.getCreationDate());
+		Assert.assertNotNull(reloadedData.getLastModified());
+		Assert.assertEquals(data.getDirectory(), reloadedData.getDirectory());
+		Assert.assertEquals(identity, reloadedData.getIdentity());
+		Assert.assertEquals(UserDataExport.ExportStatus.requested, reloadedData.getStatus());
+	}
+	
+	@Test
+	public void getUserDataExport() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("exp-1");
+		Collection<String> exporters = Collections.singletonList("test");
+		UserDataExport requestedData = userDataExportDao.createExport(identity, exporters, UserDataExport.ExportStatus.requested);
+		UserDataExport readyData = userDataExportDao.createExport(identity, exporters, UserDataExport.ExportStatus.ready);
+		dbInstance.commitAndCloseSession();
+		
+		List<UserDataExport.ExportStatus> runningStatus = new ArrayList<>();
+		runningStatus.add(UserDataExport.ExportStatus.requested);
+		runningStatus.add(UserDataExport.ExportStatus.processing);
+		List<UserDataExport> runningExports = userDataExportDao.getUserDataExport(identity, runningStatus);
+		Assert.assertNotNull(runningExports);
+		Assert.assertEquals(1, runningExports.size());
+		Assert.assertEquals(requestedData, runningExports.get(0));
+		Assert.assertFalse(runningExports.contains(readyData));
+	}
+	
+
+
+}
diff --git a/src/test/java/org/olat/user/manager/UserDataExportServiceTest.java b/src/test/java/org/olat/user/manager/UserDataExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfe43c57eee914eb85537cec76ca9d6de90557cd
--- /dev/null
+++ b/src/test/java/org/olat/user/manager/UserDataExportServiceTest.java
@@ -0,0 +1,42 @@
+package org.olat.user.manager;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.olat.user.UserDataExport;
+import org.olat.user.UserDataExportService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+
+/**
+ * 
+ * Initial date: 23 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserDataExportServiceTest extends OlatTestCase {
+
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private UserDataExportDAO userDataExportDao;
+	@Autowired
+	private UserDataExportService exportService;
+	
+	@Test
+	public void exportUserData() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("exp-1");
+		Collection<String> exportIds = Collections.singletonList("efficiency.statements");
+		UserDataExport data = userDataExportDao.createExport(identity, exportIds, UserDataExport.ExportStatus.requested);
+		dbInstance.commitAndCloseSession();
+		
+		// trigger the method manually
+		exportService.exportData(data.getKey());
+	}
+
+}