All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sirius.biz.tenants.TenantController Maven / Gradle / Ivy

There is a newer version: 9.6
Show newest version
/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.biz.tenants;

import sirius.biz.model.AddressData;
import sirius.biz.model.PermissionData;
import sirius.biz.web.BizController;
import sirius.biz.web.PageHelper;
import sirius.db.mixing.SmartQuery;
import sirius.db.mixing.constraints.And;
import sirius.db.mixing.constraints.FieldOperator;
import sirius.db.mixing.constraints.Or;
import sirius.kernel.di.std.ConfigValue;
import sirius.kernel.di.std.Register;
import sirius.kernel.health.Exceptions;
import sirius.kernel.nls.NLS;
import sirius.web.controller.Controller;
import sirius.web.controller.DefaultRoute;
import sirius.web.controller.Message;
import sirius.web.controller.Routed;
import sirius.web.http.WebContext;
import sirius.web.security.LoginRequired;
import sirius.web.security.Permission;
import sirius.web.security.UserContext;
import sirius.web.services.JSONStructuredOutput;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * Provides a GUI for managing tenants.
 */
@Register(classes = Controller.class)
public class TenantController extends BizController {

    /**
     * Contains the permission required to manage tenants.
     */
    public static final String PERMISSION_MANAGE_TENANTS = "permission-manage-tenants";

    /**
     * Contains a list of all available features or permission which can be granted to a tenant.
     */
    @ConfigValue("security.tenantPermissions")
    private List permissions;

    @ConfigValue("product.wondergemRoot")
    private String wondergemRoot;

    /**
     * Returns all available features which can be assigned to a tenant.
     *
     * @return an unmodifyable list of all features available.
     */
    public List getPermissions() {
        return Collections.unmodifiableList(permissions);
    }

    /**
     * Returns a translated name of the given permission.
     *
     * @param role the permission or feature to translate
     * @return a translated name for the permission
     */
    public String getPermissionName(String role) {
        return NLS.get("TenantPermission." + role);
    }

    /**
     * Returns a translated description of the given permission.
     *
     * @param role the permission for which a description is requested
     * @return the translated description of the permission
     */
    public String getPermissionDescription(String role) {
        return NLS.getIfExists("TenantPermission." + role + ".description", NLS.getCurrentLang()).orElse("");
    }

    /**
     * Lists all tenants known to the system.
     *
     * @param ctx the current request
     */
    @Routed("/tenants")
    @DefaultRoute
    @LoginRequired
    @Permission(PERMISSION_MANAGE_TENANTS)
    public void tenants(WebContext ctx) {
        PageHelper ph = PageHelper.withQuery(oma.select(Tenant.class).orderAsc(Tenant.NAME));
        ph.withContext(ctx);
        ph.withSearchFields(Tenant.NAME,
                            Tenant.ACCOUNT_NUMBER,
                            Tenant.ADDRESS.inner(AddressData.STREET),
                            Tenant.ADDRESS.inner(AddressData.CITY));

        ctx.respondWith().template("templates/tenants/tenants.html.pasta", ph.asPage());
    }

    /**
     * Provides an editor for updating a tenant.
     *
     * @param ctx      the current request
     * @param tenantId the id of the tenant to change
     */
    @Routed("/tenant/:1")
    @LoginRequired
    @Permission(PERMISSION_MANAGE_TENANTS)
    public void tenant(WebContext ctx, String tenantId) {
        Tenant tenant = find(Tenant.class, tenantId);

        SaveHelper saveHelper = prepareSave(ctx).withAfterCreateURI("/tenant/${id}").withAfterSaveURI("/tenants");
        saveHelper.withPreSaveHandler(isNew -> {
            tenant.getPermissions().getPermissions().clear();
            for (String permission : ctx.getParameters("permissions")) {
                // Ensure that only real permissions end up in the permissions list,
                // as roles, permissions and flags later end up in the same vector
                // therefore we don't want nothing else but tenant permissions in this list
                if (getPermissions().contains(permission)) {
                    tenant.getPermissions().getPermissions().add(permission);
                }
            }
        });

        boolean requestHandled = saveHelper.saveEntity(tenant);
        if (!requestHandled) {
            validate(tenant);
            ctx.respondWith()
               .template("templates/tenants/tenant-details.html.pasta",
                         tenant,
                         this,
                         oma.select(Tenant.class)
                            .orderAsc(Tenant.NAME)
                            .where(FieldOperator.on(Tenant.ID).notEqual(tenant.getId()))
                            .queryList());
        }
    }

    /**
     * Provides a JSON API to change the settings of a tenant, including its configuration.
     *
     * @param ctx      the current request
     * @param out      the JSON response being generated
     * @param tenantId the id of the tenant to update
     */
    @Routed(value = "/tenant/:1/update", jsonCall = true)
    @LoginRequired
    @Permission(PERMISSION_MANAGE_TENANTS)
    public void tenantUpdate(WebContext ctx, JSONStructuredOutput out, String tenantId) {
        Tenant tenant = find(Tenant.class, tenantId);
        assertNotNew(tenant);
        load(ctx, tenant);
        if (ctx.hasParameter(Tenant.PERMISSIONS.inner(PermissionData.CONFIG_STRING).getName())) {
            tenant.getPermissions().getConfig();
        }
        tenant.getPermissions().getPermissions().clear();
        for (String permission : ctx.getParameters("permissions")) {
            // Ensure that only real roles end up in the permissions list,
            // as roles, permissions and flags later end up in the same vector
            // therefore we don't want nothing else but tenant permissions in this list
            if (getPermissions().contains(permission)) {
                tenant.getPermissions().getPermissions().add(permission);
            }
        }

        oma.update(tenant);
    }

    /**
     * Provides an editor for changing the config of a tenant.
     *
     * @param ctx      the current request
     * @param tenantId the id of the tenant to change
     */
    @Routed("/tenant/:1/config")
    @LoginRequired
    @Permission(PERMISSION_MANAGE_TENANTS)
    public void tenantConfig(WebContext ctx, String tenantId) {
        Tenant tenant = find(Tenant.class, tenantId);
        assertNotNew(tenant);
        ctx.respondWith().template("templates/tenants/tenant-config.html.pasta", tenant);
    }

    /**
     * Deletes the given tenant and returns the list of tenants.
     *
     * @param ctx      the current request
     * @param tenantId the id of the tenant to delete
     */
    @Routed("/tenant/:1/delete")
    @LoginRequired
    @Permission(PERMISSION_MANAGE_TENANTS)
    public void deleteTenant(WebContext ctx, String tenantId) {
        Optional t = oma.find(Tenant.class, tenantId);
        if (t.isPresent()) {
            if (t.get().getId() == currentTenant().getId()) {
                throw Exceptions.createHandled().withNLSKey("TenantController.cannotDeleteSelf").handle();
            }
            oma.delete(t.get());
            showDeletedMessage();
        }
        tenants(ctx);
    }

    /**
     * Lists all tenants which the current user can "become" (switch to).
     *
     * @param ctx the current request
     */
    @Routed("/tenants/select")
    @LoginRequired
    @Permission(TenantUserManager.PERMISSION_SELECT_TENANT)
    public void selectTenants(WebContext ctx) {
        SmartQuery baseQuery = queryPossibleTenants(ctx).orderAsc(Tenant.NAME);
        PageHelper ph = PageHelper.withQuery(baseQuery);
        ph.withContext(ctx);
        ph.withSearchFields(Tenant.NAME,
                            Tenant.ACCOUNT_NUMBER,
                            Tenant.ADDRESS.inner(AddressData.STREET),
                            Tenant.ADDRESS.inner(AddressData.CITY));

        ctx.respondWith().template("templates/tenants/select-tenant.html.pasta", ph.asPage(), isCurrentlySpying(ctx));
    }

    private boolean isCurrentlySpying(WebContext ctx) {
        return ctx.getSessionValue(UserContext.getCurrentScope().getScopeId() + TenantUserManager.TENANT_SPY_ID_SUFFIX)
                  .isFilled();
    }

    /**
     * Makes the current user belong to the given tenant.
     *
     * @param ctx the current request
     * @param id  the id of the tenant to switch to
     */
    @LoginRequired
    @Routed("/tenants/select/:1")
    public void selectTenant(final WebContext ctx, String id) {
        if ("main".equals(id)) {
            ctx.setSessionValue(UserContext.getCurrentScope().getScopeId() + TenantUserManager.TENANT_SPY_ID_SUFFIX,
                                null);
            ctx.respondWith().redirectTemporarily("/tenants/select");
            return;
        }

        assertPermission(TenantUserManager.PERMISSION_SELECT_TENANT);

        SmartQuery baseQuery = queryPossibleTenants(ctx).eq(Tenant.ID, id);

        Tenant tenant = baseQuery.queryFirst();
        if (tenant == null) {
            UserContext.get().addMessage(Message.error(NLS.get("TenantController.cannotBecomeTenant")));
            selectTenants(ctx);
            return;
        }

        ctx.setSessionValue(UserContext.getCurrentScope().getScopeId() + TenantUserManager.TENANT_SPY_ID_SUFFIX,
                            tenant.getIdAsString());
        ctx.respondWith().redirectTemporarily(ctx.get("goto").asString(wondergemRoot));
    }

    private SmartQuery queryPossibleTenants(WebContext ctx) {
        String tenantId = ((TenantUserManager) UserContext.get().getUserManager()).getOriginalTenantId(ctx);
        Optional originalTenant = oma.find(Tenant.class, tenantId);
        if (originalTenant.isPresent()) {
            SmartQuery baseQuery = oma.select(Tenant.class);
            if (!hasPermission(TenantUserManager.PERMISSION_SYSTEM_TENANT)) {
                if (originalTenant.get().isCanAccessParent()) {
                    baseQuery.where(Or.of(And.of(FieldOperator.on(Tenant.PARENT).eq(tenantId),
                                                 FieldOperator.on(Tenant.PARENT_CAN_ACCESS).eq(true)),
                                          FieldOperator.on(Tenant.ID).eq(originalTenant.get().getParent().getId())));
                } else {
                    baseQuery.where(And.of(FieldOperator.on(Tenant.PARENT).eq(tenantId),
                                           FieldOperator.on(Tenant.PARENT_CAN_ACCESS).eq(true)));
                }
            }
            return baseQuery;
        } else {
            throw Exceptions.createHandled().withSystemErrorMessage("Cannot determine current tenant!").handle();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy