Hello all,
We are trying to ensure that one of several specific users is selected within a User Picker (single user) customfield; and that the specific user selected is within the department selected within a previous Select List (Single Choice) customfield present to the user.
For example:
We have a Select List (Single Choice) customfield called Dept which contains all departments within our group. This field asks the submitter to select their corresponding department.
After the user selects the department they are within, a User Picker (single user) customfield named Internal Approver shows up and allows the submitter to select a single user. We only want them to select from one of the following users:
1) Bob Smith (Username = bobSm)
2) Michael M (Username = micmal)
3) Test_user (Username = TestUser1)
I've been trying to create a script that handles all of this, but I can't seem to get it to work. So far I have the following:
cfValues['Dept'] == 'Dept1' && cfValues['Internal Approver'] == 'Bob Smith' || cfValues['Internal Approver'] == 'Michael M' || cfValues['Internal Approver'] == 'Test_User'
Can someone help me here?
Thanks,
Mike
Conclusion:
TLDR for those who don't want to read the back and forth. I wanted to have a validator within my create screen which allowed me to use a Select List (Single Choice) customfield to allow only specific "approvers" per value selectable within the afore mentioned Select List (Single Choice) customfield.
The code below is what we came up with:
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
Map<String, List<String>> departmentApproverMap = [
Dept1: ['bobSm', 'micmal', 'TestUser1'],
Dept2: ['jwillians', 'tessk'],
//etc
]
def deptCf = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName('Dept')[0]
def approverCf = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName('Internal Approver')[0]
def approverName = issue.getCustomFieldValue(approverCf)?.name as String
def deptValue = issue.getCustomFieldValue(deptCf)?.value as String
//add some code here is you need to do something if either dept or approver fields are empty
//For example
if (!deptValue) {
throw new InvalidInputException(deptCf.id, 'You must select the Department')
}
if (!approverName) {
throw new InvalidInputException(approverCf.id, 'You must select the approver')
}
def validApprovers = departmentApproverMap[deptValue] as List<String>
if(!validApprovers){
log.warn "The script does not contain approval mapping for deparment: $deptValue"
return
}
if (!validApprovers.contains(approverName)) {
def approverUserFullNames = validApprovers.findResults {userName->
def user = ComponentAccessor.userManager.getUserByName(userName)
if(!user){
log.warn "The script contains an invalid username: $userName"
return null
}
return user.displayName
}
throw new InvalidInputException(deptCf.id, "You selected a user that is not in the approved list: ${approverUserFullNames.join(', ')}")
}
For single select fields, cfValues['Dept'] will give you an instance of an Option object.
To caompare it to a it to a string, you have to look a the getValue method.
Simliar thing for the userPicker. Those will be instanced of ApplicationUser.
If you are not sure, you can output the getClass() to the log then lookup in the details.
Try something like this
def approverName = cfValues['Internal Approver'].name
def deptValue = cfValues['Dept'].value == 'Dept1'
deptValue == 'Dept1' && approverName in ['bobSm', 'micmal, 'TestUser1']
Hello @PD Sheehan
For some reason this did not work. I've made sure to add the additional ' behind the micmal user name, but for some reason the validation always seems to come up false.
I've looked at the workflow log, and all relating values within the needed fields are correct with the exception of the Internal Approver name. The value within that field has both the username as well as their ID within it. Example: "micmal (JIRAUSER12345)".
Could this by why it's failing?
Thanks,
Mike
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I think I missed that it was a multi-select.
In which case the value is an array of options.
To know the exact class returned, you need to manually output something to the log
e.g.
log.info "The value of 'Dept' is of type: ${cfValues[Dept].getClass()}"
I think this should work
def approverName = cfValues['Internal Approver'].name
def deptValues = cfValues['Dept'].value
'Dept1' in deptValues && approverName in ['bobSm', 'micmal', 'TestUser1']
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi again @PD Sheehan
The "Dept" field is a single select. and the Internal Approver field is "single select user picker".
I should have stated up above, but I'm also looking to have specific users be the only "valid" choice for specific departments selected within the "Dept" single select drop down field.
Example:
Dept 1 = Bob Smith, Michael M, Test_User
Dept 2 = James Williams, Tess K
Dept 3 = Matt Smith, Joe Moe
I would assume that this would change the requirements of my scripting quite a bit correct?
Thanks,
Mike
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Ah and if you will have multiple combinations to check try something like this:
The question however is, which approvers are allowed when multiple departments are selected? If any approver from any of the depatments, you can try this:
def departmentApproverMap = [
Dept1 : ['bobSm', 'micmal', 'TestUser1'],
Dept2 : ['jwillians', 'tessk'],
//etc
]
def approverName = cfValues['Internal Approver'].name
def deptValues = cfValues['Dept'].value
deptValues.any{dept->
approverName in departmentApproverMap[dept]
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Scratch all this, I need more caffein this morning.
I read "multi-field" and assumed multi select.
Let's try this again:
def departmentApproverMap = [
Dept1 : ['bobSm', 'micmal', 'TestUser1'],
Dept2 : ['jwillians', 'tessk'],
//etc
]
def approverName = cfValues['Internal Approver'].name
def deptValue = cfValues['Dept'].value
approverName in departmentApproverMap[deptValue]
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks again @PD Sheehan
This is working as I need it; and now I have an additional question - Sorry!
I want to display a different error message per "dept" group if the user selected isn't in the "approved group".
Example:
If "Dept1" was selected; I wanted to display something like "You selected a user that is not Bob smith, michael m, OR Test User 1 - Please select a user from this grouping to continue.
If "Dept2" was selected; I wanted to display a similar message but with the other names within the "approved group" (IE: You selected a user that is not James Williiams OR Tess K - Please select a user from this grouping to continue.)
Is there a way to set specific error messages per user group? And if I do that, would this script need to be moved out of the "simple scripted validator" and into the "Custom script validator" option?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You'll have to switch from a "Simple Script Validator" to "Custom Script Validator":
And go into a bit more details
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
Map<String,List<String>> departmentApproverMap = [
Dept1 : ['bobSm', 'micmal', 'TestUser1'],
Dept2 : ['jwillians', 'tessk'],
//etc
]
def approverName = cfValues['Internal Approver']?.name as String
def deptValue = cfValues['Dept']?.value as String
//add some code here is you need to do something if either dept or approver fields are empty
//For example
if(!deptValue){
throw new InvalidInputException('cusomtfield_xxxx','You must select the Department')
}
if(!approverName){
throw new InvalidInputException('cusomtfield_yyyy','You must select the approver')
}
def validApprovers = departmentApproverMap[deptValue] as List<String>
if(!validApprovers.contains(approverName)){
def approverUsers = validApprovers.collect{ComponentAccessor.userManager.getUserByName(it)}
throw new InvalidInputException('cusomtfield_xxxx', "You selected a user that is not in the approved list: ${approverUsers*.displayName.join(', ')}")
}
Be sure to replace xxxx and yyyy with the appropriate customfield id.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi again @PD Sheehan
Thanks for the continued help! When I input the code above into the custom script validator, I'm getting a [Static type checking] - The variable [cfValues] is undeclared for the cf[Values] within the script.
Would you know how to fix this?
Thanks,
mike
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Ah of course, the cfValues quick access is not available in custom script configurations.
You have to fetch the customfield object first then call issue.getCustomFieldValue
Try this instead:
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
Map<String, List<String>> departmentApproverMap = [
Dept1: ['bobSm', 'micmal', 'TestUser1'],
Dept2: ['jwillians', 'tessk'],
//etc
]
def cfm = ComponentAccessor.customFieldManager
def deptCf = cfm.getCustomFieldObjectsByName('Dept')[0]
def approverCf = cfm.getCustomFieldObjectsByName('Internal Approver')[0]
def approverName = issue.getCustomFieldValue(approverCf)?.name as String
def deptValue = issue.getCustomFieldValue(deptCf)?.value as String
//add some code here is you need to do something if either dept or approver fields are empty
//For example
if (!deptValue) {
throw new InvalidInputException(deptCf.id, 'You must select the Department')
}
if (!approverName) {
throw new InvalidInputException(approverCf.id, 'You must select the approver')
}
def validApprovers = departmentApproverMap[deptValue] as List<String>
if (!validApprovers.contains(approverName)) {
def approverUsers = validApprovers.collect { ComponentAccessor.userManager.getUserByName(it) }
throw new InvalidInputException(deptCf.id, "You selected a user that is not in the approved list: ${approverUsers*.displayName.join(', ')}")
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi again @PD Sheehan
When I try to create an issue where this validator is being used, it allows all users to be selected, and not just the groupings we added to the script. It also gave me an error when I look at the workflow validator log.
I'm trying to add the error to this comment, but the forums are giving me an "html" error constantly...
The error within the workflow states The workflow script has failed for 'jwillians' and that there is a java lang NullPointerException - Cannot invoke method contains on null object.
Does this error make sense to you?
Thanks again for all the continued help!
Mike
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You'll notice that like 5,6,7 are not necessarily complete.
You need to make sure you map all your departments with the correct list of user names.
In this case, I invented "jwillians" based on the full name you provided. You have to replace with the correct username.
I modified the script to validate things and provide some better feedback in the logs:
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
Map<String, List<String>> departmentApproverMap = [
Dept1: ['bobSm', 'micmal', 'TestUser1'],
Dept2: ['jwillians', 'tessk'],
//etc
]
def deptCf = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName('Dept')[0]
def approverCf = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName('Internal Approver')[0]
def approverName = issue.getCustomFieldValue(approverCf)?.name as String
def deptValue = issue.getCustomFieldValue(deptCf)?.value as String
//add some code here is you need to do something if either dept or approver fields are empty
//For example
if (!deptValue) {
throw new InvalidInputException(deptCf.id, 'You must select the Department')
}
if (!approverName) {
throw new InvalidInputException(approverCf.id, 'You must select the approver')
}
def validApprovers = departmentApproverMap[deptValue] as List<String>
if(!validApprovers){
log.warn "The script does not contain approval mapping for deparment: $deptValue"
return
}
if (!validApprovers.contains(approverName)) {
def approverUserFullNames = validApprovers.findResults {userName->
def user = ComponentAccessor.userManager.getUserByName(userName)
if(!user){
log.warn "The script contains an invalid username: $userName"
return null
}
return user.displayName
}
throw new InvalidInputException(deptCf.id, "You selected a user that is not in the approved list: ${approverUserFullNames.join(', ')}")
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi again @PD Sheehan
Thanks for the tip! I was using an existing username, I just put the jwillians name as an example. I must have either miss-typed the name, or left a space in the name by accident. This code is working splendidly for me now!
Thank you VERY much for all your time. Have a great day ahead!
~mike
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
When querying single select list you will need to access its value property and if you are checking the username of the single user picker field then you need to query the username property. Additionally, the logic should be an OR operator instead of an AND if you want to pass validator for other departments (dept2, dept3 ...). Can you try this code and see if it works?
cfValues['Dept']?.value != 'Dept1' || cfValues['Internal Approver']?.getUsername() in ['Bob Smith', 'Michael M', 'Test_User']
If you only want to pass the validator if the dept1 is selected and its usernames then use an AND operator:
cfValues['Dept']?.value == 'Dept1' && cfValues['Internal Approver']?.getUsername() in ['Bob Smith', 'Michael M', 'Test_User']
The above query will fail the validator if other Depts are selected or other Internal Approvers are selected
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello @Sayed Bares _ServiceRocket_ ,
I should have originally stated that I want to setup this validator up for several different groups of people / departments; seeing as how I'm assuming that changes a lot about the script.
If I want to setup specific people per Department; for example:
Dept 1 = Bob Smith, Michael M, Test_User
Dept 2 = James Williams, Tess K
Dept 3 = Matt Smith, Joe Moe
How would I go about doing this?
Thanks,
Mike
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Michael just add an OR operation or use @PD Sheehan suggestion either way should work :)
(cfValues['Dept']?.value == 'Dept1' && cfValues['Internal Approver']?.getUsername() in ['Bob Smith', 'Michael M', 'Test_User']) || (cfValues['Dept']?.value == 'Dept2' && cfValues['Internal Approver']?.getUsername() in ['James Williams', 'Tess K']) || (cfValues['Dept']?.value == 'Dept3' && cfValues['Internal Approver']?.getUsername() in ['Matt Smith', 'Joe Moe'])
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.