Page tree
Skip to end of metadata
Go to start of metadata

Business description

To secure the cost process, our company decided to block unauthorized employees' possibility of seeing issues. Access to them will be related to the department and cost center or cost group and cost category.

Solution Brief

Using decision tables, we will calculate which group is authorized and set them to the custom field. Final validation will be done based on that data.

We prepare two decision tables to solve that - each one will return a list of groups based on related parameters.

Example Decision Table

Script

Note

In this script, we use some superclasses, which help us in code management. For more information, see the Usage of base groovy classes and utilities page.

import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import eu.rivetgroup.atlas.jira.fields.api.exceptions.ExceptionHandlingMode
import global.fields.CustomFieldCode
import global.fields.FieldUtils

@WithPlugin([
		"eu.rivetgroup.atlas.rvg-jira-app-base-plugin",
		"eu.rivetgroup.atlas.rvg-jira-decision-tables-plugin"
])
class TestSetAccessDataPostFunction extends BaseDecisionTablePostFunction {

	TestSetAccessDataPostFunction(Map<String, Object> transientVars, boolean validatorMode) {
		super(transientVars, validatorMode, false)
	}

	@Override
	protected boolean executeInternal() {
		def departmentField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.DEPARTMENT_CF))
		def costCentreField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.COST_CENTRE))

		def costGroupField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.COST_GROUP))
		def costCategoryField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.COST_CATEGORY))

		def groupAssigneeField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.GROUP_ASSIGNEE))
		def accessibleForGroupsField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.ACCESSIBLE_FOR_GROUPS))

		accessibleForGroupsField.config.exceptionHandlingStrategy.globalCheckStrategy
				.setSourceHandlingMode(ExceptionHandlingMode.REGISTER)
				.setRegistryHandlingMode(ExceptionHandlingMode.LOG_WARNING)

		issueFieldOperator.config.setUseTransientFieldValues(true)

		accessibleForGroupsField.setObjectValue(null)

		accessibleForGroupsField.appendValue(groupAssigneeField.getValue().multi())

		def dtCostCentreResult = decisionTableManager.getDMNDecisionTableOperations(
				"costAccess",
				"costCentreAccess"
		).executeQuery([
				"department": departmentField.getBusinessKey().first(),
				"costCentre": costCentreField.getBusinessKey().first()
		])


		issueFieldOperator.getConfig().setCurrentExecutionInfo(dtCostCentreResult.executionContextInfo)

		def groupNames = dtCostCentreResult.multiNonNull().collect({elem -> elem.get("accessibleForGroups")})

		accessibleForGroupsField.appendValue(accessibleForGroupsField.getValueByBusinessKey(groupNames))

		def dtCategoryResult = decisionTableManager.getDMNDecisionTableOperations(
				"costAccess",
				"costCategoryAccess"
		).executeQuery([
				"costGroup": costGroupField.getBusinessKey().first(),
				"costCategory": costCategoryField.getBusinessKey().first()
		])
		issueFieldOperator.getConfig().setCurrentExecutionInfo(dtCategoryResult.executionContextInfo)

		groupNames = dtCategoryResult.multiNonNull().collect({elem -> elem.get("accessibleForGroups")})

		accessibleForGroupsField.appendValue(accessibleForGroupsField.getValueByBusinessKey(groupNames))
		return true;
	}
}

Explanation

@WithPlugin([
	"eu.rivetgroup.atlas.rvg-jira-app-base-plugin",
	"eu.rivetgroup.atlas.rvg-jira-decision-tables-plugin"
])
class TestSetAccessDataPostFunction extends BaseDecisionTablePostFunction {

TestSetAccessDataPostFunction(Map<String, Object> transientVars, boolean validatorMode) {
	super(transientVars, validatorMode, false)
}

Traditionally, we start with import functionalities and declare a constructor.

def departmentField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.DEPARTMENT_CF))
def costCentreField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.COST_CENTRE))

def costGroupField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.COST_GROUP))
def costCategoryField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.COST_CATEGORY))

def groupAssigneeField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.GROUP_ASSIGNEE))
def accessibleForGroupsField = issueFieldOperator.forField(FieldUtils.getCustomField(CustomFieldCode.ACCESSIBLE_FOR_GROUPS))

The next step is to get references to the necessary fields.

accessibleForGroupsField.config.exceptionHandlingStrategy.globalCheckStrategy
				.setSourceHandlingMode(ExceptionHandlingMode.REGISTER)
				.setRegistryHandlingMode(ExceptionHandlingMode.LOG_WARNING)

This time we want to register possible errors - for example, non-existing group. In that situation, terminate the operation is unnecessary, but we would like to log them, just in case.

issueFieldOperator.config.setUseTransientFieldValues(true)

 We are going to combine results from two decision tables and the current group assignee if it exists. We will do this using transient variables. Thanks to them, all changes are made on variables that do not interfere with change history.

accessibleForGroupsField.setObjectValue(null)
accessibleForGroupsField.appendValue(groupAssigneeField.getValue().multi())

Operations are started with clear field values and set there the currently assigned group.

def dtCostCentreResult = decisionTableManager.getDMNDecisionTableOperations(
	"costAccess",
	"costCentreAccess"
).executeQuery([
	"department": departmentField.getBusinessKey().first(),
	"costCentre": costCentreField.getBusinessKey().first()
])
issueFieldOperator.getConfig().setCurrentExecutionInfo(dtCostCentreResult.executionContextInfo)

We get possibilities from the first decision table.

def groupNames = dtCostCentreResult.multiNonNull().collect({elem -> elem.get("accessibleForGroups")})
accessibleForGroupsField.appendValue(accessibleForGroupsField.getValueByBusinessKey(groupNames))

And add them to such field values.

def dtCategoryResult = decisionTableManager.getDMNDecisionTableOperations(
	"costAccess",
	"costCategoryAccess"
).executeQuery([
	"costGroup": costGroupField.getBusinessKey().first(),
	"costCategory": costCategoryField.getBusinessKey().first()
])

issueFieldOperator.getConfig().setCurrentExecutionInfo(dtCategoryResult.executionContextInfo)
groupNames = dtCategoryResult.multiNonNull().collect({elem -> elem.get("accessibleForGroups")})
accessibleForGroupsField.appendValue(accessibleForGroupsField.getValueByBusinessKey(groupNames))

Analogously, we add values calculated by second decision tables.

Attachments

TestSetAccessDataPostFunction.groovycostAccess.dmn

  • No labels