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()); + } + +}