Multi-tenancy
The Intrexx multi-tenancy facilitates weak data separation in large, adjoined company structures.
With several clients, the structure and operation (e.g. in intranets) is greatly simplified in many places. Multi-tenancy also provides valuable support for B2B and B2C.
Because the data separation is weak, having isolated filebox locations and exporting portals with data are impossible.
Multi Tenancy in the "User" module
The three objects form the basis for client control
-
Country
-
Tenant
-
Location
in the "User" module. In the schema manager, you can define your own new objects that can act as clients.
Create tenant dependency
With the following, very simple structure we will show you how can link use objects to tenants.
User A is assigned to client "Organizational unit 1", user B to client "Organizational unit 2" and user C to both clients.
The two organizational units have no special features; they are created with the "Organizational unit" base class. The "Client" object therefore does not necessarily have to be used to create a client.
In the first step, the user object that is to be assigned to a client is edited in the schema manager.
In our example, User A, B and C are to be assigned to a tenant. These users are based on the "User" class.
If the class is selected in the left-hand area of the schema manager, an attribute can be created for this purpose via the "Edit / New attribute" menu - in our example here the "Organization assignment" attribute.
If several clients are assigned to an object (1:n), "Text" should be selected as the type for the data field so that a list of client affiliations can be saved. If there is only a 1:1 assignment and a string field is also defined as a reference attribute, a string data field can also be used.
The "Contains client ID" setting is activated so that the "Organization assignment" attribute is used to save the client ID. Click on "Edit reference" to open a dialog in which the reference can be edited.
The "Organizational unit" class is selected here for our example because "Organizational unit 1" and "Organizational unit 2" were created based on this class as described at the beginning.
Any reference attribute can be specified, i.e. not only the LID or GUID, but also another attribute that contains a unique identification value (e.g. organization abbreviation, cost centre). The displayed attribute of the referenced class is also a free choice. In this case, we select the object name. The "Allow multiple reference" setting is activated so that user C can be assigned to both clients.
If all dialogs are closed by clicking on "OK", the client dependency is set up.
Tenant assignment
In the properties of a user, the client can now be assigned on the "Other attributes" tab. To do this, select the attribute that you have created for the client dependency and click on "Edit value" in the "Value" column.
In our example User A will be assigned to ""Organizational unit 1"", User B to ""Organizational unit 2"", and User C to both.
Multi-tenancy in applications
Tenant control in data groups
A strict tenant control is achieved using the tenant filter in data groups. There, the relationship between the user's tenant membership and the data record can be established. There is an n:1 binding directly in the data group or an n:n binding via a child data group, which enables multiple tenant assignments per data record.
Tenant control in filters
For tables, selection lists, multiple selection and data pickers, there is the "Is contained in clients" operator. If a comparison is made with the user ID, only the entries assigned to the corresponding client are displayed.
Tenant control in distribution lists
In the "Multiple selection" element, any objects can be selected to define a distribution list using the "Distribution list selection" setting. A filter can be applied to the objects to only provide users or roles for selection that have been assigned to the tenant of the current user, for example.
Groovy API
The Groovy API enables you to
-
create objects for defining tenants and organizational structures
-
create groups, roles, distribution lists and their memberships in other objects
-
edit all objects
-
delete all objects
Here is a script example:
// Create "Organisation"
def strTitle = g_record["GUID"].value /* datafield Title <string> */
def strParentNode = g_record["GUID"].value /* datafield Tenant <string> */
def organization1 = g_om.createContainer ("ORGANIZATION", {
container = strParentNode
NAME = strTitle
EXTERNALGUID = "1235"
PRIORITY = 25
DN = "testDN"
DISABLED = false
DESCRIPTION = "Organization created by Groovy around ${new Date()}"
INTERNALUSN = 2
STATE = "BW"
POBOX = "UP"
STREET = "UP-Alley"
ISOCOUNTRYCODE = "DE"
CITY = "Freiburg"
POSTALCODE = "79098"
COUNTRY = "Germany"
})
// Create "default roles"
def role1 = g_om.createSet ("ROLE", {
container = organization1
NAME = strTitle + ": Employee"
DESCRIPTION = "Role created by Groovy on ${new Date()}"
memberOf = ["Users"]
})
// Create "additional roles"
def role2 = g_om.createSet ("ROLE", {
container = organization1
NAME = strTitle + ": User"
DESCRIPTION = "Role created by Groovy on ${new Date()}"
memberOf = ["Users"]
})
// Delete roles
g_om.deleteSet(role1.GUID)
// Delete container (All included objects will also be deleted!)
g_om.deleteContainer(containerBase1.GUID)
To identify the tenant memberships of a logged-in user and the tenant objects selected for the session, the GroovyTenantHelper is available in the Groovy context. When defining a GroovyTenantHelper object, the current session is stated as a parameter. Furthermore, the GroovyTenantHelper can be used to modify the selection of the active tenants in the session. The variants as a string list (||) enable the direct processing of distribution list or multiple selection information from long text fields.
// Import of class
import de.uplanet.lucy.server.usermanager.groovy.GroovyTenantHelper
// Definition of a new TenantHelper object
def thelper = new GroovyTenantHelper(g_session)
//
thelper.getTenants():Set<String>thelper.getSelectedTenants():Set<String>thelper.getAllTenantValues():String seperated by ||
thelper.getSelectedTenantValues():String seperated by ||
// Define an active tenant
thelper.setSelectedTenant(String)
// Define multiple active tenants - the definition is made by a list of tenants
thelper.setSelectedTenants(Set<String>)
//Define multiple active tenants - the definition
// of tenants is made in the form of a list as a string seperated by ||
thelper.setSelectedTenants(String)
thelper.setSelectedTenants("TENANT1_ID||TENANT2_ID")
import de.uplanet.lucy.server.ServerFeature
// Determines the setting in the portal that determines the selection of the active
// tenants limited to one tenant
ServerFeature.isSingleTenantMode()
Velocity API
The API in Velocity enables
-
checking client membership (user object against client object)
-
the determination of attributes of an object (client, organization, organizational unit, role, group)
## Check for tenant match (user - record)
#set($TenantMembersSelected = $Tenants.getAllTenantValues($Session))
#set($TenantMembersSqlList = $TenantMembersSelected.replace("||", "','") )
#set($stmtTable = $PreparedQuery.prepare($DbConnection,
"SELECT STR_TITEL FROM DATAGROUP('GUID') WHERE STR_MANDANT IN (?)"))
$stmtTable.setString(1, $TenantMembersSqlList)
#set($rsTable = $stmtTable.executeQuery())
#foreach($element in $rsTable)
#set($Title = $element.getStringValue(1))
$Title <br>#end
$rsTable.close()
$stmtTable.close()
## Read object information (attributes)
#set($ObjectGuid = "8808E768D142663695576F533A27E5CAC2739552")
#set($stmtObject = $PreparedQuery.prepare($DbConnection, "SELECT STRIDENT FROM VDSTENANT WHERE STRGUID = ?"))
$stmtObject.setString(1, $ObjectGuid)
#set($ObjectIdent= $stmtObject.executeAndGetScalarStringValue(""))
$stmtObject.close()
The following methods are provided for the clients with the $Tenants object:
## List of all tenants of the current user
$Tenants.getTenants($Session)
## List of all selected tenants of the current user/session
$Tenants.getSelectedTenants($Session)
## Piped-List of all selected tenants of the current user
$Tenants.getSelectedTenantValues ($Session)
## Number of tenants of the current user
$Tenants.getTenants($Session).size()
## All tenants of the current user as string list
## (seperated by ||)
$Tenants.getAllTenantValues($Session)
## Number of selected tenants
$Tenants.getSelectedCount($Session))
The following methods can be applied to the list of tenant objects (getTenants / getSelectedTenants):
## Display of the name of the first tenant
#set($TenantList = $Tenants.getTenants($Session))
$TenantList.get(0).getTitle()
## Check if first tenant is selected
$TenantList.get(0).isSelected()
## ID of the tenant
$TenantList.get(0).getValue()