From dd0bfaba82ac42a3cb01976ae360f2f8f43da71c Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Wed, 28 Nov 2012 14:45:43 +0100 Subject: [PATCH] OO-428: implements deduplicate tool for course and groups --- .../progressbar/ProgressController.java | 75 ++++++++++++ .../progressbar/_content/progress.html | 4 + .../generic/iframe/IFrameDeliveryMapper.java | 19 +++ .../core/util/async/ProgressDelegate.java | 34 ++++++ .../member/MembersOverviewController.java | 47 +++++++- .../member/_content/members_overview.html | 3 + .../member/_i18n/LocalStrings_de.properties | 2 + .../org/olat/group/BusinessGroupService.java | 9 ++ .../manager/BusinessGroupServiceImpl.java | 92 ++++++++++++++ .../BusinessGroupModuleAdminController.java | 112 ++++++++++++++++-- .../org/olat/group/ui/_content/bg_admin.html | 13 ++ .../group/ui/_i18n/LocalStrings_de.properties | 4 + .../DedupMembersConfirmationController.java | 91 ++++++++++++++ .../olat/group/ui/main/_content/dedup.html | 3 + .../ui/main/_i18n/LocalStrings_de.properties | 5 + .../olat/repository/RepositoryManager.java | 2 - .../java/org/olat/user/restapi/RolesVO.java | 19 +++ .../document/file/OfficeDocumentTest.java | 19 +++ 18 files changed, 541 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/olat/core/gui/components/progressbar/ProgressController.java create mode 100644 src/main/java/org/olat/core/gui/components/progressbar/_content/progress.html create mode 100644 src/main/java/org/olat/core/util/async/ProgressDelegate.java create mode 100644 src/main/java/org/olat/group/ui/_content/bg_admin.html create mode 100644 src/main/java/org/olat/group/ui/main/DedupMembersConfirmationController.java create mode 100644 src/main/java/org/olat/group/ui/main/_content/dedup.html diff --git a/src/main/java/org/olat/core/gui/components/progressbar/ProgressController.java b/src/main/java/org/olat/core/gui/components/progressbar/ProgressController.java new file mode 100644 index 00000000000..77a9c0d593f --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/progressbar/ProgressController.java @@ -0,0 +1,75 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.gui.components.progressbar; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.velocity.VelocityContainer; +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.util.async.ProgressDelegate; + +/** + * A controller which use a procentual progress bar filled at 100% at start. + * + * Initial date: 28.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class ProgressController extends BasicController implements ProgressDelegate { + + private final VelocityContainer mainVC; + private final ProgressBar progressBar; + + public ProgressController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl); + + mainVC = createVelocityContainer("progress"); + progressBar = new ProgressBar("dedup", 600, 0.0f, 100.0f, "%"); + progressBar.setActual(100.0f); + mainVC.put("progress", progressBar); + putInitialPanel(mainVC); + } + + @Override + protected void doDispose() { + // + } + + public void setMessage(String translatedMsg) { + mainVC.contextPut("msg", translatedMsg); + } + + @Override + public void setActual(float i) { + progressBar.setActual(i); + } + + @Override + public void finished() { + progressBar.setActual(0.0f); + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + // + } +} diff --git a/src/main/java/org/olat/core/gui/components/progressbar/_content/progress.html b/src/main/java/org/olat/core/gui/components/progressbar/_content/progress.html new file mode 100644 index 00000000000..8cba9133801 --- /dev/null +++ b/src/main/java/org/olat/core/gui/components/progressbar/_content/progress.html @@ -0,0 +1,4 @@ +#if($msg) +<p>$msg</p> +#end +$r.render("progress") \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java index 1abd65cb897..90637100c71 100644 --- a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java +++ b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java @@ -1,3 +1,22 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.core.gui.control.generic.iframe; import java.io.Serializable; diff --git a/src/main/java/org/olat/core/util/async/ProgressDelegate.java b/src/main/java/org/olat/core/util/async/ProgressDelegate.java new file mode 100644 index 00000000000..2e060fef023 --- /dev/null +++ b/src/main/java/org/olat/core/util/async/ProgressDelegate.java @@ -0,0 +1,34 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.util.async; + +/** + * + * Initial date: 28.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface ProgressDelegate { + + public void setActual(float value); + + public void finished(); + +} diff --git a/src/main/java/org/olat/course/member/MembersOverviewController.java b/src/main/java/org/olat/course/member/MembersOverviewController.java index f9de2c94df4..241aec8081f 100644 --- a/src/main/java/org/olat/course/member/MembersOverviewController.java +++ b/src/main/java/org/olat/course/member/MembersOverviewController.java @@ -35,6 +35,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.gui.control.generic.wizard.Step; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; @@ -57,6 +58,7 @@ import org.olat.course.member.wizard.ImportMember_1a_LoginListStep; import org.olat.course.member.wizard.ImportMember_1b_ChooseMemberStep; import org.olat.group.BusinessGroupService; import org.olat.group.model.BusinessGroupMembershipChange; +import org.olat.group.ui.main.DedupMembersConfirmationController; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.model.RepositoryEntryPermissionChangeEvent; @@ -88,9 +90,11 @@ public class MembersOverviewController extends BasicController implements Activa private AbstractMemberListController waitingCtrl; private AbstractMemberListController selectedCtrl; private AbstractMemberListController searchCtrl; - private final Link importMemberLink, addMemberLink; - + private final Link importMemberLink, addMemberLink, dedupLink; + + private CloseableModalController cmc; private StepsMainRunController importMembersWizard; + private DedupMembersConfirmationController dedupCtrl; private final RepositoryEntry repoEntry; private final RepositoryManager repositoryManager; @@ -118,12 +122,14 @@ public class MembersOverviewController extends BasicController implements Activa searchLink = LinkFactory.createLink("search", mainVC, this); segmentView.addSegment(searchLink, false); - updateAllMembers(ureq); + selectedCtrl = updateAllMembers(ureq); addMemberLink = LinkFactory.createButton("add.member", mainVC, this); mainVC.put("addMembers", addMemberLink); importMemberLink = LinkFactory.createButton("import.member", mainVC, this); mainVC.put("importMembers", importMemberLink); + dedupLink = LinkFactory.createButton("dedup.members", mainVC, this); + mainVC.put("dedupMembers", dedupLink); putInitialPanel(mainVC); } @@ -185,6 +191,8 @@ public class MembersOverviewController extends BasicController implements Activa doChooseMembers(ureq); } else if (source == importMemberLink) { doImportMembers(ureq); + } else if (source == dedupLink) { + doDedupMembers(ureq); } } @@ -201,9 +209,24 @@ public class MembersOverviewController extends BasicController implements Activa } } } + } else if(source == dedupCtrl) { + cmc.deactivate(); + if(event == Event.DONE_EVENT) { + dedupMembers(ureq, dedupCtrl.isDedupCoaches(), dedupCtrl.isDedupParticipants()); + } + cleanUp(); + } else if(source == cmc) { + cleanUp(); } super.event(ureq, source, event); } + + private void cleanUp() { + removeAsListenerAndDispose(dedupCtrl); + removeAsListenerAndDispose(cmc); + dedupCtrl = null; + cmc = null; + } private void doChooseMembers(UserRequest ureq) { removeAsListenerAndDispose(importMembersWizard); @@ -265,6 +288,24 @@ public class MembersOverviewController extends BasicController implements Activa switchToAllMembers(ureq); } + protected void doDedupMembers(UserRequest ureq) { + dedupCtrl = new DedupMembersConfirmationController(ureq, getWindowControl()); + listenTo(dedupCtrl); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), dedupCtrl.getInitialComponent(), + true, translate("dedup.members")); + cmc.activate(); + listenTo(cmc); + } + + protected void dedupMembers(UserRequest ureq, boolean coaches, boolean participants) { + businessGroupService.dedupMembers(ureq.getIdentity(), repoEntry, coaches, participants); + showInfo("dedup.done"); + if(selectedCtrl != null) { + selectedCtrl.reloadModel(); + } + } + private void switchToAllMembers(UserRequest ureq) { DBFactory.getInstance().commit();//make sure all is on the DB before reloading if(selectedCtrl != null && selectedCtrl == allMemberListCtrl) { diff --git a/src/main/java/org/olat/course/member/_content/members_overview.html b/src/main/java/org/olat/course/member/_content/members_overview.html index 77bd534159b..c0a3a83a73e 100644 --- a/src/main/java/org/olat/course/member/_content/members_overview.html +++ b/src/main/java/org/olat/course/member/_content/members_overview.html @@ -5,6 +5,9 @@ #if($r.available("importMembers")) $r.render("importMembers") #end + #if($r.available("dedupMembers")) + $r.render("dedupMembers") + #end </div> <h4 class="b_with_small_icon_left b_group_icon"> $r.translate("menu.members") diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties index 68887a36c01..f1ef8e18224 100644 --- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties @@ -5,6 +5,8 @@ assessment=Bewertungswerkzeug course.lastTime=Zuletzt ge\u00F6fnnet course.membership.creation=Kurs Beitritt course.numOfVisits=Anzahl Kursaufrufe +dedup.members=Mitglieder deduplizieren +dedup.done=Deduplizierung wurde erfolgreich beendet dialog.modal.bg.leave.text=Wollen Sie wirklich die Person(en) {0} aus dem Kurs und allen Gruppen entfernen? edit.member=Mitglied bearbeiten edit.member.groups=Gruppenmitgliedschaften diff --git a/src/main/java/org/olat/group/BusinessGroupService.java b/src/main/java/org/olat/group/BusinessGroupService.java index 55829e071db..9f686b127a0 100644 --- a/src/main/java/org/olat/group/BusinessGroupService.java +++ b/src/main/java/org/olat/group/BusinessGroupService.java @@ -26,6 +26,7 @@ import java.util.Locale; import org.olat.basesecurity.SecurityGroup; import org.olat.core.id.Identity; +import org.olat.core.util.async.ProgressDelegate; import org.olat.core.util.mail.MailerResult; import org.olat.group.area.BGArea; import org.olat.group.model.BGRepositoryEntryRelation; @@ -443,6 +444,14 @@ public interface BusinessGroupService { public BusinessGroupAddResponse addToSecurityGroupAndFireEvent(Identity ureqIdentity, List<Identity> addIdentities, SecurityGroup secGroup); public void removeAndFireEvent(Identity ureqIdentity, List<Identity> addIdentities, SecurityGroup secGroup); + + /** + * Remove the members of the repository entry which are already in a business group + * linked to it. + */ + public void dedupMembers(Identity ureqIdentity, RepositoryEntry entry, boolean coaches, boolean participants); + + public void dedupMembers(Identity ureqIdentity, boolean coaches, boolean participants, ProgressDelegate progressDelegate); //security diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java index af78d25836e..d89660ba55c 100644 --- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java +++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java @@ -46,12 +46,14 @@ import org.olat.collaboration.CollaborationToolsFactory; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.taskExecutor.TaskExecutorManager; import org.olat.core.id.Identity; +import org.olat.core.id.Roles; import org.olat.core.logging.DBRuntimeException; import org.olat.core.logging.KnownIssueException; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.logging.activity.ActionType; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; +import org.olat.core.util.async.ProgressDelegate; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.mail.MailContext; import org.olat.core.util.mail.MailContextImpl; @@ -98,6 +100,8 @@ import org.olat.instantMessaging.syncservice.SyncUserListTask; import org.olat.properties.Property; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryShort; +import org.olat.repository.RepositoryManager; +import org.olat.repository.SearchRepositoryEntryParameters; import org.olat.resource.OLATResource; import org.olat.resource.accesscontrol.ACService; import org.olat.resource.accesscontrol.model.ResourceReservation; @@ -124,6 +128,8 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD @Autowired private BusinessGroupDAO businessGroupDAO; @Autowired + private RepositoryManager repositoryManager; + @Autowired private BaseSecurity securityManager; @Autowired private BusinessGroupRelationDAO businessGroupRelationDAO; @@ -1371,6 +1377,92 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } } + @Override + public void dedupMembers(Identity ureqIdentity, boolean coaches, boolean participants, ProgressDelegate delegate) { + SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(); + params.setRoles(new Roles(true, false, false, false, false, false, false)); + params.setResourceTypes(Collections.singletonList("CourseModule")); + + float ratio = -1.0f; + if(delegate != null) { + int numOfEntries = repositoryManager.countGenericANDQueryWithRolesRestriction(params, true); + ratio = 100.0f / (float)numOfEntries; + } + + int counter = 0; + int countForCommit = 0; + float actual = 100.0f; + int batch = 25; + List<RepositoryEntry> entries; + do { + entries = repositoryManager.genericANDQueryWithRolesRestriction(params, counter, batch, true); + for(RepositoryEntry re:entries) { + countForCommit += dedupSingleRepositoryentry(ureqIdentity, re, coaches, participants); + if(countForCommit > 25) { + dbInstance.intermediateCommit(); + countForCommit = 0; + } + } + counter += entries.size(); + if(delegate != null) { + actual -= (entries.size() * ratio); + delegate.setActual(actual); + } + } while(entries.size() == batch); + + if(delegate != null) { + delegate.finished(); + } + } + + @Override + @Transactional + public void dedupMembers(Identity ureqIdentity, RepositoryEntry entry, boolean coaches, boolean participants) { + dedupSingleRepositoryentry(ureqIdentity, entry, coaches, participants); + } + + private int dedupSingleRepositoryentry(Identity ureqIdentity, RepositoryEntry entry, boolean coaches, boolean participants) { + int count = 0; + + List<BusinessGroup> groups = null;//load only if needed + if(coaches) { + List<Identity> repoTutorList = securityManager.getIdentitiesOfSecurityGroup(entry.getTutorGroup()); + if(!repoTutorList.isEmpty()) { + SearchBusinessGroupParams params = new SearchBusinessGroupParams(); + groups = businessGroupDAO.findBusinessGroups(params, entry.getOlatResource(), 0, -1); + List<SecurityGroup> ownerSecGroups = new ArrayList<SecurityGroup>(); + for(BusinessGroup group:groups) { + ownerSecGroups.add(group.getOwnerGroup()); + } + + List<Identity> ownerList = securityManager.getIdentitiesOfSecurityGroups(ownerSecGroups); + repoTutorList.retainAll(ownerList); + repositoryManager.removeTutors(null, repoTutorList, entry); + count += repoTutorList.size(); + } + } + + if(participants) { + List<Identity> repoParticipantList = securityManager.getIdentitiesOfSecurityGroup(entry.getParticipantGroup()); + if(!repoParticipantList.isEmpty()) { + + if(groups == null) { + SearchBusinessGroupParams params = new SearchBusinessGroupParams(); + groups = businessGroupDAO.findBusinessGroups(params, entry.getOlatResource(), 0, -1); + } + List<SecurityGroup> participantSecGroups = new ArrayList<SecurityGroup>(); + for(BusinessGroup group:groups) { + participantSecGroups.add(group.getPartipiciantGroup()); + } + List<Identity> participantList = securityManager.getIdentitiesOfSecurityGroups(participantSecGroups); + repoParticipantList.retainAll(participantList); + repositoryManager.removeParticipants(ureqIdentity, repoParticipantList, entry); + count += participantList.size(); + } + } + return 2 + count; + } + @Override @Transactional public void removeResourceFrom(BusinessGroup group, RepositoryEntry re) { diff --git a/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java b/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java index b570fcecd83..e99d4169f4a 100644 --- a/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java +++ b/src/main/java/org/olat/group/ui/BusinessGroupModuleAdminController.java @@ -20,42 +20,61 @@ package org.olat.group.ui; import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.taskExecutor.TaskExecutorManager; 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.elements.MultipleSelectionElement; 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.components.panel.Panel; +import org.olat.core.gui.components.progressbar.ProgressController; 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.generic.closablewrapper.CloseableModalController; +import org.olat.core.util.async.ProgressDelegate; import org.olat.group.BusinessGroupModule; +import org.olat.group.BusinessGroupService; +import org.olat.group.ui.main.DedupMembersConfirmationController; /** * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class BusinessGroupModuleAdminController extends FormBasicController { +public class BusinessGroupModuleAdminController extends FormBasicController implements ProgressDelegate { + private FormLink dedupLink; private MultipleSelectionElement allowEl; + + private Panel mainPopPanel; + private CloseableModalController cmc; + private ProgressController progressCtrl; + private DedupMembersConfirmationController dedupCtrl; private final BusinessGroupModule module; + private final BusinessGroupService businessGroupService; private String[] onKeys = new String[]{"user","author"}; public BusinessGroupModuleAdminController(UserRequest ureq, WindowControl wControl) { - super(ureq, wControl); + super(ureq, wControl, "bg_admin"); module = CoreSpringFactory.getImpl(BusinessGroupModule.class); + businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class); initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - setFormTitle("module.admin.title"); - setFormDescription("module.admin.desc"); - + FormLayoutContainer optionsContainer = FormLayoutContainer.createDefaultFormLayout("options", getTranslator()); + formLayout.add(optionsContainer); String[] values = new String[]{ translate("user.allow.create"), translate("author.allow.create") }; - allowEl = uifactory.addCheckboxesVertical("module.admin.allow.create", formLayout, onKeys, values, null, 1); + allowEl = uifactory.addCheckboxesVertical("module.admin.allow.create", optionsContainer, onKeys, values, null, 1); allowEl.select("user", module.isUserAllowedCreate()); allowEl.select("author", module.isAuthorAllowedCreate()); @@ -63,16 +82,95 @@ public class BusinessGroupModuleAdminController extends FormBasicController { buttonsContainer.setRootForm(mainForm); formLayout.add(buttonsContainer); uifactory.addFormSubmitButton("ok", "ok", formLayout); + + FormLayoutContainer dedupCont = FormLayoutContainer.createDefaultFormLayout("dedup", getTranslator()); + formLayout.add(dedupCont); + dedupLink = uifactory.addFormLink("dedup.members", dedupCont, Link.BUTTON); } @Override protected void doDispose() { // } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(source == dedupCtrl) { + boolean coaches = dedupCtrl.isDedupCoaches(); + boolean participants = dedupCtrl.isDedupParticipants(); + if(event == Event.DONE_EVENT) { + dedupMembers(ureq, coaches, participants); + } else { + cmc.deactivate(); + cleanUp(); + } + } else if(source == cmc) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeAsListenerAndDispose(dedupCtrl); + removeAsListenerAndDispose(progressCtrl); + removeAsListenerAndDispose(cmc); + progressCtrl = null; + dedupCtrl = null; + cmc = null; + } + + @Override + public void setActual(float value) { + if(progressCtrl != null) { + progressCtrl.setActual(value); + } + } + + @Override + public void finished() { + cmc.deactivate(); + cleanUp(); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source == dedupLink) { + doDedupMembers(ureq); + } else { + super.formInnerEvent(ureq, source, event); + } + } + + protected void doDedupMembers(UserRequest ureq) { + dedupCtrl = new DedupMembersConfirmationController(ureq, getWindowControl()); + listenTo(dedupCtrl); + + mainPopPanel = new Panel("dedup"); + mainPopPanel.setContent(dedupCtrl.getInitialComponent()); + + cmc = new CloseableModalController(getWindowControl(), translate("close"), mainPopPanel, true, translate("dedup.members"), true); + cmc.activate(); + listenTo(cmc); + } + + protected void dedupMembers(UserRequest ureq, final boolean coaches, final boolean participants) { + progressCtrl = new ProgressController(ureq, getWindowControl()); + progressCtrl.setMessage(translate("dedup.running")); + mainPopPanel.setContent(progressCtrl.getInitialComponent()); + listenTo(progressCtrl); + + Runnable worker = new Runnable() { + @Override + public void run() { + businessGroupService.dedupMembers(getIdentity(), coaches, participants, BusinessGroupModuleAdminController.this); + } + }; + TaskExecutorManager.getInstance().runTask(worker); + } @Override protected void formOK(UserRequest ureq) { module.setUserAllowedCreate(allowEl.isSelected(0)); module.setAuthorAllowedCreate(allowEl.isSelected(1)); } -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/group/ui/_content/bg_admin.html b/src/main/java/org/olat/group/ui/_content/bg_admin.html new file mode 100644 index 00000000000..724e10e4459 --- /dev/null +++ b/src/main/java/org/olat/group/ui/_content/bg_admin.html @@ -0,0 +1,13 @@ +<div class="b_form b_clearfix"> + <fieldset> + <legend>$r.translate("module.admin.title")</legend> + <div class="b_form_desc">$r.translate("module.admin.desc")</div> + $r.render("options") + $r.render("module.buttons") + </fieldset> + <fieldset> + <legend>$r.translate("dedup.members")</legend> + <div class="b_form_desc">$r.translate("dedup.members.desc")</div> + $r.render("dedup") + </fieldset> +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties index 08545aa146a..1a64823dc6c 100644 --- a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties @@ -34,6 +34,10 @@ notification.mail.self.error=Die E-Mail konnte nicht an Sie verschickt werden. warn.foldernotavailable=Der Ordner ist momentan nicht aktiviert und kann nicht angezeigt werden. warn.forumnotavailable=Das Forum ist momentan nicht aktiviert und kann nicht angezeigt werden. +dedup.members=Mitglieder deduplizieren +dedup.members.desc=Hier können Sie die Mitglieder entfernen in einer Kurs sowie in einer Grupper dieser Kurs eingetragen sind. +dedup.running=Deduplizerung ist am Laufen +dedup.done=Deduplizierung wurde erfolgreich beendet admin.menu.title=Gruppe admin.menu.title.alt=Gruppe diff --git a/src/main/java/org/olat/group/ui/main/DedupMembersConfirmationController.java b/src/main/java/org/olat/group/ui/main/DedupMembersConfirmationController.java new file mode 100644 index 00000000000..e6bb69ac60e --- /dev/null +++ b/src/main/java/org/olat/group/ui/main/DedupMembersConfirmationController.java @@ -0,0 +1,91 @@ +/** + * <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.group.ui.main; + +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; + + +/** + * + * Initial date: 27.11.2012<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class DedupMembersConfirmationController extends FormBasicController { + + private static final String[] keys = { "coaches", "participants" }; + + private MultipleSelectionElement typEl; + + public DedupMembersConfirmationController(UserRequest ureq, WindowControl wControl) { + super(ureq, wControl, "dedup"); + + initForm(ureq); + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + FormLayoutContainer optionsCont = FormLayoutContainer.createDefaultFormLayout("options", getTranslator()); + formLayout.add(optionsCont); + formLayout.add("options", optionsCont); + String[] values = new String[] { + translate("dedup.members.coaches"), translate("dedup.members.particpants") + }; + typEl = uifactory.addCheckboxesVertical("typ", "dedup.members.typ", optionsCont, keys, values, null, 1); + typEl.select(keys[0], true); + typEl.select(keys[1], true); + + FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add(buttonCont); + formLayout.add("buttons", buttonCont); + uifactory.addFormSubmitButton("ok", buttonCont); + uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl()); + } + + public boolean isDedupCoaches() { + return typEl.isSelected(0); + } + + public boolean isDedupParticipants() { + return typEl.isSelected(1); + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void formOK(UserRequest ureq) { + fireEvent(ureq, Event.DONE_EVENT); + } + + @Override + protected void formCancelled(UserRequest ureq) { + fireEvent(ureq, Event.CANCELLED_EVENT); + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/group/ui/main/_content/dedup.html b/src/main/java/org/olat/group/ui/main/_content/dedup.html new file mode 100644 index 00000000000..8faa6c97bb4 --- /dev/null +++ b/src/main/java/org/olat/group/ui/main/_content/dedup.html @@ -0,0 +1,3 @@ +$r.translate("dedup.members.info") +$r.render("options") +$r.render("buttons") diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties index a0506470946..9c09c71ccf0 100644 --- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties @@ -3,6 +3,11 @@ create.form.title=Neue Gruppe erstellen create.group=Gruppe erstellen create.group.description=Erzeugen Sie eine neue Gruppe mit der unten stehenden Schaltfläche. Als Betreuer dieser Gruppe können Sie danach die Gruppenwerkzeuge freischalten, Benutzer hinzufügen oder die Gruppe veröffentlichen. copy.group=Kopieren +deup.members=Mitglieder deduplizieren +dedup.members.typ=Typ +dedup.members.coaches=Betreuer +dedup.members.particpants=Teilnehmer +dedup.members.info=Wollen Sie die Mitglieder deduplizieren? dialog.modal.bg.delete.title=Gruppe l\u00F6schen? dialog.modal.bg.delete.text=Wollen Sie die Gruppe "{0}" wirklich l\u00F6schen? dialog.modal.bg.mail.text=Wollen Sie die Mitglieder per Mail benachrichtigen? diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java index 46312771f15..f972b7bdc83 100644 --- a/src/main/java/org/olat/repository/RepositoryManager.java +++ b/src/main/java/org/olat/repository/RepositoryManager.java @@ -32,7 +32,6 @@ import java.util.Collections; import java.util.Date; import java.util.List; -import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.TypedQuery; @@ -91,7 +90,6 @@ import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceImpl; import org.olat.resource.OLATResourceManager; import org.olat.util.logging.activity.LoggingResourceable; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** diff --git a/src/main/java/org/olat/user/restapi/RolesVO.java b/src/main/java/org/olat/user/restapi/RolesVO.java index b99369dd257..f1fcc853ee8 100644 --- a/src/main/java/org/olat/user/restapi/RolesVO.java +++ b/src/main/java/org/olat/user/restapi/RolesVO.java @@ -1,3 +1,22 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.user.restapi; import org.olat.core.id.Roles; diff --git a/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java b/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java index 4a92bd3e9e9..d6f63e1de37 100644 --- a/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java +++ b/src/test/java/org/olat/search/service/document/file/OfficeDocumentTest.java @@ -1,3 +1,22 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.search.service.document.file; import java.io.File; -- GitLab