From 96d0f69802e3395176b86e8ab26050224d56d2d1 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 25 Jul 2012 11:48:50 +0200
Subject: [PATCH] OO-291: start implementation of the wizard to manage the
 users

---
 .../AbstractBusinessGroupListController.java  |  49 +++-
 .../ui/main/_i18n/LocalStrings_de.properties  |   1 +
 .../ui/wizard/BGUserManagementController.java | 248 ++++++++++++++++++
 .../BGUserManagementGroupTableDataModel.java  |  65 +++++
 .../BGUserManagementSendMailController.java   |  80 ++++++
 .../olat/group/ui/wizard/_content/users.html  |   5 +
 .../wizard/_i18n/LocalStrings_de.properties   |  12 +-
 7 files changed, 456 insertions(+), 4 deletions(-)
 create mode 100644 src/main/java/org/olat/group/ui/wizard/BGUserManagementController.java
 create mode 100644 src/main/java/org/olat/group/ui/wizard/BGUserManagementGroupTableDataModel.java
 create mode 100644 src/main/java/org/olat/group/ui/wizard/BGUserManagementSendMailController.java
 create mode 100644 src/main/java/org/olat/group/ui/wizard/_content/users.html

diff --git a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
index ffb31c181ef..66a6a3dd4d9 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractBusinessGroupListController.java
@@ -72,6 +72,8 @@ import org.olat.group.ui.wizard.BGCopyBusinessGroup;
 import org.olat.group.ui.wizard.BGCopyPreparationStep;
 import org.olat.group.ui.wizard.BGEmailSelectReceiversStep;
 import org.olat.group.ui.wizard.BGMergeStep;
+import org.olat.group.ui.wizard.BGUserManagementController;
+import org.olat.group.ui.wizard.BGUserManagementSendMailController;
 import org.olat.resource.OLATResource;
 import org.olat.resource.accesscontrol.manager.ACFrontendManager;
 import org.olat.resource.accesscontrol.model.OLATResourceAccess;
@@ -104,6 +106,8 @@ abstract class AbstractBusinessGroupListController extends BasicController {
 	private Link createButton;
 	
 	private NewBGController groupCreateController;
+	private BGUserManagementController userManagementController;
+	private BGUserManagementSendMailController userManagementSendMailController;
 	private BusinessGroupDeleteDialogBoxController deleteDialogBox;
 	private StepsMainRunController businessGroupWizard;
 	private CloseableModalController cmc;
@@ -289,6 +293,21 @@ abstract class AbstractBusinessGroupListController extends BasicController {
 					reload();
 				}
 			}
+		} else if (source == userManagementController) {
+			cmc.deactivate();
+			if(event == Event.DONE_EVENT) {
+				//confirm sending emails
+				confirmUserManagementEmail(ureq);
+			} else {
+				cleanUpPopups();
+			}
+		} else if (source == userManagementSendMailController) {
+			if(event == Event.DONE_EVENT) {
+				boolean sendMail = userManagementSendMailController.isSendMail();
+				finishUserManagement(sendMail);
+			}
+			cmc.deactivate();
+			cleanUpPopups();
 		} else if (source == cmc) {
 			cleanUpPopups();
 		}
@@ -505,8 +524,34 @@ abstract class AbstractBusinessGroupListController extends BasicController {
 	 * @param ureq
 	 * @param items
 	 */
-	private void doUserManagement(UserRequest ureq, List<BGTableItem> items) {
-		if(items == null || items.isEmpty()) return;
+	private void doUserManagement(UserRequest ureq, List<BGTableItem> selectedItems) {
+		removeAsListenerAndDispose(cmc);
+		removeAsListenerAndDispose(userManagementController);
+		if(selectedItems == null || selectedItems.isEmpty()) return;
+		
+		List<BusinessGroup> groups = toBusinessGroups(selectedItems);
+		
+		userManagementController = new BGUserManagementController(ureq, getWindowControl(), groups);
+		listenTo(userManagementController);
+		cmc = new CloseableModalController(getWindowControl(), translate("close"), userManagementController.getInitialComponent(),
+				true, translate("users.group"));
+		cmc.activate();
+		listenTo(cmc);
+	}
+	
+	private void confirmUserManagementEmail(UserRequest ureq) {
+		removeAsListenerAndDispose(cmc);
+		removeAsListenerAndDispose(userManagementSendMailController);
+		
+		userManagementSendMailController = new BGUserManagementSendMailController(ureq, getWindowControl());
+		listenTo(userManagementSendMailController);
+		cmc = new CloseableModalController(getWindowControl(), translate("close"), userManagementSendMailController.getInitialComponent(),
+				true, translate("users.group"));
+		cmc.activate();
+		listenTo(cmc);
+	}
+	
+	private void finishUserManagement(boolean sendMail) {
 		
 	}
 	
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 7b1eb6e2dcd..0aadf6f7141 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
@@ -88,6 +88,7 @@ tools.delete.unusedgroup=Arbeitsgruppen
 merge.group=Zusammenführen
 email.group=Email versenden
 config.group=Konfigurieren
+users.group=Benutzer verwalten
 
 notification.mail.added.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\nSie wurden von {0} {1} ({3}) in eine Arbeitsgruppe eingeladen\: \n\nGruppenname\: $groupname\nBeschreibung\: $groupdescription\n\nSind Sie damit nicht einverstanden, so k\u00F6nnen Sie sich aus der Arbeitsgruppe wieder austragen.
 notification.mail.added.self.body=*** Das ist eine automatisch generierte Nachricht. Bitte antworten Sie nicht auf diese Nachricht *** \n\n Sie haben in OLAT eine Arbeitsgruppe eröffnet\: \n\nGruppenname\: $groupname\nBeschreibung\: $groupdescription\n\nSie k\u00F6nnen die Gruppe jederzeit wieder löschen.
diff --git a/src/main/java/org/olat/group/ui/wizard/BGUserManagementController.java b/src/main/java/org/olat/group/ui/wizard/BGUserManagementController.java
new file mode 100644
index 00000000000..6fbcdc4fe65
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/wizard/BGUserManagementController.java
@@ -0,0 +1,248 @@
+/**
+ * <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.wizard;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.admin.securitygroup.gui.IdentitiesOfGroupTableDataModel;
+import org.olat.admin.user.UserSearchController;
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.SecurityGroup;
+import org.olat.basesecurity.events.MultiIdentityChosenEvent;
+import org.olat.basesecurity.events.SingleIdentityChosenEvent;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.table.DefaultColumnDescriptor;
+import org.olat.core.gui.components.table.StaticColumnDescriptor;
+import org.olat.core.gui.components.table.Table;
+import org.olat.core.gui.components.table.TableController;
+import org.olat.core.gui.components.table.TableGuiConfiguration;
+import org.olat.core.gui.components.table.TableMultiSelectEvent;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+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.translator.Translator;
+import org.olat.core.id.Identity;
+import org.olat.group.BusinessGroup;
+import org.olat.user.UserManager;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class BGUserManagementController extends BasicController {
+
+	protected static final String usageIdentifyer = IdentitiesOfGroupTableDataModel.class.getCanonicalName();
+
+	protected static final String COMMAND_REMOVEUSER = "removesubjectofgroup";
+	protected static final String COMMAND_VCARD = "show.vcard";
+	protected static final String COMMAND_SELECTUSER = "select.user";
+	
+	private VelocityContainer mainVC;
+	private Link addOwner, addParticipant;
+	private Link okLink, cancelLink;
+	private TableController usersCtrl;
+	private UserSearchController addOwnerCtrl;
+	private UserSearchController addParticipantCtrl;
+	private CloseableModalController cmc;
+	private BGUserManagementGroupTableDataModel userTableModel;
+	private final List<UserPropertyHandler> userPropertyHandlers;
+	
+	private final List<BusinessGroup> groups;
+	private final BaseSecurity securityManager;
+	private final List<Identity> addedOwners = new ArrayList<Identity>();
+	private final List<Identity> addedParticipants = new ArrayList<Identity>();
+	private final List<Identity> removedIdentities = new ArrayList<Identity>();
+
+	public BGUserManagementController(UserRequest ureq, WindowControl wControl, List<BusinessGroup> groups) {
+		super(ureq, wControl);
+		this.groups = groups;
+		securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		userPropertyHandlers = UserManager.getInstance().getUserPropertyHandlersFor(usageIdentifyer, true);
+		
+		mainVC = createVelocityContainer("users");
+		
+		addOwner = LinkFactory.createButton("users.addparticipant", mainVC, this);
+		addParticipant = LinkFactory.createButton("users.addowner", mainVC, this);
+
+		Translator userTrans = UserManager.getInstance().getPropertyHandlerTranslator(getTranslator());;
+		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
+		tableConfig.setTableEmptyMessage(translate("resources.noresources"));
+		usersCtrl = new TableController(tableConfig, ureq, getWindowControl(), userTrans);
+		listenTo(usersCtrl);
+
+		userTableModel = new BGUserManagementGroupTableDataModel(Collections.<Identity>emptyList(), getLocale(), userPropertyHandlers);
+		initGroupTable();
+		usersCtrl.setTableDataModel(userTableModel);
+		
+		mainVC.put("users", usersCtrl.getInitialComponent());
+		
+		
+
+		okLink = LinkFactory.createButton("ok", mainVC, this);
+		cancelLink = LinkFactory.createButton("cancel", mainVC, this);
+		
+		
+		putInitialPanel(mainVC);
+
+		loadModel();
+	}
+	
+	protected void initGroupTable() {			
+		// first the login name
+		DefaultColumnDescriptor cd0 = new DefaultColumnDescriptor("table.user.login", 0, COMMAND_VCARD, getLocale());
+		cd0.setIsPopUpWindowAction(true, "height=700, width=900, location=no, menubar=no, resizable=yes, status=no, scrollbars=yes, toolbar=no");
+		
+		usersCtrl.addColumnDescriptor(cd0);
+
+		// followed by the users fields
+		for (int i = 0; i < userPropertyHandlers.size(); i++) {
+			UserPropertyHandler userPropertyHandler	= userPropertyHandlers.get(i);
+			boolean visible = UserManager.getInstance().isMandatoryUserProperty(usageIdentifyer , userPropertyHandler);
+			usersCtrl.addColumnDescriptor(visible, userPropertyHandler.getColumnDescriptor(i+1, null, getLocale()));
+		}
+
+		usersCtrl.addColumnDescriptor(new StaticColumnDescriptor(COMMAND_SELECTUSER, "table.subject.action", translate("action.general")));
+		usersCtrl.addMultiSelectAction("remove", COMMAND_REMOVEUSER);
+		usersCtrl.setMultiSelect(true);
+	}
+	
+	private void loadModel() {
+		List<SecurityGroup> secGroups = new ArrayList<SecurityGroup>();
+		
+		for(BusinessGroup group:groups) {
+			if(group.getOwnerGroup() != null) {
+				secGroups.add(group.getOwnerGroup());
+			}
+			if(group.getPartipiciantGroup() != null) {
+				secGroups.add(group.getPartipiciantGroup());
+			}
+			if(group.getWaitingGroup() != null) {
+				secGroups.add(group.getWaitingGroup());
+			}
+		}
+		
+		List<Identity> identities = securityManager.getIdentitiesOfSecurityGroups(secGroups);
+		userTableModel.setObjects(identities);
+		usersCtrl.modelChanged();
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(source == cmc) {
+			cleanupPopup();
+		} else if (source == addOwnerCtrl || source == addParticipantCtrl) {
+			List<Identity> identitiesToAdd = extractIdentities(event);
+			if (source == addOwnerCtrl) {
+				addedParticipants.addAll(identitiesToAdd);
+				userTableModel.getObjects().addAll(identitiesToAdd);
+			} else if(source == addParticipantCtrl) {
+				addedParticipants.addAll(identitiesToAdd);
+				userTableModel.getObjects().addAll(identitiesToAdd);
+			}
+			usersCtrl.modelChanged();
+			cmc.deactivate();
+			cleanupPopup();
+		} else if (source == usersCtrl) {
+			if (event.getCommand().equals(Table.COMMAND_MULTISELECT)) {
+				TableMultiSelectEvent tmse = (TableMultiSelectEvent) event;
+				if (tmse.getAction().equals(COMMAND_REMOVEUSER)) {
+					List<Identity> toRemove = userTableModel.getObjects(tmse.getSelection());
+					removeIdentities(toRemove);
+				}
+			}
+		}
+		super.event(ureq, source, event);
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(source == addOwner) {
+			removeAsListenerAndDispose(cmc);
+			removeAsListenerAndDispose(addOwnerCtrl);
+			
+			addOwnerCtrl = new UserSearchController(ureq, getWindowControl(), true, true, false);			
+			listenTo(addOwnerCtrl);
+			cmc = new CloseableModalController(getWindowControl(), translate("close"), addOwnerCtrl.getInitialComponent(), true, translate("users.addowner"));
+			listenTo(cmc);
+			cmc.activate();
+		} else if (source == addParticipant) {
+			removeAsListenerAndDispose(cmc);
+			removeAsListenerAndDispose(addParticipantCtrl);
+			
+			addParticipantCtrl = new UserSearchController(ureq, getWindowControl(), true, true, false);			
+			listenTo(addParticipantCtrl);
+			cmc = new CloseableModalController(getWindowControl(), translate("close"), addParticipantCtrl.getInitialComponent(), true, translate("users.addowner"));
+			listenTo(cmc);
+			cmc.activate();
+		} else if (source == okLink) {
+			fireEvent(ureq, Event.DONE_EVENT);
+		} else if (source == cancelLink) {
+			fireEvent(ureq, Event.CANCELLED_EVENT);
+		}
+	}
+	
+	private void removeIdentities(List<Identity> toRemove) {
+		userTableModel.getObjects().removeAll(toRemove);
+		addedOwners.removeAll(toRemove);
+		addedParticipants.removeAll(toRemove);
+		removedIdentities.addAll(toRemove);
+		usersCtrl.modelChanged();
+	}
+	
+	private List<Identity> extractIdentities(Event event) {
+		if(event instanceof SingleIdentityChosenEvent) {
+			SingleIdentityChosenEvent chosenEvent = (SingleIdentityChosenEvent)event;
+			Identity identity = chosenEvent.getChosenIdentity();
+			return Collections.singletonList(identity);
+		}
+		if (event instanceof MultiIdentityChosenEvent) {
+			MultiIdentityChosenEvent chosenEvent = (MultiIdentityChosenEvent)event;
+			List<Identity> identities = chosenEvent.getChosenIdentities();
+			return identities;
+		}
+		return Collections.emptyList();
+	}
+	
+	private void cleanupPopup() {
+		removeAsListenerAndDispose(cmc);
+		removeAsListenerAndDispose(addOwnerCtrl);
+		removeAsListenerAndDispose(addParticipantCtrl);
+		cmc = null;
+		addOwnerCtrl = null;
+		addParticipantCtrl = null;
+	}
+
+
+}
diff --git a/src/main/java/org/olat/group/ui/wizard/BGUserManagementGroupTableDataModel.java b/src/main/java/org/olat/group/ui/wizard/BGUserManagementGroupTableDataModel.java
new file mode 100644
index 00000000000..aeee236fb09
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/wizard/BGUserManagementGroupTableDataModel.java
@@ -0,0 +1,65 @@
+/**
+ * <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.wizard;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.gui.components.table.DefaultTableDataModel;
+import org.olat.core.id.Identity;
+import org.olat.core.id.User;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class BGUserManagementGroupTableDataModel extends DefaultTableDataModel<Identity> {
+	private List<UserPropertyHandler> userPropertyHandlers;
+
+	public BGUserManagementGroupTableDataModel(List<Identity> combo, Locale locale, List<UserPropertyHandler> userPropertyHandlers) {
+		super(combo);
+		setLocale(locale);		
+		this.userPropertyHandlers = userPropertyHandlers;
+	}
+
+
+	public final Object getValueAt(int row, int col) {
+		Identity identity = getObject(row);
+		User user = identity.getUser();
+		
+		if (col == 0) {
+			return identity.getName();			
+
+		} else if (col > 0 && col < userPropertyHandlers.size()+1 ) {
+			// get user property for this column
+			UserPropertyHandler userPropertyHandler = userPropertyHandlers.get(col-1);
+			String value = userPropertyHandler.getUserProperty(user, getLocale());
+			return (value == null ? "n/a" : value);
+			
+		} else {
+			return "error";			
+		}
+	}
+
+	public int getColumnCount() {
+		return userPropertyHandlers.size() + 2;
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/wizard/BGUserManagementSendMailController.java b/src/main/java/org/olat/group/ui/wizard/BGUserManagementSendMailController.java
new file mode 100644
index 00000000000..06b583b142d
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/wizard/BGUserManagementSendMailController.java
@@ -0,0 +1,80 @@
+/**
+ * <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.wizard;
+
+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.WindowControl;
+import org.olat.core.gui.control.generic.wizard.StepsEvent;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class BGUserManagementSendMailController extends FormBasicController {
+	
+	private MultipleSelectionElement sendMailEl;
+	
+	private String[] keys = new String[]{ "on" };
+
+	public BGUserManagementSendMailController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		initForm(ureq);
+	}
+
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		String[] values = new String[]{
+			"send"	
+		};
+		sendMailEl = uifactory.addCheckboxesHorizontal("", formLayout, keys, values, null);
+		
+		FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		buttonsContainer.setRootForm(mainForm);
+		formLayout.add(buttonsContainer);
+		uifactory.addFormSubmitButton("ok", buttonsContainer);
+		uifactory.addFormCancelButton("cancel", buttonsContainer, ureq, getWindowControl());
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	public boolean isSendMail() {
+		return sendMailEl.isAtLeastSelected(1);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, StepsEvent.CANCELLED_EVENT);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, StepsEvent.DONE_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/wizard/_content/users.html b/src/main/java/org/olat/group/ui/wizard/_content/users.html
new file mode 100644
index 00000000000..649e8bd8c66
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/wizard/_content/users.html
@@ -0,0 +1,5 @@
+$r.render("users.addowner") $r.render("users.addparticipant")
+
+$r.render("users")
+
+$r.render("ok") $r.render("cancel")
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_de.properties
index 589d8c9c726..79062841ce5 100644
--- a/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_de.properties
@@ -46,7 +46,6 @@ config.tools.title=Werkzeuge
 config.tools.desc=Werkzeuge
 config.resources.title=Kursen
 config.resources.desc=Kursen
-
 copy.wizard.bgstep=Kopieren "{0}"
 merge.wizard.title=Gruppe zusammenführen
 merge.confirmation=Diese Gruppe werden gel\u00F6scht nach den zusammenführung: "{0}".
@@ -64,4 +63,13 @@ email.write.description=Email schreiben
 email.select.receivers=E-Mail ausl\u00F6sen
 email.select.receiver.tutor=Besitzer / Tutoren
 email.select.receiver.participant=Teilnehmer
-
+users.manage.title=Benutzer verwalten
+users.manage.desc=Benutzer verwalten
+users.email.title=Email versenden
+users.email.desc=Email versenden
+users.addowner=Add owner
+users.addparticipant=Add participant
+action.general=Action
+remove=Entfernen
+table.user.login=Login
+table.subject.action=Action
\ No newline at end of file
-- 
GitLab