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