Custom field containing security levels as select list

Carlos David August 2, 2017

 

I'm trying to populate a select list (on the create issue screen) populated with security levels . It is not appropriate to simply show the Security Level field (I understand that I can't simply rename it). I haven't been able to find a custom field type suitable.

Any help appreciated,

 

Thanks

 

2 answers

0 votes
adammarkham
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
August 2, 2017

You could use a behaviour for this to create the options and then restrict the list.

Adapting the last example here could work for you.

I'd follow some of the examples from our documentation and see if behaviours would work for you.

You can get the various security levels for that project by using (for some reason I can't post formatted code so I've added it as below):

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.security.IssueSecuritySchemeManager

def issueSecurityLevelManager = ComponentAccessor.getIssueSecurityLevelManager()
def issueSecuritySchemeManager = ComponentAccessor.getComponent(IssueSecuritySchemeManager)

def srcProject = underlyingIssue.getProjectObject()
def issueSecurityScheme = issueSecuritySchemeManager.getSchemeFor(srcProject)

if (! issueSecurityScheme) {
log.warn("No issue security scheme defined for project ${srcProject.name}".toString())
return null
}

def securityLevels = issueSecurityLevelManager.getIssueSecurityLevels(issueSecurityScheme.id)

def securityLevelNames = securityLevels*.name

Carlos David August 7, 2017

does this mean the script is run every single time any issue is updated? Is that practical?

Carlos David August 8, 2017

Thanks Adam, I'm now able to populate a custom field with security levels using the code:

import com.atlassian.jira.security.groups.GroupManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.security.IssueSecurityLevel
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.security.IssueSecuritySchemeManager
import com.atlassian.jira.issue.security.IssueSecurityLevelManager
import com.atlassian.jira.component.ComponentAccessor

IssueSecuritySchemeManager issueSecuritySchemeManager = ComponentAccessor.getComponent(IssueSecuritySchemeManager.class)
IssueSecurityLevelManager issueSecurityLevelManager = ComponentAccessor.getComponent(IssueSecurityLevelManager.class)

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cField= customFieldManager.getCustomFieldObjectByName("Etest")
def issue = event.issue as Issue
def srcProject = issue.getProjectObject()
def issueSecurityScheme = issueSecuritySchemeManager.getSchemeFor(srcProject)

def optionsManager = ComponentAccessor.getOptionsManager()
def issueService = ComponentAccessor.getIssueService()

if (! issueSecurityScheme) {
log.warn("No issue security scheme defined for project ${srcProject.name}".toString())
return null
}

def securityLevels = issueSecurityLevelManager.getIssueSecurityLevels(issueSecurityScheme.id)
def securityLevelNames = securityLevels*.name
log.debug "sec level names: " + securityLevelNames

def fieldConfig = cField.getRelevantConfig(issue)
def currentOptions = optionsManager.getOptions(fieldConfig)

def newSecurityLevelNames = []

log.debug " current options: " + currentOptions

for (i in securityLevelNames){
log.debug i
if (!currentOptions.toString().contains(i)){
log.debug " new sec level " + i + " found "
newSecurityLevelNames.add(i)
}
}

for (i in newSecurityLevelNames){
def newSeqId = currentOptions*.sequence.max() - 1
optionsManager.createOption(fieldConfig, null, newSeqId, i.toString())
}
Carlos David August 8, 2017

The list of security levels will be static so I will look to adapt this script to be run from the console as part of the Jira deployment, rather than running as a listener. Or is there any way I can setup the listener to trigger when a new security level (or the config is changed) is added?

What does the remaining code from the example do? Is this to update the create issue form on the fly?



def issueInputParameters = IssueService.newIssueInputParameters()

issueInputParameters.with {
addCustomFieldValue(faveFruitFld.idAsLong, option.optionId.toString())
addCustomFieldValue(faveFruitOtherFld.idAsLong,
null) }
def updateValidationResult = issueService.validateUpdate(currentUser, issue.id, issueInputParameters)
if (updateValidationResult.isValid()) {
issueService.update(currentUser, updateValidationResult) }
else {
log.warn(
"Failed to update issue: ${issue.key}: ${updateValidationResult.errorCollection}")
}

Thanks for your help

adammarkham
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
August 8, 2017

You should pull the security levels when you populate the list. That way they will keep in sync. The last part of that example was more to show you how to create new custom field options for your custom field in the current script you have. I see you already have that so you won't need anything else from that.

There is an IssueSecurityLevelAddedEvent in JIRA but we don't support those type of events in ScriptRunner at the moment. It could be done using behaviours which would allow the updated to be done automatically when a new security level is added.

Carlos David August 8, 2017

Thanks Adam.

 

I've adapted my listener to work as a Behaviour (code is 99% the same), but nothing happens. The code below is added as the Initializer, and I've added appropriate workflow & field mapping to the Behaviour. I don't get anything written to the log - can you help? Also, I'd like this behaviour to trigger on "Edit Issue" also - is this a valid ActionName?

 

import com.atlassian.jira.security.groups.GroupManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.security.IssueSecurityLevel
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.security.IssueSecuritySchemeManager
import com.atlassian.jira.issue.security.IssueSecurityLevelManager
import com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Logger
import org.apache.log4j.Level

// set a select list value -- also same for radio buttons
if (getActionName() != "Create Issue") {
return // not the initial action, so don't set default values
}

IssueSecuritySchemeManager issueSecuritySchemeManager = ComponentAccessor.getComponent(IssueSecuritySchemeManager.class)
IssueSecurityLevelManager issueSecurityLevelManager = ComponentAccessor.getComponent(IssueSecurityLevelManager.class)

def log = Logger.getLogger("com.apache.CreateSubTask")
log.setLevel(Level.DEBUG)

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cField= customFieldManager.getCustomFieldObjectByName("Entity")
//def issue = Issue
def srcProject = underlyingIssue?.getProjectObject()
def issueSecurityScheme = issueSecuritySchemeManager.getSchemeFor(srcProject)

def optionsManager = ComponentAccessor.getOptionsManager()
def issueService = ComponentAccessor.getIssueService()

if (! issueSecurityScheme) {
log.warn("No issue security scheme defined for project ${srcProject.name}".toString())
return null
}

def securityLevels = issueSecurityLevelManager.getIssueSecurityLevels(issueSecurityScheme.id)
def securityLevelNames = securityLevels*.name
log.debug "sec level names: " + securityLevelNames

def fieldConfig = cField.getRelevantConfig(getIssueContext())
def currentOptions = optionsManager.getOptions(fieldConfig)

def newSecurityLevelNames = []

log.debug " current options: " + currentOptions

for (i in securityLevelNames){
if (!currentOptions.toString().contains(i)){
newSecurityLevelNames.add(i)
}
}

def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def issueInputParameters = issueService.newIssueInputParameters()

for (i in newSecurityLevelNames){
def newSeqId = currentOptions*.sequence.max() - 1
def option = optionsManager.createOption(fieldConfig, null, newSeqId, i.toString())

}
0 votes
Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 2, 2017

You'll need to write a new field type to do that if you want to directly use the security levels.  Another option might be to create a standard select list and then script something that synchronises it with the security level list.

Out of curiosity, why do you need this?  I can think of only one use for it, and I'd probably take a different approach for that myself, but I'm keen to hear of other use-cases!

Carlos David August 2, 2017

Hi Nick, thanks for the very swift reply!

 Here's a long-winded attempt at an explanation!

On our other system the security level is deliberately hidden, set automatically on issue creation according to the user's group membership (done via script runner). A custom field ('Group') is then autopopulated with the security level. The custom field naming has much more meaning to our users than 'Security Level'.

I would like to mimic this convention in the new Jira instance, whereby the user is able to select a Group value from a custom select list (choices being the security levels available), and then the security level is automatically set to this value following creation.

Is this the most up-to-date / suitable guide for custom field creation?

https://developer.atlassian.com/jiradev/jira-platform/guides/fields/tutorial-creating-a-custom-field-type

 

Thanks again

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 2, 2017

Hmm.  I'm not sure I understand that.  Could you not set the security level automatically on create, and then place the security level on edit screens for them to edit later?

That would reduce the problem to "we don't like the name 'security level'" which is completely understandable.  But you could put explanatory test with it, or, with a little "development", create a "translation" for your system that uses a different phrase (I say "development", but it's more "copy existing and do a search on some plain text")

Carlos David August 7, 2017

It's important that the security level is *chosen* on creation I'm afraid. I've looked into a translation add-on* for Jira but wasn't able to work out how to use it with fields on the create issue form e.g. security level, issue.

*https://marketplace.atlassian.com/plugins/com.atlassian.translations.jira.inproduct/server/overview

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 7, 2017

Hang on, that's not what you said earlier - "set automatically on issue creation according to the user's group membership".

In the case where you want them to choose, you don't need the script, just stick it on the screen and make it mandatory.  Remember that JIRA will only let the user see and select a level that the user is in, so they can't get it too wrong.

Carlos David August 7, 2017

Duh sorry, what I meant to say is the following:

The workaround at the moment is that the user has to choose the security level on the create screen (with a field description containing the user friendly name). The Group field is then autopopulated with the security level on the view screen.

 

I'm currently trying out Adam's Behaviour suggestion below.

Suggest an answer

Log in or Sign up to answer