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 22f1e189f3aee6e68073f0d3c560b13230e58015..bd81c47caa7b14c1e8692273678a02391d0e74bd 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
@@ -31,9 +31,6 @@ import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
-import org.olat.user.UserDataDeletable;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -49,9 +46,7 @@ import org.springframework.stereotype.Service;
  * @author gnaegi
  */
 @Service
-public class CommentAndRatingServiceImpl implements CommentAndRatingService, UserDataDeletable {
-	
-	private static final OLog log = Tracing.createLoggerFor(CommentAndRatingServiceImpl.class);
+public class CommentAndRatingServiceImpl implements CommentAndRatingService {
 
 	@Autowired
 	private UserRatingsDAO userRatingsDao;
@@ -173,14 +168,6 @@ public class CommentAndRatingServiceImpl implements CommentAndRatingService, Use
 		return delCount;
 	}
 
-	@Override
-	public void deleteUserData(Identity identity, String newDeletedUserName) {
-		int rows = userRatingsDao.deleteRatings(identity);
-		log.audit(rows + " rating deleted");
-		int comments = userCommentsDao.deleteAllComments(identity);
-		log.audit(comments + " rating erased");
-	}
-
 	private void markPublisherNews(UserComment comment) {
 		if (comment == null) return;
 
diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingUserDataManager.java b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingUserDataManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..340cf012054babdb1da12c5e1781c11adc29a8e5
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/CommentAndRatingUserDataManager.java
@@ -0,0 +1,225 @@
+/**
+ * <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.core.commons.services.commentAndRating.manager;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.commentAndRating.model.UserComment;
+import org.olat.core.commons.services.commentAndRating.model.UserRating;
+import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.BusinessControlFactory;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
+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.modules.portfolio.Binder;
+import org.olat.modules.portfolio.Page;
+import org.olat.modules.portfolio.manager.PageDAO;
+import org.olat.modules.qpool.QuestionItem;
+import org.olat.modules.qpool.manager.QuestionItemDAO;
+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;
+
+/**
+ * 
+ * Initial date: 28 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class CommentAndRatingUserDataManager implements UserDataDeletable, UserDataExportable {
+	
+	private static final OLog log = Tracing.createLoggerFor(CommentAndRatingUserDataManager.class);
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private PageDAO pageDao;
+	@Autowired
+	private QuestionItemDAO questionItemDao;
+	@Autowired
+	private UserRatingsDAO userRatingsDao;
+	@Autowired
+	private UserCommentsDAO userCommentsDao;
+	@Autowired
+	private RepositoryManager repositoryManager;
+	
+	@Override
+	public void deleteUserData(Identity identity, String newDeletedUserName) {
+		int rows = userRatingsDao.deleteRatings(identity);
+		log.audit(rows + " rating deleted");
+		int comments = userCommentsDao.deleteAllComments(identity);
+		log.audit(comments + " rating erased");
+	}
+
+	@Override
+	public String getExporterID() {
+		return "comments.ratings";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		exportRatings(identity, manifest, archiveDirectory);
+		exportComments(identity, manifest, archiveDirectory);
+	}
+	
+	private void exportComments(Identity identity, ManifestBuilder manifest, File archiveDirectory) {
+		List<UserComment> comments = userCommentsDao.getComments(identity);
+		if(comments == null || comments.isEmpty()) return;
+		dbInstance.commitAndCloseSession();
+		
+		File noteArchive = new File(archiveDirectory, "Comments.xlsx");
+		try(OutputStream out = new FileOutputStream(noteArchive);
+			OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1)) {
+			OpenXMLWorksheet sheet = workbook.nextWorksheet();
+			sheet.setHeaderRows(1);
+			
+			Row header = sheet.newRow();
+			header.addCell(0, "Comment");
+			header.addCell(1, "Resource");
+			header.addCell(2, "URL");
+			
+			for(UserComment comment:comments) {
+				Row row = sheet.newRow();
+				row.addCell(0, comment.getComment());
+				Location location = resolveLocation(comment.getResName(), comment.getResId());
+				if(StringHelper.containsNonWhitespace(location.getName())) {
+					row.addCell(1, location.getName());
+				}
+				if(StringHelper.containsNonWhitespace(location.getUrl())) {
+					row.addCell(2, location.getUrl());
+				}
+			}
+		} catch (IOException e) {
+			log.error("Unable to export xlsx", e);
+		}
+		manifest.appendFile("Bookings.xlsx");
+	}
+	
+	private void exportRatings(Identity identity, ManifestBuilder manifest, File archiveDirectory) {
+		List<UserRating> ratings = userRatingsDao.getAllRatings(identity);
+		if(ratings == null || ratings.isEmpty()) return;
+		dbInstance.commitAndCloseSession();
+		
+		File ratingsArchive = new File(archiveDirectory, "Ratings.xlsx");
+		try(OutputStream out = new FileOutputStream(ratingsArchive);
+			OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1)) {
+			OpenXMLWorksheet sheet = workbook.nextWorksheet();
+			sheet.setHeaderRows(1);
+			
+			Row header = sheet.newRow();
+			header.addCell(0, "Rating");
+			header.addCell(1, "Resource");
+			header.addCell(2, "URL");
+			
+			for(UserRating rating:ratings) {
+				Row row = sheet.newRow();
+				row.addCell(0, rating.getRating().toString());
+				Location location = resolveLocation(rating.getResName(), rating.getResId());
+				if(StringHelper.containsNonWhitespace(location.getName())) {
+					row.addCell(1, location.getName());
+				}
+				if(StringHelper.containsNonWhitespace(location.getUrl())) {
+					row.addCell(2, location.getUrl());
+				}
+			}
+		} catch (IOException e) {
+			log.error("Unable to export xlsx", e);
+		}
+		manifest.appendFile("Bookings.xlsx");
+	}
+	
+	private Location resolveLocation (String resName, Long resId) {
+		String name = null;
+		String businessPath = null;
+		if("RepositoryEntry".equals(resName)) {
+			RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(resId, false);
+			if(entry != null) {
+				name = entry.getDisplayname();
+				businessPath = "[RepositoryEntry:" + entry.getKey() + "]";
+			}
+		} else if("QuestionItem".equals(resName)) {
+			QuestionItem item = questionItemDao.loadById(resId);
+			if(item != null) {
+				name = item.getTitle();
+				businessPath = "[QPool:0][QuestionItem:" + item.getKey() + "]";
+			}
+		} else if("Page".equals(resName)) {
+			Page page = pageDao.loadByKey(resId);
+			if(page != null) {
+				name = page.getTitle();
+				if(page.getSection() != null) {
+					Binder binder = page.getSection().getBinder();
+					businessPath = "[PortfolioV2:0][Binder:" + binder.getKey() + "][Entries:0][Entry:" + page.getKey() + "]";
+				} else {
+					businessPath = "[PortfolioV2:0][MyPages:0][Entry:" + page.getKey() + "]";
+				}
+			}
+		} else if("EPDefaultMap".equals(resName)) {
+			name = "Mappe (v 1.0)";
+		} else if("LibrarySite".equals(resName)) {
+			name = "Library";
+		} else {
+			OLATResourceable resourceable = OresHelper.createOLATResourceableInstance(resName, resId);
+			RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(resourceable, false);
+			if(entry != null) {
+				name = entry.getDisplayname();
+				businessPath = "[RepositoryEntry:" + entry.getKey() + "]";
+			}
+		}
+
+		String url = BusinessControlFactory.getInstance().getURLFromBusinessPathString(businessPath);
+		return new Location(name, url);
+	}
+	
+	private static class Location {
+		
+		private final String name;
+		private final String url;
+		
+		public Location(String name, String url) {
+			this.url = url;
+			this.name = name;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public String getUrl() {
+			return url;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserCommentsDAO.java b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserCommentsDAO.java
index 80d50d90d91b29b555764c6d4851ded622f3a3a6..1cc11bab16bc910ea22de2c238582534b092102a 100644
--- a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserCommentsDAO.java
+++ b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserCommentsDAO.java
@@ -30,7 +30,6 @@ import javax.persistence.TypedQuery;
 
 import org.olat.basesecurity.IdentityRef;
 import org.olat.core.commons.persistence.DB;
-import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.commons.services.commentAndRating.CommentAndRatingLoggingAction;
 import org.olat.core.commons.services.commentAndRating.UserCommentsDelegate;
 import org.olat.core.commons.services.commentAndRating.model.UserComment;
@@ -104,10 +103,10 @@ public class UserCommentsDAO {
 		TypedQuery<UserComment> query;
 		if (resSubPath == null) {
 			// special query when sub path is null
-			query = DBFactory.getInstance().getCurrentEntityManager()
+			query = dbInstance.getCurrentEntityManager()
 					.createQuery("select comment from usercomment as comment where resName=:resname AND resId=:resId AND resSubPath is NULL", UserComment.class);
 		} else {
-			query = DBFactory.getInstance().getCurrentEntityManager()
+			query = dbInstance.getCurrentEntityManager()
 					.createQuery("select comment from usercomment as comment where resName=:resname AND resId=:resId AND resSubPath=:resSubPath", UserComment.class)
 					.setParameter("resSubPath", resSubPath);
 		}
@@ -115,6 +114,14 @@ public class UserCommentsDAO {
 		     .setParameter("resId", ores.getResourceableId())
 		     .getResultList();
 	}
+	
+	public List<UserComment> getComments(IdentityRef identity) {
+		String  query = "select comment from usercomment as comment where comment.creator.key=:identityKey";
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(query, UserComment.class)
+				.setParameter("identityKey", identity.getKey())
+				.getResultList();
+	}
 
 	public UserComment updateComment(UserComment comment, String newCommentText) {
 		// First reload parent from cache to prevent stale object or cache issues
@@ -200,10 +207,10 @@ public class UserCommentsDAO {
 		TypedQuery<Number> query;
 		if (resSubPath == null) {
 			// special query when sub path is null
-			query = DBFactory.getInstance().getCurrentEntityManager()
+			query = dbInstance.getCurrentEntityManager()
 					.createQuery("select count(*) from usercomment where resName=:resname AND resId=:resId AND resSubPath is NULL", Number.class);
 		} else {
-			query = DBFactory.getInstance().getCurrentEntityManager()
+			query = dbInstance.getCurrentEntityManager()
 					.createQuery("select count(*) from usercomment where resName=:resname AND resId=:resId AND resSubPath=:resSubPath", Number.class)
 					.setParameter("resSubPath", resSubPath);
 		}
diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserRatingsDAO.java b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserRatingsDAO.java
index eb265ee4e36f79705037db35c962486430c25bb8..be36e55e9acf04720df0ac67bdfdb7cad9701c60 100644
--- a/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserRatingsDAO.java
+++ b/src/main/java/org/olat/core/commons/services/commentAndRating/manager/UserRatingsDAO.java
@@ -85,6 +85,14 @@ public class UserRatingsDAO {
 		     .setHint("org.hibernate.cacheable", Boolean.TRUE)
 		     .getResultList();
 	}
+
+	public List<UserRating> getAllRatings(IdentityRef identity) {
+		String sb = "select rating from userrating as rating where rating.creator.key=:identityKey";
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb, UserRating.class)
+				.setParameter("identityKey", identity.getKey())
+				.getResultList();
+	}
 	
 	public float getRatingAverage(OLATResourceable ores, String resSubPath) {
 		StringBuilder sb = new StringBuilder();
diff --git a/src/main/java/org/olat/core/gui/DefaultGlobalSettings.java b/src/main/java/org/olat/core/gui/DefaultGlobalSettings.java
index e0c340647916554bc81d4e546dfedf1376e86e70..50f569e62010316ff6306c9cc4ecd8a8cc9b885e 100644
--- a/src/main/java/org/olat/core/gui/DefaultGlobalSettings.java
+++ b/src/main/java/org/olat/core/gui/DefaultGlobalSettings.java
@@ -1,3 +1,22 @@
+/**
+ * <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.core.gui;
 
 import org.olat.core.gui.control.winmgr.AJAXFlags;
diff --git a/src/main/java/org/olat/core/util/FileUtils.java b/src/main/java/org/olat/core/util/FileUtils.java
index 62a71d5060545fa0e36729d7040b83f42a88d2d0..e417066549ea1c414cbd85e8f1e481dec1beb797 100644
--- a/src/main/java/org/olat/core/util/FileUtils.java
+++ b/src/main/java/org/olat/core/util/FileUtils.java
@@ -50,11 +50,14 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.commons.io.IOUtils;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.OLATRuntimeException;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.filters.SystemItemFilter;
 import org.springframework.core.io.Resource;
 
 
@@ -136,6 +139,35 @@ public class FileUtils {
 	public static boolean copyFileToDir(File sourceFile, File targetDir, String wt) {
 		return copyFileToDir(sourceFile, targetDir, false, null, wt);
 	}
+	
+	/**
+	 * 
+	 * @param source The source
+	 * @param targetDirectory The directory to copy the source in
+	 * @param wt A message
+	 * @return True if ok
+	 */
+	public static boolean copyItemToDir(VFSItem source, File targetDirectory, String wt) {
+		targetDirectory.mkdirs();
+
+		File target = new File(targetDirectory, source.getName());
+		if(source instanceof VFSLeaf) {
+			try(InputStream inStream = ((VFSLeaf)source).getInputStream();
+					OutputStream outStream = new FileOutputStream(target)) {
+				bcopy(inStream, outStream, wt);
+			} catch(IOException ex) {
+				log.error("", ex);
+				return false;
+			}
+		} else if(source instanceof VFSContainer) {
+			target.mkdir();
+			List<VFSItem> items = ((VFSContainer)source).getItems(new SystemItemFilter());
+			for(VFSItem item:items) {
+				copyItemToDir(item, target, wt);
+			}
+		}
+		return true;
+	}
 
 	/**
 	 * @param sourceFile
@@ -403,23 +435,20 @@ public class FileUtils {
 		return true;
 	} // end copy
 	
-	public static boolean copyToFile(InputStream in, File targetFile, String wt) {
+	public static boolean copyToFile(InputStream in, File targetFile, String wt) throws IOException {
 		if (targetFile.isDirectory()) return false;
 		
 		// create target directories
 		targetFile.getParentFile().mkdirs(); // don't check for success... would return false on
-		
-		BufferedInputStream  bis = new BufferedInputStream(in);
-		try (OutputStream dst = new FileOutputStream(targetFile);
+
+		try(BufferedInputStream  bis = new BufferedInputStream(in);
+				OutputStream dst = new FileOutputStream(targetFile);
 				BufferedOutputStream bos = getBos (dst)) {
 			cpio (bis, bos, wt);
 			bos.flush();
 			return true;
 		} catch (IOException e) {
-			throw new RuntimeException("I/O error in cpio "+wt);
-		} finally {
-			IOUtils.closeQuietly(bis);
-			IOUtils.closeQuietly(in);
+			throw e;
 		}
 	}
 	
diff --git a/src/main/java/org/olat/course/nodes/gta/GTAManager.java b/src/main/java/org/olat/course/nodes/gta/GTAManager.java
index 0499a8f79fd9f8c63b5e1e6ad4a3e6f8cbda6484..0140879b7c4ff4ed11ff0e03dd7aafa29f15941c 100644
--- a/src/main/java/org/olat/course/nodes/gta/GTAManager.java
+++ b/src/main/java/org/olat/course/nodes/gta/GTAManager.java
@@ -271,6 +271,8 @@ public interface GTAManager {
 
 	public List<Task> getTasks(TaskList taskList, GTACourseNode gtaNode);
 	
+	public List<Task> getTasks(IdentityRef identity);
+	
 	public List<TaskLight> getTasksLight(RepositoryEntryRef entry, GTACourseNode gtaNode);
 	
 	public List<TaskRevisionDate> getTaskRevisions(Task task);
diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
index c0150d07c9a2cbfb46491ee9aea7e60bcb9191e0..f871cb355a65bac4aec6a8bf4076eceb0381e7e1 100644
--- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
@@ -90,7 +90,6 @@ import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupRef;
 import org.olat.group.BusinessGroupService;
-import org.olat.group.DeletableGroupData;
 import org.olat.group.area.BGAreaManager;
 import org.olat.group.manager.BusinessGroupRelationDAO;
 import org.olat.group.model.BusinessGroupRefImpl;
@@ -117,7 +116,7 @@ import com.thoughtworks.xstream.XStream;
  *
  */
 @Service
-public class GTAManagerImpl implements GTAManager, DeletableGroupData {
+public class GTAManagerImpl implements GTAManager {
 	
 	private static final OLog log = Tracing.createLoggerFor(GTAManagerImpl.class);
 	
@@ -735,17 +734,6 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData {
 
 		return tasks.isEmpty() ? null : tasks.get(0);
 	}
-	
-	@Override
-	public boolean deleteGroupDataFor(BusinessGroup group) {
-		log.audit("Delete tasks of business group: " + group.getKey());
-		String deleteTasks = "delete from gtatask as task where task.businessGroup.key=:groupKey";
-		dbInstance.getCurrentEntityManager()
-				.createQuery(deleteTasks)
-				.setParameter("groupKey", group.getKey())
-				.executeUpdate();
-		return true;
-	}
 
 	@Override
 	public int deleteTaskList(RepositoryEntryRef entry, GTACourseNode cNode) {
@@ -813,6 +801,19 @@ public class GTAManagerImpl implements GTAManager, DeletableGroupData {
 				.setParameter("taskListKey", taskList.getKey())
 				.getResultList();
 	}
+	
+	@Override
+	public List<Task> getTasks(IdentityRef identity) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select task from gtatask task")
+		  .append(" inner join task.taskList as tasklist")
+		  .append(" inner join tasklist.entry as entry")
+		  .append(" where task.identity.key=:identityKey");
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Task.class)
+				.setParameter("identityKey", identity.getKey())
+				.getResultList();
+	}
 
 	@Override
 	public List<TaskLight> getTasksLight(RepositoryEntryRef entry, GTACourseNode gtaNode) {
diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAUserDataManager.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAUserDataManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c5d1962622009499d30c9bfe540907d41ff3771
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAUserDataManager.java
@@ -0,0 +1,140 @@
+/**
+ * <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.course.nodes.gta.manager;
+
+import java.io.File;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.DB;
+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.StringHelper;
+import org.olat.core.util.io.SystemFileFilter;
+import org.olat.course.CorruptedCourseException;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.nodes.CourseNode;
+import org.olat.course.nodes.GTACourseNode;
+import org.olat.course.nodes.gta.GTAManager;
+import org.olat.course.nodes.gta.Task;
+import org.olat.course.nodes.gta.TaskList;
+import org.olat.group.BusinessGroup;
+import org.olat.group.DeletableGroupData;
+import org.olat.modules.ModuleConfiguration;
+import org.olat.user.UserDataExportable;
+import org.olat.user.manager.ManifestBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 28 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class GTAUserDataManager implements DeletableGroupData, UserDataExportable {
+	
+	private static final OLog log = Tracing.createLoggerFor(GTAUserDataManager.class);
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private GTAManager gtaManager;
+	
+	@Override
+	public boolean deleteGroupDataFor(BusinessGroup group) {
+		log.audit("Delete tasks of business group: " + group.getKey());
+		String deleteTasks = "delete from gtatask as task where task.businessGroup.key=:groupKey";
+		dbInstance.getCurrentEntityManager()
+				.createQuery(deleteTasks)
+				.setParameter("groupKey", group.getKey())
+				.executeUpdate();
+		return true;
+	}
+
+
+	@Override
+	public String getExporterID() {
+		return "gta";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		File tasksArchiveDir = new File(archiveDirectory, "Tasks");
+		tasksArchiveDir.mkdir();
+		
+		List<Task> tasks = gtaManager.getTasks(identity);
+		for(Task task:tasks) {
+			try {
+				TaskList taskList = task.getTaskList();
+				ICourse course = CourseFactory.loadCourse(taskList.getEntry());
+				if(course == null) continue;
+				
+				CourseNode node = course.getRunStructure().getNode(taskList.getCourseNodeIdent());
+				if(node instanceof GTACourseNode) {
+					String archiveName = node.getIdent() + "_" + StringHelper.transformDisplayNameToFileSystemName(node.getShortName());
+					File taskArchiveDir = new File(tasksArchiveDir, archiveName); 
+					exportTask(identity, task, (GTACourseNode)node, course, taskArchiveDir);
+				}
+			} catch (CorruptedCourseException e) {
+				log.warn("", e);
+			}
+		}
+	}
+	
+	private void exportTask(Identity assessedIdentity, Task task, GTACourseNode node , ICourse course, File taskArchiveDir) {
+		int flow = 0;//for beautiful ordering
+		ModuleConfiguration config = node.getModuleConfiguration();
+		if(config.getBooleanSafe(GTACourseNode.GTASK_SUBMIT)) {
+			File submitDirectory = gtaManager.getSubmitDirectory(course.getCourseEnvironment(), node, assessedIdentity);
+			String submissionDirName = (++flow) + "_submissions";
+			copyDirContentToDir(submitDirectory, new File(taskArchiveDir, submissionDirName));
+		}
+
+		if(config.getBooleanSafe(GTACourseNode.GTASK_REVIEW_AND_CORRECTION)) {
+			File correctionsDir = gtaManager.getCorrectionDirectory(course.getCourseEnvironment(), node, assessedIdentity);
+			String correctionDirName = (++flow) + "_corrections";
+			copyDirContentToDir(correctionsDir, new File(taskArchiveDir, correctionDirName));
+		}
+		
+		if(task != null && config.getBooleanSafe(GTACourseNode.GTASK_REVISION_PERIOD)) {
+			int numOfIteration = task.getRevisionLoop();
+			for(int i=1; i<=numOfIteration; i++) {
+				File revisionDirectory = gtaManager.getRevisedDocumentsDirectory(course.getCourseEnvironment(), node, i, assessedIdentity);
+				String revisionDirName = (++flow) + "_revisions_" + i;
+				copyDirContentToDir(revisionDirectory, new File(taskArchiveDir, revisionDirName));
+			}
+		}
+	}
+	
+	private void copyDirContentToDir(File source, File target) {
+		File[] sourceFiles = source.listFiles(new SystemFileFilter(true, true));
+		if(sourceFiles != null && sourceFiles.length > 0) {
+			target.mkdirs();
+			for(File sourceFile:sourceFiles) {
+				FileUtils.copyFileToDir(sourceFile, target, "");
+			}
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/statistic/export/UserDataLogExporter.java b/src/main/java/org/olat/course/statistic/export/UserDataLogExporter.java
new file mode 100644
index 0000000000000000000000000000000000000000..415bd35593f01ef429e21013281dd38971620801
--- /dev/null
+++ b/src/main/java/org/olat/course/statistic/export/UserDataLogExporter.java
@@ -0,0 +1,124 @@
+/**
+ * <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.course.statistic.export;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Locale;
+
+import javax.persistence.EntityManager;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.logging.activity.LoggingObject;
+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.user.UserDataExportable;
+import org.olat.user.manager.ManifestBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 29 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class UserDataLogExporter implements UserDataExportable {
+	
+	private static final OLog log = Tracing.createLoggerFor(UserDataLogExporter.class);
+
+	@Autowired
+	private DB dbInstance;
+	
+	@Override
+	public String getExporterID() {
+		return "logs";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		File profileArchive = new File(archiveDirectory, "Log.xlsx");
+		try(OutputStream out = new FileOutputStream(profileArchive);
+			OpenXMLWorkbook workbook = new OpenXMLWorkbook(out, 1)) {
+			OpenXMLWorksheet sheet = workbook.nextWorksheet();
+			
+			Row header = sheet.newRow();
+			header.addCell(0, "Date");
+			header.addCell(1, "Action");
+			header.addCell(2, "Verb");
+			header.addCell(3, "Object");
+			header.addCell(4, "Duration");
+			header.addCell(5, "Administrative");
+			header.addCell(6, "Path");
+			header.addCell(7, "Target name");
+			header.addCell(8, "Target type");
+			header.addCell(9, "Parent name");
+			header.addCell(10, "Parent type");
+
+			EntityManager em = dbInstance.getCurrentEntityManager();
+			em.clear();
+
+			String query = "select v from loggingobject as v where v.userId=:identityKey";
+			List<LoggingObject> queryResult = em.createQuery(query, LoggingObject.class)
+					.setParameter("identityKey", identity.getKey())
+					.getResultList();
+			int count = 0;
+			for (LoggingObject loggingObject : queryResult) {
+
+				Row row = sheet.newRow();
+				row.addCell(0, loggingObject.getCreationDate(), workbook.getStyles().getDateTimeStyle());
+				row.addCell(1, loggingObject.getActionCrudType());
+				row.addCell(2, loggingObject.getActionVerb());
+				row.addCell(3, loggingObject.getActionObject());
+				row.addCell(4, String.valueOf(loggingObject.getSimpleDuration()));
+				if(loggingObject.getResourceAdminAction() != null) {
+					row.addCell(5, loggingObject.getResourceAdminAction().toString());
+				}
+				row.addCell(6, loggingObject.getBusinessPath());
+				writeData(loggingObject.getTargetResName(), loggingObject.getTargetResType(), identity, row, 7);
+				writeData(loggingObject.getParentResName(), loggingObject.getParentResType(), identity, row, 9);
+
+				if(count++ % 1000 == 0) {
+					out.flush();
+					em.clear();
+				}
+			}
+		} catch (IOException e) {
+			log.error("Unable to export xlsx", e);
+		}
+		manifest.appendFile(profileArchive.getName());
+	}
+	
+	private void writeData(String resName, String resType, Identity identity, Row row, int col) {
+		row.addCell(col, resType);
+		if("targetIdentity".equals(resType)) {
+			resName = resName.equals(identity.getName()) ? resName : "";
+		}
+		row.addCell(col + 1, resName);
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioUserDataManager.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioUserDataManager.java
index 5e36df4bb2c036c1b3f77d120d89cef0f96e0281..d7f3adcfbab660d1428cc374413e8e7f4beb39e6 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioUserDataManager.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioUserDataManager.java
@@ -1,3 +1,22 @@
+/**
+ * <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.modules.portfolio.manager;
 
 import java.io.File;
diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java
index 7a16614fd789aea359b217a2b6bd5bc2a6051c69..1c73badc207bbf6a8eae4c69b5af26f7d4b8d129 100644
--- a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java
+++ b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java
@@ -99,9 +99,6 @@ public class FeedManagerImpl extends FeedManager {
 	// 10 minutes
 	private static final int EXTERNAL_FEED_ACTUALIZATION_MILLIS = 10*60*1000;
 
-	public static final String KIND_PODCAST = "podcast";
-	public static final String KIND_BLOG = "blog";
-
 	private RepositoryManager repositoryManager;
 	private Coordinator coordinator;
 	private OLATResourceManager resourceManager;
diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedUserDataManager.java b/src/main/java/org/olat/modules/webFeed/manager/FeedUserDataManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..b627ee785f29525c6cdf88c6a7c74daa8f861799
--- /dev/null
+++ b/src/main/java/org/olat/modules/webFeed/manager/FeedUserDataManager.java
@@ -0,0 +1,135 @@
+/**
+ * <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.modules.webFeed.manager;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.gui.DefaultGlobalSettings;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.render.EmptyURLBuilder;
+import org.olat.core.gui.render.RenderResult;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.velocity.VelocityRenderDecorator;
+import org.olat.core.gui.translator.Translator;
+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.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.filters.SystemItemFilter;
+import org.olat.modules.portfolio.ui.MediaCenterController;
+import org.olat.modules.webFeed.Item;
+import org.olat.user.UserDataExportable;
+import org.olat.user.manager.ManifestBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 28 mai 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class FeedUserDataManager implements UserDataExportable {
+	
+	private static final OLog log = Tracing.createLoggerFor(FeedUserDataManager.class);
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private ItemDAO itemDao;
+	@Autowired
+	private FeedManager feedManager;
+
+	@Override
+	public String getExporterID() {
+		return "feeds";
+	}
+
+	@Override
+	public void export(Identity identity, ManifestBuilder manifest, File archiveDirectory, Locale locale) {
+		List<Item> items = itemDao.loadItemsByAuthor(identity);
+		dbInstance.commitAndCloseSession();
+		
+		File itemsDirectory = new File(archiveDirectory, "blogspodcasts");
+		itemsDirectory.mkdir();
+		for(Item item:items) {
+			export(item, itemsDirectory, locale);
+		}
+	}
+	
+	private void export(Item item, File itemsDirectory, Locale locale) {
+		String title = StringHelper.transformDisplayNameToFileSystemName(item.getTitle());
+		String name = item.getKey() + "_" + title;
+		File itemDir = new File(itemsDirectory, name);
+		itemDir.mkdir();
+
+		VFSContainer itemContainer = feedManager.getItemContainer(item);
+		List<File> attachments = new ArrayList<>();
+		if(itemContainer != null) {
+			List<VFSItem> attachmentItems = itemContainer.getItems(new SystemItemFilter());
+			for(VFSItem attachmentItem:attachmentItems) {
+				FileUtils.copyItemToDir(attachmentItem, itemDir, "Copy blog/podcast files");
+				attachments.add(new File(itemDir, attachmentItem.getName()));
+			}
+		}
+		
+		File mediaFile = new File(itemDir, "index.html");
+		try(OutputStream out = new FileOutputStream(mediaFile)) {
+			String content = exportContent(item, attachments, locale);
+			out.write(content.getBytes("UTF-8"));
+			out.flush();
+		} catch(IOException e) {
+			log.error("", e);
+		}
+	}
+
+	private String exportContent(Item item,  List<File> attachments, Locale locale) {
+		StringOutput sb = new StringOutput(10000);
+		Translator translator = Util.createPackageTranslator(MediaCenterController.class, locale);
+		String pagePath = Util.getPackageVelocityRoot(FeedUserDataManager.class) + "/export_item.html";
+		VelocityContainer component = new VelocityContainer("html", pagePath, translator, null);
+		component.contextPut("item", item);
+		component.contextPut("content", item.getContent());
+		component.contextPut("attachments", attachments);
+
+		Renderer renderer = Renderer.getInstance(component, translator, new EmptyURLBuilder(), new RenderResult(), new DefaultGlobalSettings());
+		try(VelocityRenderDecorator vrdec = new VelocityRenderDecorator(renderer, component, sb)) {
+			component.contextPut("r", vrdec);
+			renderer.render(sb, component, null);
+		} catch(IOException e) {
+			log.error("", e);
+		}
+		return sb.toString();
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java b/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java
index cac85bbc27767b1a2bbd770441b5049ccd745e20..f65fee6615e48bdcce2c0c0ca8b8da9284f7d200 100644
--- a/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java
+++ b/src/main/java/org/olat/modules/webFeed/manager/ItemDAO.java
@@ -26,6 +26,7 @@ import java.util.stream.Collectors;
 
 import javax.persistence.TypedQuery;
 
+import org.olat.basesecurity.IdentityRef;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.util.StringHelper;
 import org.olat.modules.webFeed.Feed;
@@ -194,6 +195,13 @@ public class ItemDAO {
 		return query.getResultList();
 	}
 	
+	public List<Item> loadItemsByAuthor(IdentityRef author) {
+		return dbInstance.getCurrentEntityManager()
+			.createNamedQuery("loadItemsByAuthorWithFeed", Item.class)
+			.setParameter("authorKey", author.getKey())
+			.getResultList();
+	}
+	
 	/**
 	 * Loads all items of a feed.
 	 * 
diff --git a/src/main/java/org/olat/modules/webFeed/manager/_content/export_item.html b/src/main/java/org/olat/modules/webFeed/manager/_content/export_item.html
new file mode 100644
index 0000000000000000000000000000000000000000..a40b00ae8c888e9aca7bb4fc79fb6bf837a53784
--- /dev/null
+++ b/src/main/java/org/olat/modules/webFeed/manager/_content/export_item.html
@@ -0,0 +1,40 @@
+<html>
+	<head>
+		<title>$r.escapeHtml($item.title)</title>
+		<meta http-equiv="Content-type" content="text/html; charset=utf-8">
+		<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
+		<script>
+		jQuery(function() {
+			jQuery("video").each(function(index, el) {
+				el.attr("controls", "");
+			});
+			jQuery("audio").each(function(index, el) {
+				el.attr("controls", "");
+			});
+		});
+		</script>
+	</head>
+	<body>
+		<h4>$r.escapeHtml($item.title)</h4>
+		#if($r.isNotEmpty($item.description))
+			$r.xssScan($item.description)
+		#end
+		#if($r.isNotEmpty($item.enclosure) && $r.isNotEmpty($item.enclosure.fileName))
+			#if($item.getEnclosure().getType().startsWith("video/"))
+				<video width="$item.width" height="$item.height" controls>
+					<source src="media/$item.enclosure.fileName" type="$item.enclosure.type">
+				</video>
+			#elseif($item.getEnclosure().getType().startsWith("audio/")) 
+				<audio controls>
+					<source src="media/$item.enclosure.fileName" type="$item.enclosure.type">
+				</video>
+			#else
+				<a href="media/$item.enclosure.fileName" targe="_blanck">$item.enclosure.fileName</a>
+			#end
+		#end
+		#if($r.isNotEmpty($item.content))
+			$r.xssScan($item.content)
+		#end
+	
+	</body>
+</html>
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java b/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java
index 571d22bc7b4e97dddf0325aef8fc9a943617d9ae..f945f225218ef1b030b46eda1eb5ee8eb8d2cb16 100644
--- a/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java
+++ b/src/main/java/org/olat/modules/webFeed/model/ItemImpl.java
@@ -62,6 +62,8 @@ import org.olat.user.UserManager;
 			query="select data from item data where data.guid=:guid"),
 	@NamedQuery(name="loadItemsByFeed",
 		query="select data from item data where data.feed=:feed"),
+	@NamedQuery(name="loadItemsByAuthorWithFeed",
+		query="select data from item data inner join fetch data.feed as feed where data.authorKey=:authorKey"),
 	@NamedQuery(name="loadItemsGuidByFeed",
 		query="select guid from item data where data.feed=:feed"),
 	@NamedQuery(name="removeItem",
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java
index 9a82b3e44109b0b6389a49e2275bd786f18fdec7..d7c6cd50540d318fb8e5a07725f16cecfd55a6c5 100644
--- a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java
@@ -777,13 +777,13 @@ public class ACFrontendManager implements ACService, UserDataExportable {
 			OpenXMLWorksheet sheet = workbook.nextWorksheet();
 			sheet.setHeaderRows(1);
 			
-			Row row = sheet.newRow();
-			row.addCell(0, "Status");
-			row.addCell(1, "Booking number");
-			row.addCell(2, "Date");
-			row.addCell(3, "Content");
-			row.addCell(4, "Method");
-			row.addCell(5, "Total");
+			Row header = sheet.newRow();
+			header.addCell(0, "Status");
+			header.addCell(1, "Booking number");
+			header.addCell(2, "Date");
+			header.addCell(3, "Content");
+			header.addCell(4, "Method");
+			header.addCell(5, "Total");
 			
 			List<OrderTableItem> orders = findOrderItems(null, identity, null, null, null, null, 0, -1, null);
 			for(OrderTableItem order:orders) {
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
index 54789b0ca66ae672eda538f475899e67156879b1..3ec6006af26e30538b7304a61fd840af4d969b56 100644
--- 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
@@ -4,6 +4,7 @@ bookings=Buchungen
 calendars=Kalendareintr\u00E4ge
 certificates=Certifikaten
 chat=Chat
+comments.ratings=Kommentaren und Bewertungen
 disclaimer=Nutzungsbedigung
 display.portrait=Profilbild
 download.data=Dateien herunterladen
@@ -18,8 +19,11 @@ export.user.data.processing=Der Export ist gerade bearbeitet.
 export.user.data.ready=Der Benutzer kann den Export mit dem folgenden Link herunterladen. Sie k\u00F6nnen auch ein en neuen Export erfordern.
 export.user.data.ready.subject=Export von "{0}" ist fertig
 export.user.data.ready.text=<p>Export von "{0}" ist fertig. Es konnte unter <a href\="{1}">{1}</a> heruntergeladen werden</p>
+feeds=Blogs und Podcasts
 forums=Foren
 group.memberships=Zugeh\u00F6rigkeit zu Gruppen
+gta=Aufgabe
+logs=Logs
 mail=Mail
 notes=Pers\u00F6nliche Notizen
 notifications=Abonnements
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
index 6236b054fd31aa7d67bf1b3fd4e6940e253e72f9..5bb571cb71e8a72f0332bf3afe057d43fd5a0066 100644
--- 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
@@ -4,19 +4,22 @@ bookings=Bookings
 calendars=Calendars
 certificates=Certificates
 chat=Chat messages
+comments.ratings=Comments and ratings
 disclaimer=Disclaimer
 display.portrait=Published image
 download.data=Download the data
-dx=dr
-dy=dr
 efficiency.statements=Evidences of achievement
 export.options=Export elements
 export.start=Start export
 export.url=Link to the data
+feeds=Blogs and podcasts
 forums=Forums
 group.memberships=Membership to groups
+gta=Tasks
+logs=Logs
 mail=Emails
 notes=Notes
 notifications=Subscriptions
 personal.folders=All documents in private and public folders
 repository.memberships=Membership to courses
+