Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

How to find last login date of users in Confluence

Kjell Lauren September 19, 2012

Hi,

Is there a way I can tell the last login date of all users in one screen? I know I can see it by clicking on the user name. However I need to look at over 1500 users and see who has not logged in for a while to be able to deactive these users. We are using Confluence 3.5.17

I have tried some of the earlier posted user macros but the result is either empyt field for last login daye, NEVER or the userlist is showing only ~20 users of the 1500.

Would also need to get the date when the account was created and a tab showing if the user is active or deactivated.

Thanks, Kjell

7 answers

10 votes
Bruce Schlueter February 6, 2013

I created a user macro with the help of some answers here https://answers.atlassian.com/questions/33385/macro-that-produces-a-list-of-users-last-login-date that creates a table with the Name, Create Date, Last Login and number of days since last login (roughly because of the time being in milliseconds).

## @param group:title=Gruppe|type=string|required=true|desc=Group to show

#set($containerManagerClass = $content.class.forName('com.atlassian.spring.container.ContainerManager'))
#set($getInstanceMethod = $containerManagerClass.getDeclaredMethod('getInstance',null))
#set($containerManager = $getInstanceMethod.invoke(null,null))
#set($containerContext = $containerManager.containerContext)

#set($loginManager = $containerContext.getComponent('loginManager'))
#set($crowdService = $containerContext.getComponent('crowdService'))
#set($t1=$content.currentDate.time)

#set($group = $userAccessor.getGroup($paramgroup))

#if($group)
    #set($usernames = $userAccessor.getMemberNames($group))



<table class="confluenceTable" width="660px">
    <tr>
        <th class="confluenceTh " width="220px">Name</th>
        <th class="confluenceTh"  width="110px">Create date</th>
        <th class="confluenceTh" width="110px">Last Login</th>
        <th class="confluenceTh" width="110px" style="text-align:center;">Activated</th>
        <th class="confluenceTh" width="110px" style="text-align:center;">Days</th>
    </tr>
    #foreach($username in $usernames)
        #set($t3="9999")
        #set($user = $userAccessor.getUser($username))
        #set($crowdUser = $crowdService.getUser($user.name))
        
        <tr>
           <td class="confluenceTd">#usernameLink($user.name)</td>
           <td class="confluenceTd" style="text-align:center;">$action.dateFormatter.formatGivenString('dd.MM.yyyy', $crowdUser.createdDate)</td>
           <td class="confluenceTd" style="text-align:center;">$action.dateFormatter.formatGivenString('dd.MM.yyyy',$loginManager.getLoginInfo($user).lastSuccessfulLoginDate)</td>
          <td class="confluenceTd" style="text-align:center;">
           #if($userAccessor.isDeactivated($user))
                    <ac:macro ac:name="status">
                    <ac:parameter ac:name="colour">Red</ac:parameter>
                   <ac:parameter ac:name="title">Nein</ac:parameter>
                   </ac:macro>
           #else
                   <ac:macro ac:name="status">
                   <ac:parameter ac:name="colour">Green</ac:parameter>
                   <ac:parameter ac:name="title">Ja</ac:parameter>
                   </ac:macro>
                  #set($totalactiveusers = $totalactiveusers + 1)
            #end
                

            </td>
         
          #if($loginManager.getLoginInfo($user).lastSuccessfulLoginDate)
                #set($t3= $content.currentDate.time -  $loginManager.getLoginInfo($user).lastSuccessfulLoginDate.time)
                #set($t3=$t3/1000/24/60/60)
           #end
           <td class="confluenceTd" style="text-align:center;">
           #if($t3 < 7) 
                 <ac:macro ac:name="status">
                 <ac:parameter ac:name="colour">Green</ac:parameter>
                 <ac:parameter ac:name="title">$t3</ac:parameter>
                 </ac:macro>
           #elseif($t3 < 14) 
                 <ac:macro ac:name="status">
                 <ac:parameter ac:name="colour">Yellow</ac:parameter>
                 <ac:parameter ac:name="title">$t3</ac:parameter>
                 </ac:macro>
           #elseif($t3 < 9999) 
                 <ac:macro ac:name="status">
                 <ac:parameter ac:name="colour">Red</ac:parameter>
                 <ac:parameter ac:name="title">$t3</ac:parameter>
                 </ac:macro>
           #else 
                 <ac:macro ac:name="status">
                 <ac:parameter ac:name="colour">Magenta</ac:parameter>
                 <ac:parameter ac:name="title">$t3</ac:parameter>
                 </ac:macro>

           #end 
           
           </td>
        </tr>
    #end
</table>
#end

 

You can give the group-name as parameter or you use confluence-users to show all users. Hope this helps.

 

Bruce

 

Jorge
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.
January 9, 2014

what if one wants to know the user creation date. I know these:

$user.fullName
$user.email
$user.name

But, is there a place where I can see the full list of parameters?

Steve Goldberg
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.
January 9, 2014
Kirstin Seidel-Gebert
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.
July 24, 2018

Thanks, Bruce. This macro made my day. :)

Thu Nguyen September 23, 2018

Many thanks, Bruce. The macro is great, it helps us to get information from different angles.

4 votes
Alejandro Conde Carrillo
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.
September 19, 2012

You can get them from the databse with this query:

select cu.user_name, cua.attribute_value from cwd_user_attribute cua left join cwd_user cu on cua.user_id=cu.id where attribute_name='lastAuthenticated';

The time is in unix format. Yoy may want to write a script to change that to a more human readable format.

Larry Archer March 22, 2013

This appears to only work for users in Confluence's local user directory, but not any users who authenticate through an external LDAP server (delegated LDAP auth).

Does Confluence no longer save the last login time for these users? (It used to work in 3.4.x -- the login date was stored in the OS_PROPERTYENTRY table under entity key "confluence.user.last.login.date")

Matt Janulewicz July 7, 2014

The following works for me on Confluence 5.5 using Postgres. They perhaps changed the structure of the database. There are other examples in the Confluence docs:

SELECT cwd_user.user_name, to_timestamp(CAST(cwd_user_attribute.attribute_value as bigint)/1000)
FROM cwd_user, cwd_user_attribute
WHERE cwd_user_attribute.user_id = cwd_user.id
AND cwd_user_attribute.attribute_name = 'lastAuthenticated'
AND cwd_user.active='T'
ORDER BY to_timestamp;

This keys in on active users, you can take that AND clause out if you want to include inactive users. We use a mix of LDAP and a few local users and everyone seems to be in there.

I run a free SQL embedding plugin (check the store for Pocket Queries) and throw this list into a velocity template that was mostly stolen from Bruce. If you have a lot of users the SQL query runs faster than the full macro.

For good measure, this is a query for Jira 6.2.2 with a Postgres backend:

SELECT cwd_user.user_name, to_timestamp(CAST(cwd_user_attributes.attribute_value as bigint)/1000)
FROM cwd_user, cwd_user_attributes
WHERE cwd_user_attributes.user_id = cwd_user.id
AND cwd_user_attributes.attribute_name = 'lastAuthenticated'
AND cwd_user.active = '1'
ORDER BY to_timestamp;

Royce Wong
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.
February 20, 2015

It's weird, the macro is using $crowdUser.createdDate, but https://developer.atlassian.com/static/javadoc/embedded-crowd-api/latest/reference/com/atlassian/crowd/embedded/api/User.html doesn't contain the createdDate method. Anyone know where is that createdDate method from? I am trying to find the API equivalent. Thanks.

2 votes
Jack D. Pond July 30, 2019

This is a GREAT macro - thank you very much @Bruce Schlueter 

A couple of updates for current Confluence version:

  1. Substituted escaped characters from the original (e.g., &lt;  for '<')
  2. Suggested options when creating:
    1. Visibility - Visible only to system administrators in the Macro Browser
    2. Definition of User Macro - Rendered

## @param group:title=Gruppe|type=string|required=true|desc=Group to show

#set($containerManagerClass = $content.class.forName('com.atlassian.spring.container.ContainerManager'))
#set($getInstanceMethod = $containerManagerClass.getDeclaredMethod('getInstance',null))
#set($containerManager = $getInstanceMethod.invoke(null,null))
#set($containerContext = $containerManager.containerContext)

#set($loginManager = $containerContext.getComponent('loginManager'))
#set($crowdService = $containerContext.getComponent('crowdService'))
#set($t1=$content.currentDate.time)

#set($group = $userAccessor.getGroup($paramgroup))

#if($group)
#set($usernames = $userAccessor.getMemberNames($group))




<table class="confluenceTable" width="660px">
<tr>
<th class="confluenceTh " width="220px">Name</th>
<th class="confluenceTh" width="110px">Create date</th>
<th class="confluenceTh" width="110px">Last Login</th>
<th class="confluenceTh" width="110px" style="text-align:center;">Activated</th>
<th class="confluenceTh" width="110px" style="text-align:center;">Days</th>
</tr>
#foreach($username in $usernames)
#set($t3="9999")
#set($user = $userAccessor.getUser($username))
#set($crowdUser = $crowdService.getUser($user.name))

<tr>
<td class="confluenceTd">#usernameLink($user.name)</td>
<td class="confluenceTd" style="text-align:center;">$action.dateFormatter.formatGivenString('dd.MM.yyyy', $crowdUser.createdDate)</td>
<td class="confluenceTd" style="text-align:center;">$action.dateFormatter.formatGivenString('dd.MM.yyyy',$loginManager.getLoginInfo($user).lastSuccessfulLoginDate)</td>
<td class="confluenceTd" style="text-align:center;">
#if($userAccessor.isDeactivated($user))
<ac:macro ac:name="status">
<ac:parameter ac:name="colour">Red</ac:parameter>
<ac:parameter ac:name="title">Nein</ac:parameter>
</ac:macro>
#else
<ac:macro ac:name="status">
<ac:parameter ac:name="colour">Green</ac:parameter>
<ac:parameter ac:name="title">Ja</ac:parameter>
</ac:macro>
#set($totalactiveusers = $totalactiveusers + 1)
#end

</td>

#if($loginManager.getLoginInfo($user).lastSuccessfulLoginDate)
#set($t3= $content.currentDate.time - $loginManager.getLoginInfo($user).lastSuccessfulLoginDate.time)
#set($t3=$t3/1000/24/60/60)
#end
<td class="confluenceTd" style="text-align:center;">
#if($t3 < 7)
<ac:macro ac:name="status">
<ac:parameter ac:name="colour">Green</ac:parameter>
<ac:parameter ac:name="title">$t3</ac:parameter>
</ac:macro>
#elseif($t3 < 14)
<ac:macro ac:name="status">
<ac:parameter ac:name="colour">Yellow</ac:parameter>
<ac:parameter ac:name="title">$t3</ac:parameter>
</ac:macro>
#elseif($t3 < 9999)
<ac:macro ac:name="status">
<ac:parameter ac:name="colour">Red</ac:parameter>
<ac:parameter ac:name="title">$t3</ac:parameter>
</ac:macro>
#else
<ac:macro ac:name="status">
<ac:parameter ac:name="colour">Magenta</ac:parameter>
<ac:parameter ac:name="title">$t3</ac:parameter>
</ac:macro>

#end

</td>
</tr>
#end
</table>
#end
Fox Chen September 25, 2019

@Jack D_ Pond @Bruce Schlueter , you saved me! Thank you for the sharing!

Anas Ibrahim November 13, 2019

It's Amazing but just a quick request 

can you display the Username also ?? 

Anas Ibrahim November 13, 2019
Jack D. Pond November 13, 2019

I haven't actually tested this, but . . .

After:

<th class="confluenceTh " width="220px">Name</th>

add 

<th class="confluenceTh " width="110px">UserName</th>

 and after

<td class="confluenceTd">#usernameLink($user.name)</td>

add

<td class="confluenceTd">$username</td>

Hope this works! 

Like Anas Ibrahim likes this
Anas Ibrahim November 15, 2019

Oh man you are the Gandalf of the Macro :D  .

Thanks a lot it's Work  

Brian Stults May 23, 2020

The macro doesn't seem to be working for me on Confluence 7.4.0. For everyone, "Create Date" and "Last Login" are blank, and "Days" is 9999.

Edit -- I see now that there's actually no way to fix the macro in Confluence 7.x:

https://confluence.atlassian.com/doc/deprecated-code-paths-removed-in-7-0-967879993.html?_ga=2.220289368.1533145928.1575273676-803821957.1552482208

Like Atlassian Sales likes this
Kirstin Seidel-Gebert
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.
May 24, 2020

Isn't there any replacement for the removed functions in Confluence 7.x?

Fox Chen August 6, 2020

Yes, now I faced the same problem after upgrade....

1 vote
Deleted user February 4, 2020

Hi Bruce

i tried the macro but it only list the users and the last login date comes empty , Could you let me know where i am doing wrong .

BR

Aakanksha 

lotfi.laabidi February 28, 2020

same issue for me as well.. last login fields are empty for all users

kenny.snyder April 24, 2020

Same issue here.  Create date and Last login fields are both empty. 

Krzysztof Zarębski June 11, 2020

same issue :/ 

Fox Chen August 6, 2020

same...:(

1 vote
Nabil Sayegh
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.
February 23, 2016

I know this is an old thread, but I'm pretty sure someone will find it handy to have a SQL that works with recursive (LDAP) groups. It requires a database with Common Table Expressions, e.g. MS SQLServer

-- CTE (Common Table Expression)
WITH recursive_groups ( group_id, name, directory_id)
AS
(
	-- Anchor, i.e. the login groups
	SELECT
		g.id, group_name, directory_id
	FROM
		cwd_group g
		JOIN cwd_directory d ON (g.directory_id = d.id)
	WHERE
		d.active = 'T' -- only enabled directories
		AND g.group_name in ('confluence-users-ldap','confluence-administrators','confluence-administrators-system') -- put your login groups here
	UNION ALL
	-- Recursive sub groups
	SELECT
		g.id, g.group_name, g.directory_id
	FROM
		cwd_membership m
		JOIN recursive_groups to_the_root ON (to_the_root.group_id = m.parent_id)
		JOIN cwd_group g ON (m.child_group_id = g.id)
		JOIN cwd_directory d ON (g.directory_id = d.id)
	WHERE
		d.active = 'T' -- only enabled directories
)
SELECT
	distinct u.id AS [UserId], u.lower_user_name AS [User], u.display_name AS FullName, l.SUCCESSDATE AS [LastLogin], du.directory_name AS DirectoryName
FROM
	recursive_groups g
	JOIN cwd_membership m ON (m.parent_id = g.group_id)
	JOIN cwd_user u ON (u.id = m.child_user_id)
	JOIN cwd_directory du ON (u.directory_id = du.id)
	LEFT JOIN user_mapping map ON (map.username = u.user_name)
	LEFT JOIN logininfo l ON (l.USERNAME = map.user_key)
WHERE
	u.active = 'T' -- only enabled users
ORDER BY
	u.lower_user_name
0 votes
Steve Goldberg
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.
February 10, 2013

Using Bruce's work, I have updated the version that I use and put it on GitHub: https://github.com/stevegoldberg/ConfluenceMacros/blob/master/Last%20Login/lastlogin.css

Poornika Reddy Ekkati February 19, 2023

Hi Steve,

I've tried the updated version of yours and bruce's work, but I'm getting error at "<ac:macro ac:name="show-if"" can you tell why is it coming. It's showing as "Failed to transform the HTML macro template for display. Nested message: RuntimeException occurred while performing an XHTML storage transformation (macro name is required)".

your reply would be a lot useful

0 votes
Beth Schaefermann
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.
September 19, 2012

You might be interested in this improvement request on Atlassian's Confluence project:

https://jira.atlassian.com/browse/CONF-1556

You can both watch and vote on the issue as important to you as well as review the SQL statement provided in the comments as a temporary work-around to your need.

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events