diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java index 3a8ffb6224f3ee8560229e48473e538de0044b11..b3ae1611b8769fb2cec5f57cfb66c1dde4a449c7 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java +++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeManager.java @@ -41,6 +41,8 @@ import org.olat.core.gui.components.form.ValidationError; import org.olat.core.gui.translator.Translator; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; +import org.olat.core.id.Organisation; +import org.olat.core.id.OrganisationRef; import org.olat.core.id.Preferences; import org.olat.core.id.Roles; import org.olat.core.id.User; @@ -121,12 +123,7 @@ public class UserBulkChangeManager implements InitializingBean { notUpdatedIdentities.clear(); List<Identity> changedIdentities = new ArrayList<>(); List<UserPropertyHandler> userPropertyHandlers = userManager.getUserPropertyHandlersFor(usageIdentifyer, isAdministrativeUser); - OrganisationRoles[] organisationRoles = { - OrganisationRoles.usermanager, OrganisationRoles.groupmanager, - OrganisationRoles.author, OrganisationRoles.administrator, - OrganisationRoles.poolmanager, OrganisationRoles.learnresourcemanager - }; - + Map<String,String> attributeChangeMap = userBulkChanges.getAttributeChangeMap(); // loop over users to be edited: for (Identity identity : selIdentities) { @@ -209,25 +206,29 @@ public class UserBulkChangeManager implements InitializingBean { } } - } // for (propertyHandlers) + } // for property handlers // set roles for identity // loop over securityGroups defined above Map<OrganisationRoles,String> roleChangeMap = userBulkChanges.getRoleChangeMap(); - for (OrganisationRoles organisationRole : organisationRoles) { - boolean isInGroup = organisationService.hasRole(identity, organisationRole); - String thisRoleAction = ""; - if (roleChangeMap.containsKey(organisationRole)) { - thisRoleAction = roleChangeMap.get(organisationRole); - // user not anymore in security group, remove him - if (isInGroup && thisRoleAction.equals("remove")) { - organisationService.removeMember(identity, organisationRole); - log.info(Tracing.M_AUDIT, "User::" + actingIdentity.getKey() + " removed system role::" + organisationRole + " from user::" + identity.getKey()); - } - // user not yet in security group, add him - if (!isInGroup && thisRoleAction.equals("add")) { - organisationService.addMember(identity, organisationRole); - log.info(Tracing.M_AUDIT, "User::" + actingIdentity.getKey() + " added system role::" + organisationRole + " to user::" + identity.getKey()); + if(!roleChangeMap.isEmpty()) { + OrganisationRef organisationRef = userBulkChanges.getOrganisation(); + Organisation organisation = organisationRef == null + ? organisationService.getDefaultOrganisation() : organisationService.getOrganisation(organisationRef); + for (OrganisationRoles organisationRole : OrganisationRoles.values()) { + if (roleChangeMap.containsKey(organisationRole)) { + boolean isInGroup = organisationService.hasRole(identity, organisation, organisationRole); + String thisRoleAction = roleChangeMap.get(organisationRole); + // user not anymore in security group, remove him + if (isInGroup && thisRoleAction.equals("remove")) { + organisationService.removeMember(organisation, identity, organisationRole, false); + log.info(Tracing.M_AUDIT, "User::{} removed system role::{} from user:: {}", actingIdentity.getKey(), organisationRole, identity); + } + // user not yet in security group, add him + if (!isInGroup && thisRoleAction.equals("add")) { + organisationService.addMember(organisation, identity, organisationRole); + log.info(Tracing.M_AUDIT, "User::{} added system role::{} to user::{}", actingIdentity.getKey(), organisationRole, identity); + } } } } @@ -243,19 +244,21 @@ public class UserBulkChangeManager implements InitializingBean { sendLoginDeniedEmail(identity); } identity = securityManager.saveIdentityStatus(identity, status, actingIdentity); - log.info(Tracing.M_AUDIT, "User::" + actingIdentity.getKey() + " changed account status for user::" + identity.getKey() + " from::" + oldStatusText + " to::" + newStatusText); + log.info(Tracing.M_AUDIT, "User::{} changed account status for user::{} from::{} to::{}", + actingIdentity.getKey(), identity.getKey(), oldStatusText, newStatusText); } // persist changes: if (updateError) { String errorOutput = identity.getKey() + ": " + errorDesc; - log.debug("error during bulkChange of users, following user could not be updated: " + errorOutput); + log.debug("error during bulkChange of users, following user could not be updated: {}", errorOutput); notUpdatedIdentities.add(errorOutput); } else { userManager.updateUserFromIdentity(identity); securityManager.deleteInvalidAuthenticationsByEmail(oldEmail); changedIdentities.add(identity); - log.info(Tracing.M_AUDIT, "User::" + actingIdentity.getKey() + " successfully changed account data for user::" + identity.getKey() + " in bulk change"); + log.info(Tracing.M_AUDIT, "User::{} successfully changed account data for user::{} in bulk change", + actingIdentity.getKey(), identity.getKey()); } // commit changes for this user diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java index 707ba3d5c0d41be6ca9fff42a0fc530d8de7cd4e..9a297e84112d4ab026ddda911428cc86c3fc52c9 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java +++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChangeStep01.java @@ -25,6 +25,8 @@ import java.util.Map; import org.olat.admin.user.SystemRolesAndRightsController; import org.olat.basesecurity.OrganisationRoles; +import org.olat.basesecurity.OrganisationService; +import org.olat.basesecurity.model.OrganisationRefImpl; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -33,6 +35,7 @@ import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.impl.Form; 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.util.KeyValues; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.wizard.BasicStep; @@ -42,11 +45,15 @@ import org.olat.core.gui.control.generic.wizard.StepFormController; import org.olat.core.gui.control.generic.wizard.StepsEvent; import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.id.Identity; +import org.olat.core.id.Organisation; +import org.olat.core.id.OrganisationNameComparator; import org.olat.core.id.Roles; import org.olat.core.util.Util; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; +import edu.emory.mathcs.backport.java.util.Collections; + /** * Description:<br> * first step: select attributes, which should be changed @@ -85,6 +92,7 @@ class UserBulkChangeStep01 extends BasicStep { private final class UserBulkChangeStepForm01 extends StepFormBasicController { private SingleSelection setStatus; + private SingleSelection organisationEl; private MultipleSelectionElement chkStatus; private MultipleSelectionElement sendLoginDeniedEmail; private final List<RoleChange> roleChanges = new ArrayList<>(); @@ -95,6 +103,8 @@ class UserBulkChangeStep01 extends BasicStep { @Autowired private UserManager userManager; + @Autowired + private OrganisationService organisationService; public UserBulkChangeStepForm01(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext) { super(ureq, control, rootForm, runContext, LAYOUT_VERTICAL, null); @@ -123,8 +133,13 @@ class UserBulkChangeStep01 extends BasicStep { validChange = true; } } + + if(organisationEl != null && organisationEl.isOneSelected()) { + Long organisationkey = Long.valueOf(organisationEl.getSelectedKey()); + userBulkChanges.setOrganisation(new OrganisationRefImpl(organisationkey)); + } - if (chkStatus!=null && chkStatus.isAtLeastSelected(1)) { + if (chkStatus != null && chkStatus.isAtLeastSelected(1)) { userBulkChanges.setStatus(Integer.parseInt(setStatus.getSelectedKey())); // also check dependent send-email checkbox if (sendLoginDeniedEmail != null) { @@ -159,32 +174,39 @@ class UserBulkChangeStep01 extends BasicStep { } private void initRole(OrganisationRoles role, FormItemContainer formLayout) { - MultipleSelectionElement chkAuthor = uifactory.addCheckboxesHorizontal("rolechk_" + (++counter), "table.role." + role.name(), formLayout, onKeys, onValues); - chkAuthor.select("Author", false); - - chkAuthor.addActionListener(FormEvent.ONCLICK); + MultipleSelectionElement chkRole = uifactory.addCheckboxesHorizontal("rolechk_" + (++counter), "table.role." + role.name(), formLayout, onKeys, onValues); + chkRole.addActionListener(FormEvent.ONCLICK); - SingleSelection setAuthor = uifactory.addDropdownSingleselect("roleset_" + (++counter), null, formLayout, addremove, addremoveTranslated, null); - setAuthor.setVisible(false); + SingleSelection setRole = uifactory.addDropdownSingleselect("roleset_" + (++counter), null, formLayout, addremove, addremoveTranslated, null); + setRole.setVisible(false); - RoleChange change = new RoleChange(chkAuthor, setAuthor, OrganisationRoles.author); + RoleChange change = new RoleChange(chkRole, setRole, role); roleChanges.add(change); - chkAuthor.setUserObject(change); + chkRole.setUserObject(change); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("step1.title"); - FormLayoutContainer textContainer = FormLayoutContainer.createCustomFormLayout("index", getTranslator(), this.velocity_root + "/step1.html"); + FormLayoutContainer textContainer = FormLayoutContainer.createCustomFormLayout("index", getTranslator(), velocity_root + "/step1.html"); formLayout.add(textContainer); - // Main layout is a vertical layout without left side padding. To format // the checkboxes properly we need a default layout for the remaining form // elements FormItemContainer innerFormLayout = FormLayoutContainer.createDefaultFormLayout("innerFormLayout", getTranslator()); formLayout.add(innerFormLayout); + + if(userBulkChanges.getOrganisation() == null) { + KeyValues orgKeyValues = getOrganisationKeyValues(ureq); + if(!orgKeyValues.isEmpty()) { + String[] keys = orgKeyValues.keys(); + organisationEl = uifactory.addDropdownSingleselect("organisations", "organisations", innerFormLayout, + keys, orgKeyValues.values()); + organisationEl.select(keys[0], true); + } + } // check user rights: Roles roles = ureq.getUserSession().getRoles(); @@ -200,7 +222,7 @@ class UserBulkChangeStep01 extends BasicStep { OrganisationRoles.linemanager, OrganisationRoles.principal, OrganisationRoles.administrator }; - + for(OrganisationRoles role:roleArr) { initRole(role, innerFormLayout); } @@ -238,6 +260,20 @@ class UserBulkChangeStep01 extends BasicStep { sendLoginDeniedEmail.setVisible(false); } } + + private KeyValues getOrganisationKeyValues(UserRequest ureq) { + Roles roles = ureq.getUserSession().getRoles(); + List<Organisation> organisations = organisationService.getOrganisations(getIdentity(), roles, + OrganisationRoles.administrator, OrganisationRoles.usermanager, OrganisationRoles.rolesmanager); + if(organisations.size() > 1) { + Collections.sort(organisations, new OrganisationNameComparator(getLocale())); + } + KeyValues organisationKeyValues = new KeyValues(); + for(Organisation organisation:organisations) { + organisationKeyValues.add(KeyValues.entry(organisation.getKey().toString(), organisation.getDisplayName())); + } + return organisationKeyValues; + } } private static final class RoleChange { diff --git a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChanges.java b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChanges.java index 6d1080cf3056a2dc2e35c1b86fe74ad492e533f9..b0203dadcafd6d7ab286d07985fea7ad0d1c9a7a 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/UserBulkChanges.java +++ b/src/main/java/org/olat/admin/user/bulkChange/UserBulkChanges.java @@ -27,6 +27,7 @@ import java.util.Map; import org.olat.admin.user.groups.GroupChanges; import org.olat.basesecurity.OrganisationRoles; import org.olat.core.id.Identity; +import org.olat.core.id.OrganisationRef; /** * @@ -46,6 +47,20 @@ public class UserBulkChanges extends GroupChanges { private Integer status; private boolean sendLoginDeniedEmail; + private OrganisationRef organisation; + + public UserBulkChanges(OrganisationRef organisation) { + this.organisation = organisation; + } + + public OrganisationRef getOrganisation() { + return organisation; + } + + public void setOrganisation(OrganisationRef organisation) { + this.organisation = organisation; + } + public Map<OrganisationRoles, String> getRoleChangeMap() { return roleChangeMap; } diff --git a/src/main/java/org/olat/admin/user/bulkChange/_content/step0.html b/src/main/java/org/olat/admin/user/bulkChange/_content/step0.html index 5a4c2d8c24d83b197cbae1ba6c52b54407362320..94b266d501da74d0ab64961f90095827f6d1bfe4 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_content/step0.html +++ b/src/main/java/org/olat/admin/user/bulkChange/_content/step0.html @@ -1,17 +1,11 @@ -$r.translate("step0.content") -<p>$r.translate("step.notmandatory")</p> -<br /> +<div class="o_desc"><p>$r.translate("step0.content")<br>$r.translate("step.notmandatory")</p></div> #o_togglebox_start("o_usermanagement_bulkChange" "$r.translate('step0.formatexplanation.link')") $r.translate('step0.formatexplanation.text') <table class="table table-bordered"><tbody> #foreach( $propertyHandler in $userPropertyHandlers ) <tr> - <td> - <label> - $r.translate($propertyHandler.i18nFormElementLabelKey()) - </label> - </td> + <th scope="row">$r.translate($propertyHandler.i18nFormElementLabelKey())</th> <td> #set($so='{') #set($sc='}') diff --git a/src/main/java/org/olat/admin/user/bulkChange/_content/step1.html b/src/main/java/org/olat/admin/user/bulkChange/_content/step1.html index 458c08323b31422cf3ea9ed6c00287ae198c88ed..f64f4ad8a3678744534a9648716454b83fb91afa 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_content/step1.html +++ b/src/main/java/org/olat/admin/user/bulkChange/_content/step1.html @@ -1,2 +1 @@ -$r.translate("step1.content") -<p>$r.translate("step.notmandatory")</p> \ No newline at end of file +<div class="o_desc"><p>$r.translate("step1.content")<br>$r.translate("step.notmandatory")</p></div> \ No newline at end of file diff --git a/src/main/java/org/olat/admin/user/bulkChange/_content/step2.html b/src/main/java/org/olat/admin/user/bulkChange/_content/step2.html index a4b8fde73e0112a8ccace426781d7a02a3b93205..53a57cc98e9d3f9f8d691ec9487279ded3e51fa3 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_content/step2.html +++ b/src/main/java/org/olat/admin/user/bulkChange/_content/step2.html @@ -1,5 +1,5 @@ #if($validChange=="true") - $r.translate("step2.content") + <div class="o_desc">$r.translate("step2.content")</div> #else - $r.translate("step2.novalidChanges") + <div class="o_error" role="alert">$r.translate("step2.novalidChanges")</div> #end diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties index 44325d35344aeb8c7396fc7ad717a2913595d780..2c65ff15b893100dd665c2f3a6c4b3c3fe415813 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_de.properties @@ -2,6 +2,7 @@ error.password=$org.olat.user\:error.password.invalid form.name.language=Sprache form.name.pwd=Passwort +organisations=Organisation role.add=hinzuf\u00FCgen role.remove=entfernen step.notmandatory=Dieser Schritt kann \u00FCbersprungen werden, sofern Sie in andernorts \u00C4nderungen vornehmen. diff --git a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties index 4100e7dd8d383a274fccdb2968aad12aa2a5c5bd..bad73e76e93a7b949ff6177b65be58a7d68e0d06 100644 --- a/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/admin/user/bulkChange/_i18n/LocalStrings_en.properties @@ -10,6 +10,7 @@ form.name.language=Language form.name.pwd=Password main.menu.title=OLAT password main.menu.title.alt=Bulk modification of OLAT password +organisations=Organisation role.add=Add role.remove=Remove step.notmandatory=This step is not mandatory provided that there are modifications elsewhere. diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java index e9cae0b4027d754dced9e834008075a333e81335..2af0d03df5496482a6a39e1b8c43ba40ed51dde3 100644 --- a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java +++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java @@ -70,6 +70,7 @@ import org.olat.core.gui.control.generic.wizard.StepsMainRunController; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.Organisation; +import org.olat.core.id.OrganisationRef; import org.olat.core.id.Roles; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; @@ -434,9 +435,15 @@ public class UserSearchTableController extends FormBasicController implements Ac if(identities.isEmpty()) { return; } + + OrganisationRef selectedOrganisation = null; + if(currentSearchParams != null && currentSearchParams.getOrganisations() != null + && currentSearchParams.getOrganisations().size() == 1) { + selectedOrganisation = currentSearchParams.getOrganisations().get(0); + } // valid selection: load in wizard - final UserBulkChanges userBulkChanges = new UserBulkChanges(); + final UserBulkChanges userBulkChanges = new UserBulkChanges(selectedOrganisation); Step start = new UserBulkChangeStep00(ureq, identities, userBulkChanges); // callback executed in case wizard is finished. StepRunnerCallback finish = (uureq, wwControl, runContext) -> {