Implement new edit user screen with Role template

Hi ,

While implementing new edit user screen , with role template

If i tried to save user with roles from the template , I’m getting an error as the user is still not yet saved , as trying to save instance with persist not cascade ,

but if i saved the user first , then editing and applying the template it works fine as the user is already saved ,

below is my current implementation

XML

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
        caption="msg://editorCaption"
        focusComponent="form"
        messagesPack="com.vtss.vtower.web.screens.user">
    <data>
        <instance id="vTowerUserDc"
                  class="com.vtss.vtower.entity.user.VTowerUser"
                  view="vtower-user-base-edit">
            <loader/>
            <collection id="userRolesDc" property="userRoles"/>
            <collection id="assignableOrganizationsDc" property="assignableOrganizations"/>
        </instance>
        <collection id="groupsDc" class="com.haulmont.cuba.security.entity.Group" view="_minimal">
            <loader id="groupsDl">
                <query>
                    <![CDATA[select e from sec$Group e]]>
                </query>
            </loader>
        </collection>
    </data>
    <dialogMode height="AUTO"
                width="AUTO"
                modal="true"
                forceDialog="true"/>
    <layout expand="scrollBox" spacing="true">
        <scrollBox id="scrollBox" spacing="true">

            <form id="form" dataContainer="vTowerUserDc">
                <column width="250px">
                    <textField id="loginField" property="login" inputPrompt="msg://valid-email-address"/>
                    <textField id="nameField" required="true" requiredMessage="msg://name-required" property="name"/>
                    <textField id="positionField" property="position"/>
                    <lookupField id="groupField" property="group" required="true" requiredMessage="msg://group-required"
                                 nullName="msg://null-option" optionsContainer="groupsDc"/>
                    <checkBox id="activeField" property="active"/>
                </column>
                <column width="250px" id="details-user-account">
                    <textField id="ipMaskField" property="ipMask"/>
                    <lookupField id="timeZoneField" property="timeZone"/>
                    <checkBox id="canBeAssignedToCountryField" property="canBeAssignedToCountry"/>
                    <checkBox id="isEmployeeField" property="isEmployee"/>
                    <checkBox id="isGlobalUserField" property="isGlobalUser"/>
                </column>
            </form>
            <vbox spacing="true">
                <lookupField id="rolesTemplateLKP" caption="msg://role-template" width="350px"/>
                <buttonsPanel id="roleTemplateActionsPnl" enable="false">
                    <button id="applyTemplateBtn" caption="mainMsg://action.apply.role" stylename="primary"/>
                    <button id="revokeTemplateBtn" caption="mainMsg://action.revoke.role" stylename="friendly"/>
                </buttonsPanel>
            </vbox>

            <hbox spacing="true" width="100%">
                <groupBox width="50%" id="userRolesBox" caption="msg://user-roles">
                    <table id="userRolesTable" dataContainer="userRolesDc" width="100%">
                        <actions>
                            <action id="create" type="create"/>
                            <action id="remove" type="remove"/>
                        </actions>
                        <columns>
                            <column id="role"/>
                            <column id="roleName"/>
                        </columns>
                        <buttonsPanel>
                            <button action="userRolesTable.create" stylename="primary"/>
                            <button action="userRolesTable.remove" stylename="friendly"/>
                        </buttonsPanel>
                    </table>
                </groupBox>

                <groupBox width="50%" id="assignableOrganizationsBox"
                          caption="msg://assignable-organizations">
                    <table id="assignableOrganizationsTable" dataContainer="assignableOrganizationsDc" width="100%">
                        <actions>
                            <action id="create" type="create"/>
                            <action id="edit" type="edit"/>
                            <action id="remove" type="remove"/>
                        </actions>
                        <columns>
                            <column id="user"/>
                            <column id="organization"/>
                        </columns>
                        <buttonsPanel>
                            <button action="assignableOrganizationsTable.create" stylename="primary"/>
                            <button action="assignableOrganizationsTable.edit" stylename="friendly"/>
                            <button action="assignableOrganizationsTable.remove" stylename="danger"/>
                        </buttonsPanel>
                    </table>
                </groupBox>
            </hbox>
        </scrollBox>
        <hbox id="editActions" spacing="true">
            <button action="windowCommitAndClose" stylename="primary"/>
            <button action="windowClose" stylename="friendly"/>
        </hbox>
    </layout>
</window>


Controller

package com.vtss.vtower.web.screens.user;

import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.Notifications;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.model.CollectionPropertyContainer;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.screen.*;
import com.haulmont.cuba.security.entity.RoleType;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.cuba.security.entity.UserRole;
import com.vtss.vtower.entity.approle.ApplicationRoleTemplate;
import com.vtss.vtower.entity.approle.ApplicationRoleType;
import com.vtss.vtower.entity.user.VTowerUser;
import com.vtss.vtower.service.ApplicationRoleTemplateService;
import com.vtss.vtower.web.screens.mixin.util.UIUtil;
import com.vtss.vtower.web.utils.Constants;

import javax.inject.Inject;
import java.util.*;
import java.util.regex.Pattern;

@UiController("vtower_VTowerUser.edit")
@UiDescriptor("v-tower-user-edit.xml")
@EditedEntityContainer("vTowerUserDc")
@LoadDataBeforeShow
public class VTowerUserEdit extends StandardEditor<VTowerUser> {


    @Inject
    private LookupField<String> timeZoneField;

    @Inject
    private LookupField<ApplicationRoleTemplate> rolesTemplateLKP;

    @Inject
    private Table<UserRole> userRolesTable;

    @Inject
    private ButtonsPanel roleTemplateActionsPnl;


    

    @Inject
    private ApplicationRoleTemplateService applicationRoleTemplateService;

    @Inject
    private CollectionPropertyContainer<UserRole> userRolesDc;

    @Inject
    private Metadata metadata;

    @Inject
    protected TimeZones timeZones;

    private Map<String, Object> params;
    @Inject
    private Notifications notifications;
    @Inject
    private Messages messages;
    @Inject
    private MessageBundle messageBundle;

    @Inject
    private TextField<String> ipMaskField;
    @Inject
    private CheckBox canBeAssignedToCountryField;
    @Inject
    private GroupBoxLayout assignableOrganizationsBox;
    @Inject
    private CheckBox isGlobalUserField;
    @Inject
    private CheckBox isEmployeeField;


    @Subscribe
    public void onInit(InitEvent event) {
        ScreenOptions options = event.getOptions();
        if (options instanceof MapScreenOptions) {
            params = ((MapScreenOptions) options).getParams();
            if (params.containsKey(Constants.READ_ONLY_MODE)){
                setReadOnly(Boolean.TRUE);
                rolesTemplateLKP.setEnabled(Boolean.FALSE);
            }
        }
    }


    @Subscribe
    public void onBeforeShow(BeforeShowEvent event) {
        buildTimeZoneField();
        buildRoleTemplateLkpField();
        buildScreenComponents();
    }



    @Subscribe("rolesTemplateLKP")
    public void onRolesTemplateLKPValueChange(HasValue.ValueChangeEvent event) {
        if (Objects.nonNull(event)) {
            if (Objects.nonNull(event.getValue())) {
                roleTemplateActionsPnl.setEnabled(true);
            } else {
                roleTemplateActionsPnl.setEnabled(false);
            }
        }
    }

    @Subscribe("loginField")
    public void onLoginFieldValueChange(HasValue.ValueChangeEvent<String> event) {
        if (Objects.nonNull(event) && Objects.nonNull(event.getValue())) {
                if (!Pattern.compile(Constants.EMAIL).matcher(event.getValue()).matches()) {
                    event.getComponent().setValue(null);
                    notifications.create().withCaption(messages.getMainMessage("msg-warning"))
                            .withDescription(messageBundle.getMessage("invalid-email-address"))
                            .withType(Notifications.NotificationType.TRAY)
                            .withPosition(Notifications.Position.BOTTOM_RIGHT)
                            .show();
                } else {
                    getEditedEntity().setEmail(event.getValue());
                }
        }
    }
    
    

    @Subscribe(id = "userRolesDc", target = Target.DATA_CONTAINER)
    public void onUserRolesDcItemChange(InstanceContainer.ItemChangeEvent<UserRole> event) {
        if (Objects.nonNull(event) && Objects.nonNull(event.getItem())) {
            if (userRolesDc.getItem().getRole().getDefaultRole() != null && userRolesDc.getItem().getRole().getDefaultRole()) {
                userRolesTable.getAction("remove").setEnabled(false);
            } else {
                userRolesTable.getAction("remove").setEnabled(true);
            }
        }
    }


    @Subscribe("applyTemplateBtn")
    public void onApplyTemplateBtnClick(Button.ClickEvent event) {
        User user = getEditedEntity();

        rolesTemplateLKP.getValue().getTemplateLines()
                .forEach(applicationRoleTemplateLine -> {
                    if (!userRolesDc.getItems().stream()
                            .filter(userRole -> !userRole.getRoleName().equals("system-minimal"))
                            .anyMatch(userRole -> userRole.getRole().equals(applicationRoleTemplateLine.getRole()))) {
                        UserRole role = metadata.create(UserRole.class);
                        role.setUser(user);
                        role.setRole(applicationRoleTemplateLine.getRole());
                        userRolesDc.getMutableItems().add(role);
                        user.getUserRoles().add(role);
                    }
                });
    }

    @Subscribe("revokeTemplateBtn")
    public void onRevokeTemplateBtnClick(Button.ClickEvent event) {
        rolesTemplateLKP.getValue().getTemplateLines()
                .forEach(applicationRoleTemplateLine -> {
                    UserRole role = userRolesDc.getItems().stream()
                            .filter(userRole -> userRole.getRole().equals(applicationRoleTemplateLine.getRole()))
                            .findFirst().orElse(null);
                    if (role != null) {
                        userRolesDc.getMutableItems().remove(role);
                    }
                });
    }


    private void buildTimeZoneField() {
        Map<String, String> options = new TreeMap<>();
        for (String id : TimeZone.getAvailableIDs()) {
            TimeZone timeZone = TimeZone.getTimeZone(id);
            options.put(timeZones.getDisplayNameLong(timeZone), id);
        }
        timeZoneField.setOptionsMap(options);
    }

    private void buildRoleTemplateLkpField() {
        List<ApplicationRoleTemplate> roleTemplates = new ArrayList<>();
        if (Objects.nonNull(params)) {
            if (params.containsKey(Constants.LEGAL_ENTITY_PARAM)) {
                roleTemplates = applicationRoleTemplateService
                        .getApplicationRoleTemplates(
                                (ApplicationRoleType) params.get(Constants.APPLICATION_ROLE_TYPE_PARAM)
                                ,(UUID) params.get(Constants.LEGAL_ENTITY_PARAM),
                                Boolean.FALSE);
            } else if (params.containsKey(Constants.ORGANIZATION_PARAM)) {
                roleTemplates = applicationRoleTemplateService.getApplicationRoleTemplates(
                        (ApplicationRoleType) params.get(Constants.APPLICATION_ROLE_TYPE_PARAM),
                        (UUID) params.get(Constants.ORGANIZATION_PARAM),
                        Boolean.TRUE);
            }else {
                roleTemplates = applicationRoleTemplateService.getApplicationRoleTemplates(
                        (ApplicationRoleType) params.get(Constants.APPLICATION_ROLE_TYPE_PARAM));
            }
        } else {
            roleTemplates = applicationRoleTemplateService.getApplicationRoleTemplates(null);
        }
        UIUtil.populateOptionsLookup(roleTemplates, rolesTemplateLKP);
    }


    private void buildScreenComponents() {
        if (Objects.nonNull(params) && params.containsKey(Constants.OPENED_FROM_PARAM)) {
            ipMaskField.setVisible(false);
            canBeAssignedToCountryField.setVisible(false);
            isGlobalUserField.setVisible(false);
            isEmployeeField.setVisible(false);
            timeZoneField.setVisible(false);
            assignableOrganizationsBox.setVisible(false);

            if (PersistenceHelper.isNew(getEditedEntity())) {
                switch ((String) params.get(Constants.OPENED_FROM_PARAM)) {
                    case Constants.COUNTRY_PARAM:
                        getEditedEntity().setCanBeAssignedToCountry(true);
                    case Constants.GLOB_PARAM:
                        getEditedEntity().setIsGlobalUser(true);
                }
            }
        } else {
            VTowerUser user = (VTowerUser) AppBeans.get(UserSessionSource.class).getUserSession().getUser();
            Boolean isSuperAdmin = user.getUserRoles().stream().anyMatch(userRole -> userRole.getRoleName().equals("system-full-access"));
            if (!isSuperAdmin) {
                if (!user.getCanBeAssignedToCountry()) {
                    canBeAssignedToCountryField.setEditable(false);
                }
                if (!user.getIsGlobalUser()) {
                    isGlobalUserField.setEditable(false);
                }
            }
        }
    }

}

I want to be able to save both the roles while saving the user , while the user is on the new state save behavior like CASCADE

Hi @abd.ibrahim.allam,

Try changing the code below:

To:

UserRole role = DataContext.create(UserRole.class);

Take a look at this answer from @knstvk.

Hope it helps.

Regards,
Peterson

1 Like