Multi-tenancy

1. General

The Intrexx multi-tenancy facilitates weak data separation in large, adjoined company structures. If you have multiple tenants, the setup and usabilizty (e.g. in intranets) is made easier in many ways. Multi-tenancy also provides valuable support for B2B and B2C. Because the data separation is weak, having isolated file storage locations and exporting portals with data are impossible.

2. Multi-tenancy in the Users module




The three objects in the Users module form the basis for the tenant control. You can also create custom objects that can function as tenants.

2.1. Create tenant dependency




With the following, very simple structure we will show you how can link use objects to tenants. User A will be assigned to tenant "Organizational unit 1", User B to tenant "Organizational unit 1", and User C to both. Neither of the organizational units have anything particular about them but are simply created using the basic class "Organizational unit". As you can see, you do not have to use the tenant object to create a tenant.



In the first step, the user object, which should be assigned to a tenant, will be 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. Once the class has been selected from the left-hand area of the Schema Manager, an attribute can be created for this purpose via the "Edit menu / New attribute". In our example, we will create the attribute "Organizational assignment". If multiple tenants are assigned to one object (1:n), the "Text" type should be selected for the data field so that a list of tenant memberships can be saved. If there is only a 1:1 relationship and a string field is also selected as a reference attribute, then a string data field can also be used.



So that this attribute can be used to save the tenant ID, the "Contains tenant ID" is activated. Click on ""Edit reference" to open a dialog where the reference can be edited.



For our example, we select the class "Organizational unit", because "Organizational unit 1" and "Organizational unit 1" were created on this basis, as was described at the beginning. Any reference attribute can be defined here, meaning not just the LID or GUID, but also any other attribute that contains a unique identification value (e.g. organization abbreviation, cost center). The displayed attribute of the referenced class is also a free choice. In this case, we select the object name. So that User C can be assigned to both tenants, the "Support multiple values" option is selected here.

Close all dialogs with "OK". The tenant dependency has now been configured.

2.2. Tenant assignment




In the properties of a user, the tenant can now be assigned on the More attributes tab. To do this, highlight the attribute, which was created for the tenant 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 1", and User C to both.

3. Multi-tenancy in applications

3.1. 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.

3.2. Tenant control in filters

There is a new operator available for tables, multiple selections and data pickers: "Is contained in tenants". If the UserID is compared, only the entries assigned to the corresponding tenant will be shown.

3.3. Tenant control in distribution lists

In the multiple selection element, you can activate the setting Users and groups to select any objects as a distribution list. 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.

4. Groovy API

The Groovy API enables you to Here is a script example:
// Generate "Organization"

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 on ${new Date()}"
       INTERNALUSN    = 2
       STATE          = "BW"
       POBOX          = "UP"
       STREET         = "UP Road"
       ISOCOUNTRYCODE = "DE"
       CITY           = "Freiburg"
       POSTALCODE     = "79098"
       COUNTRY        = "Germany"
})

// Generate "Standard roles"
def role1 = g_om.createSet ("ROLE", {
	container      = organization1
	NAME           = strTitle + ": Employee"
	DESCRIPTION    = "Role created by Groovy on ${new Date()}"
	memberOf       = ["Users"]
})

// Generate "Additional roles"
def role2 = g_om.createSet ("ROLE", {
	container      = organization1
	NAME           = strTitle + ": Collective user"
	DESCRIPTION    = "Role created by Groovy on ${new Date()}"
	memberOf       = ["Users"]
})

// Delete roles
g_om.deleteSet(role1.GUID)
 
// Delete containers (All objects within the container 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 entered as a character string list (||) enable you to directly edit distribution list and multiple selection information from long text fields.
// Import the class
import de.uplanet.lucy.server.usermanager.groovy.GroovyTenantHelper

// Define a new TenantHelper object
def thelper = new  GroovyTenantHelper(g_session)

//
thelper.getTenants():Set<String>
thelper.getSelectedTenants():Set<String>
thelper.getAllTenantValues():String separated by ||
thelper.getSelectedTenantValues():String separated by ||

// Determine an active tenant
thelper.setSelectedTenant(String)

// Determine multiple active tenants. Defined by a list of tenants
thelper.setSelectedTenants(Set<String>)

// Determine multiple active tenants. The tenants are defined
// in the form of a character string separated by || (piped)
thelper.setSelectedTenants(String)
thelper.setSelectedTenants("TENANT1_ID||TENANT2_ID")

// Display the name of the first tenant
def tenantList = g_session.getTenants().get(0).getTitle()

// Check whether first tenant is selected
g_session.getTenants().tenantList.get(0).isSelected()

// Tenant ID
g_session.getTenants().tenantList.get(0).getValue()
import de.uplanet.lucy.server.ServerFeature

// Identifies the setting in the portal that restricts the
// selection of the active tenant to one tenant

ServerFeature.isSingleTenantMode()

5. Velocity API

The Velocity API enables you to
## Check tenant match (User – Data record)
#set($TenantMembersSelected = $Tenants.getAllTenantValues($Session))
#set($TenantMembersList = $TextUtil.stringToArray($TenantMembersSelected))
#set($TenantMembersSqlList = $TextUtil.arrayToString($TenantMembersList,",","'"))

#set($stmtTable = $PreparedQuery.prepare($DbConnection, 
"SELECT STR_TITEL FROM DATAGROUP('GUID') WHERE STR_MANDANT IN (?)"))
$stmtTable.setString(1, $TenantMembersSql)
#set($rsTable = $stmtTable.executeQuery())

#foreach($element in $rsTable)
	#set($Title = $element.getStringValue(1))
	$Title 
#end $rsTable.close() $stmtTable.close() ## Read object information (Attribute) #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 tenants 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 a character string list
## (separated 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 the name of the first tenant
#set($TenantList = $Tenants.getTenants($Session))
$TenantList.get(0).getTitle()

## Check whether first tenant is selected
$TenantList.get(0).isSelected()

## Tenant ID
$TenantList.get(0).getValue()

6. More information

Parameter dialog Velocity Docs
Groovy Docs