It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

How to get inactive users of JIRA with jelly or groovy script?

Hi All,

is it possible to get the list of inactive users of JIRA by jelly or groovy?

Note, I do not have access to DB so SQL is not possible.

Thanks in advance,

Rumi

3 answers

Yes.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.util.UserManager

UserManager userManager = ComponentAccessor.getUserManager()
userManager.getUsers().findAll{user -> !user.isActive()}.each { user ->
   //...
}

 

 

Hello Henning,

 

Can we get list of inactive users for specific time, like I need list of users who are inactive from last 30 days?

 

Regards,

 

 

 

Hi,

if you define inactive as "not logged in" you can use something like this.

import com.atlassian.jira.component.ComponentAccessor
def crowdService = ComponentAccessor.crowdService
def ofBizUserDao = ComponentAccessor.getComponent(OfBizUserDao)
def userUtil = ComponentAccessor.userUtil
def dateLimit = (new Date()) - 30
userUtil.getUsers().findAll { it.isActive() }.each {
	def user = crowdService.getUserWithAttributes(it.getName())
	def lastLoginMillis = user.getValue('login.lastLoginMillis')
	if (!lastLoginMillis?.isNumber()) {
		def tu = ofBizUserDao.findByName(user.directoryId, user.name)
		lastLoginMillis = tu.getCreatedDate()?.time
	}
	if (lastLoginMillis) {
		def d = new Date(Long.parseLong(lastLoginMillis))
		if (d.before(dateLimit)) {
			// not logged in for 30 days...
		}
	}
}

If the user never was logged in, this uses the created date for calculating the time of "inactivity".

Henning

Groovy error.JPG

Ah, I missed an import while copying..

import com.atlassian.jira.crowd.embedded.ofbiz.OfBizUserDao

And you have to do something at the position of the comment (// blue), like 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.crowd.embedded.ofbiz.OfBizUserDao


def crowdService = ComponentAccessor.crowdService
def ofBizUserDao = ComponentAccessor.getComponent(OfBizUserDao)
def userUtil = ComponentAccessor.userUtil
def dateLimit = (new Date()) - 30
def result = ""


userUtil.getUsers().findAll { it.isActive() }.each {
    def user = crowdService.getUserWithAttributes(it.getName())
    String lastLoginMillis = user.getValue('login.lastLoginMillis')
    if (!lastLoginMillis?.isNumber()) {
        def tu = ofBizUserDao.findByName(user.directoryId, user.name)
        lastLoginMillis = tu.getCreatedDate()?.time
    }
    if (lastLoginMillis) {
        def d = new Date(Long.parseLong(lastLoginMillis))
        if (d.before(dateLimit)) {
            // not logged in for 30 days...
			result += "${user.displayName} (${user.name})<br>"
        }
    }
}
result

to print a list of "inactive" users.

Please note the change to String lastLoginMillis, otherwise you'll get a runtime error.

Henning

Like Tushar.Kamble likes this

Thanks, it works perfectly well..

 

Thanks,

Tushar

I can't seem to comment on this, it says I'm a spammer :(

 

There it goes, now for my actual comment:

Does this need to be revised?  I'm getting 

Cannot invoke method findByName() on null object.

 Thanks!

 
Like Josh Simnitt likes this

There were some changes in JIRA 7. Here's my current script to deactivate inactive users:

import com.atlassian.crowd.embedded.api.UserWithAttributes
import com.atlassian.crowd.embedded.spi.UserDao
import com.atlassian.jira.application.ApplicationAuthorizationService
import com.atlassian.jira.application.ApplicationKeys
import com.atlassian.jira.bc.user.ApplicationUserBuilderImpl
import com.atlassian.jira.bc.user.UserService
import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.component.ComponentAccessor

def test = true // to really deactivate users, change to false
int numOfDays = 182 // Number of days the user was not logged in
def blockedUsers = // User who should not be deactivated
[
'administrator'
]
def maximumNumberOfUsers = 10000 // search is restricted to find at max this number of users

def userSearchService = ComponentAccessor.getComponent(UserSearchService)
def crowdService = ComponentAccessor.crowdService
def userService = ComponentAccessor.getComponent(UserService.class)
def userDao = ComponentAccessor.getComponent(UserDao)
def applicationAuthorizationService = ComponentAccessor.getComponent(ApplicationAuthorizationService)
def updateUser
def updateUserValidationResult

Date dateLimit = (new Date()) - numOfDays
String result = ""

def userSearchParamsBuilder = new UserSearchParams.Builder()
userSearchParamsBuilder
.allowEmptyQuery(true)
.ignorePermissionCheck(true)
.maxResults(maximumNumberOfUsers)

def allActiveUsers = userSearchService.findUsers("", userSearchParamsBuilder.build())
result += "All active Users: ${allActiveUsers.size()}<br>"
allActiveUsers.findAll {
!blockedUsers.contains(it.name) &&
(
applicationAuthorizationService.canUseApplication(it, ApplicationKeys.SOFTWARE) ||
applicationAuthorizationService.canUseApplication(it, ApplicationKeys.SERVICE_DESK)
)
}.each { appUser ->
UserWithAttributes user = crowdService.getUserWithAttributes(appUser.getName())
String lastLoginMillis = user.getValue('login.lastLoginMillis')
def start_text = "Last Login was"
if (!lastLoginMillis?.isNumber()) {
if (user.directoryId && user.name) {
def tu = userDao.findByName(user.directoryId, user.name)
lastLoginMillis = tu?.getCreatedDate()?.time
start_text = "Not logged in, created on"
} else {
start_text = "SOMETHING WRONG: $user.directoryId && $user.name"
}
}
if (lastLoginMillis) {
Date d = new Date(Long.parseLong(lastLoginMillis))
if (d.before(dateLimit)) {
updateUser = (new ApplicationUserBuilderImpl(appUser)).active(false).build()
updateUserValidationResult = userService.validateUpdateUser(updateUser)
if (updateUserValidationResult.isValid()) {
if (!test) {
userService.updateUser(updateUserValidationResult)
}
result += "Deactivated ${updateUser.name} - $start_text ${d.format("dd.MM.yyyy hh:mm")}"
} else {
result += "Update of ${updateUser.displayName} (${updateUser.name}) failed: ${updateUserValidationResult.getErrorCollection().getErrors().entrySet().join(',')}"
}
}
}
}
result

Henning

Like Josh Simnitt likes this

Hi Henning

 

Regarding your script for JIRA 7. What would be the script if I nly need to display user who did not login in the last 60 days without deactivationg them.

 

Thanks for your help,

Elvir

Hi Elvir,

just exchange the inner part of if (d.before(dateLimit)):

if (d.before(dateLimit)) {
result += "Inactive user: ${appUser.name} - $start_text ${d.format("dd.MM.yyyy hh:mm")}<br>"
}

Henning

@Henning_Tietgens ,

 

Can we use this groovy script with cloud script runner to get the inactive users and projects?

Hi Henning, is it possible to deactivated user by using name for any position like team lead, administrator. Thanks for your time.

Hi Asif, I don't understand your question. What do you mean with "position"? The script could deactivate every user, as long as this user is not component or project lead in any project.

Hi Henning,

I have written a groovy script to deactivate users. The issue I am running into is that the script will fail if the user is a component lead or project lead.  What I want to do is check if the user is a component lead and remove them if they are. So far I have been struggling to do so. (My current version of Jira 8.1.1)


Any help would be much appreciated.

Ah, ok, understand. Try to integrate this into your script:

import com.atlassian.jira.bc.project.component.MutableProjectComponent
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.UpdateProjectParameters
import com.atlassian.jira.user.ApplicationUser

def userUtil = ComponentAccessor.userUtil
def projectManager = ComponentAccessor.projectManager
def projectComponentManager = ComponentAccessor.projectComponentManager

ApplicationUser user // the user who should be deactivated
ApplicationUser replacementUser // the user who should be used as project/component lead instead

// Check if user is component lead
def components = userUtil.getComponentsUserLeads(user)
components?.each{ component ->
def mutProjComp = MutableProjectComponent.copy(component)
mutProjComp.setLead(replacementUser?.name)
projectComponentManager.update(mutProjComp)
}

// Check if user is project lead
def projects = userUtil.getProjectsLeadBy(user)
projects?.each{project ->
def updateProjectParameters = UpdateProjectParameters.forProject(project.id).leadUserKey(replacementUser?.key)
projectManager.updateProject(updateProjectParameters)
}

 

Hi Henning

Thanks for your prompt response. I tried to integrate your code in my script but still its not working. Could you please give me the full script. 

Thanks in advance. 

Hi Asif,

I would suggest you post your script and the error you get and I will help you to get it going.

Best, Henning

Hi Henning,

I would like to do remove/deactivate Project Lead, Component Lead from the project who aren't available in project and replace them automatically with current Project Lead, Component Lead. (Jira v8.1.1)

I will be grateful for any help you can provide.

Hi Asif,

how do you define "aren't available in project" and "current Project Lead, Component Lead"?

Best,
Henning

Hi Henning,

Actually what I want to do is check if the user is a component lead/ project lead and who isn't anymore in project/company remove them automatically and replace another project lead/ component lead in this place.  Any help would be much appreciated.PL.jpg

Thanks for your time

Hi Asif,

mmh, ok, so that's the same as in December. You should combine the scripts from comments from Aug 09, 2017 and Dec 17, 2019 • edited. If you get an error after doing this, you can post your combined script here and I'll take a look what's wrong.

Best,
Henning

Hi Henning,

I'm trying to combine with this script but it shows error. Could you please tell what can I do. 

Thanks a lot for your help

import com.atlassian.jira.bc.project.component.MutableProjectComponent
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.UpdateProjectParameters
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.crowd.embedded.impl.ImmutableUser
import com.atlassian.jira.bc.project.component.MutableProjectComponent
import com.atlassian.jira.bc.user.UserService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.DelegatingApplicationUser

def userService = ComponentAccessor.getComponent(UserService.class)
def userName = "..."
def userUtil = ComponentAccessor.userUtil
def projectManager = ComponentAccessor.projectManager
def projectComponentManager = ComponentAccessor.projectComponentManager
def User
ApplicationUser user // the user who should be deactivated
ApplicationUser replacementUser // the user who should be used as project/component lead instead

// Check if user is component lead
def components = userUtil.getComponentsUserLeads(user)
components?.each{ component ->
def mutProjComp = MutableProjectComponent.copy(component)
mutProjComp.setLead(replacementUser?.name)
projectComponentManager.update(mutProjComp)
}

// Check if user is project lead
def projects = userUtil.getProjectsLeadBy(user)
projects?.each{project ->
def updateProjectParameters = UpdateProjectParameters.forProject(project.id).leadUserKey(replacementUser?.key)
projectManager.updateProject(updateProjectParameters)
}
if (!componentsLeadedBy && !projectLeadedBy)
log.info "userName doesn't lead any component or project"
else {
//remove userName from project lead roles
if (projectLeadedBy.size() > 0)
for (project in projectLeadedBy) {
projectManager.updateProject(project, project.name, project.description, "", project.url, project.assigneeType);
}

//remove userName from component lead roles
if (componentsLeadedBy.size() > 0)
for (component in componentsLeadedBy) {
MutableProjectComponent newComponent = MutableProjectComponent.copy(component)
newComponent.setLead("")
projectComponentManager.update(newComponent)
}

}
def listUsers = userManager.getUsers().findAll{user -> user.name.equals(userName)}
if (listUsers.size() > 0)
return "User userName does not exist"
ImmutableUser.Builder builder = ImmutableUser.newUser(listUsers[0]);
builder.active(false);
def updatedUser = new DelegatingApplicationUser(applicationUser.key, builder.toUser())

UserService.UpdateUserValidationResult updateUserValidationResult =
userService.validateUpdateUser(updatedUser)
if (updateUserValidationResult.isValid()) {
userService.updateUser(updateUserValidationResult)
return "User ${applicationUser.name} deactivated";
} else {
return updateUserValidationResult.getErrorCollection()
}

Hi Asif,

you have to get a user first before you try to determine if the user is a component lead etc. This part is missing before the first use auf "user".

Hi,

   I do not have Atlassian crowd integrated , can I still use this script ? or is there anyway to generate the list of inactive users in my jira without crowd  services.

Thanks

Ramji

The script doesn't need an explicit crowd integration, it's meant for a pure Jira installation. The CrowdService class used by the script is part of Jira.

@Henning_Tietgens 

could you please help me , how to add an attachment to the mail?

we are using below script for sending a mail:

import com.atlassian.mail.Email
import com.atlassian.mail.server.SMTPMailServer
import com.atlassian.jira.component.ComponentAccessor

def emailSubject="test mail"
def emailBody="test mail body"
def emailAddress="yampalla.srinivasareddy@gmail.com"
SMTPMailServer mailServer=ComponentAccessor.getMailServerManager().getDefaultSMTPMailServer()

if(mailServer){
Email email=new Email(emailAddress)
email.setSubject(emailSubject)
email.setBody(emailBody)
mailServer.send(email)
}

Try something like this

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.mail.Email
import com.atlassian.mail.MailException
import com.atlassian.mail.MailFactory
import com.atlassian.mail.queue.SingleMailQueueItem

import javax.activation.DataHandler
import javax.mail.BodyPart
import javax.mail.Multipart
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart
import javax.mail.util.ByteArrayDataSource

Multipart mp = new MimeMultipart("mixed")
BodyPart attPart = new MimeBodyPart()
// take care to set correct mime type for the attachment
ByteArrayDataSource attBds = new ByteArrayDataSource(data, 'text/plain; charset=utf-8')
attPart.setDataHandler(new DataHandler(attBds))
attPart.setFileName(attachmentFileName)
mp.addBodyPart(attPart)

def mailServerManager = ComponentAccessor.getMailServerManager()
def mailServer = mailServerManager.getDefaultSMTPMailServer()

if (mailServer && !MailFactory.settings.isSendingDisabled()) {
Email email = new Email(emailTo, emailCC, emailBCC)

email.setMultipart(mp)
email.setFrom(mailServer.getDefaultFrom())
email.setSubject(config.emailSubject)
email.setMimeType(config.emailMimeType)
email.setBody(config.emailBody)
try {
SingleMailQueueItem item = new SingleMailQueueItem(email)
ComponentAccessor.getMailQueue().addItem(item)
}
catch (MailException e) {
log.error("Error sending email", e)
}
} else {
log.warn("No mail server or sending disabled.")
}

@Henning_Tietgens 

Thanks a lot for your help, it is working.

Here is a Jira cloud addon developed by my company that allows you to search, filter and bulk delete users:
https://marketplace.atlassian.com/apps/1221764/user-management-by-toros

In addition, it allows you to search for inactive users (users who haven't login in a while) and perform some bulk operation.

Suggest an answer

Log in or Sign up to answer
TAGS

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you