Nowadays personal data protection is the cornerstone of many new features, released in software products. Be it GDPR, ISO 27701 or some other standard, companies are obliged to follow the rules if they do not want to face severe consequences.
Atlassian has put a lot of effort in their Cloud products to assure they comply to data protection regulations, from the feature to anonymize users to restrictions in the API when fetching user details. As necessary and important that is, it also means that routine operations, like fetching a user's e-mail to enable integration with another product in your company through REST calls can become quite hard to achieve.
The Problem:
Lately we had to come up with a way to fetch Jira Cloud users logged time and present it in JSON format to be imported by Microsoft Dynamics 365 and used for billing. After some discussions with the integrators of the Dynamics 365 solution, we agreed that the user's e-mail will be used as identification of the person that logged the time, as all other options would not guarantee uniqueness. Fast forward couple of weeks, our Jira app developers created a prototype of a standalone Java app, which used Jira Cloud REST calls to fetch all users logged time for a specified month and prepare a JSON from it. That is when we realized, that the e-mails of the users could not be fetched through REST calls, no matter what we tried. The REST call would return something like:
{ "self": "https://somecompany.atlassian.net/rest/api/3/user?accountId=123456:38935ea6-083c-466d-9056-a1e742423fc", "accountId": "123456:38935ea6-083c-466d-9056-a1e742423fc", "accountType": "atlassian", "avatarUrls": { "48x48": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/123456:38935ea6-083c-466d-9056-a1e7424243fc/123b8336-6a15-420c-af71-f9b3196d39c4/48", "24x24": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/123456:38935ea6-083c-466d-9056-a1e7424243fc/123b8336-6a15-420c-af71-f9b3196d39c4/24", "16x16": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/123456:38935ea6-083c-466d-9056-a1e7424243fc/123b8336-6a15-420c-af71-f9b3196d39c4/16", "32x32": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/123456:38935ea6-083c-466d-9056-a1e7424243fc/123b8336-6a15-420c-af71-f9b3196d39c4/32" }, "displayName": "John Doe",
"active": true, "timeZone": "Europe/Paris", "locale": "en_US" }
So we have an accountId, that uniquely identifies the user in the Cloud but does not help us in the integration, we have displayName, that cannot be used as it is not unique. We also have info about the accountType (can be "atlassian", "customer" or "app") and if the user is "active".
At this point our integration plan seemed a bit doomed, because not having e-mail would mean we cannot really identify the users on the Dynamics 365 side. As customers do not like to get as an answer "It is not possible", we had to come up with something...
The Workaround:
As Atlassian are famous by the fact, that they have hundreds (if not thousands) of feature requests for their products, for which they provide a workaround and never really fix, we also decided to go for a "quick and dirty" one to fetch user's data when you need something like e-mail. The idea is to create a Jira issue for each user and store there their e-mail as text, so that it can be read through the API and added to the JSON. The aim was to make these issues creation automated, so that the customer would not need to do anything in the process. Jira Automation provided all the needed tools to do that, so here how we did it.
First we created a Jira project called "UserEmailMatch", which would store the issues (team-managed one), so that these issues did not interfere with the rest of the customer data in the instance. Then the following automation rule was created:
Simply put the rule would automatically run at the start of every month, delete all the issues in the "UserEmailMatch" project and then re-create them for all active users. The search for active users is done again by using REST call like:
https://somecompany.atlassian.net/rest/api/3/users/search?query=*&startAt=0&maxResults=500
Wait, what? Didn't REST calls fail to return e-mail data for the users??? If these questions just popped up in your mind, congratulations for paying attention so far!
Yes, the REST call will not give us the needed data yet, but we do not need the e-mail for now, we only need the users. Now it is time to create an issue for each user, but first we filter the ones that are not active and are not of the correct type, because we can have a Jira instance, that has 200 users of Jira Software, 10 Jira Service Management agents and 5000 portal customers. We only need to get the data of those 210 users that can actually log time, right? So here we go:
In the first block above, we iterate over the returned users list and assign the {{NextUser}} variable with the {{webResponse.body}}, here is how it looks:
Then we compare the accountType and active values from the response with our target users - "atlassian" accounts that are active. This will filter all account types like "customer" (e.g. portal users) or "app" (e.g. app service accounts).
{Offtopic} If you are thinking now "Oh, but that is not completely right, you can have accountType "atlassian" users, that still have "Portal only" access and in this way you will include them as well in the created issues - you are completely right and probably you should try to get the new "Atlassian Cloud Organization Admin Certification" as you are really advanced admin. I will not go here into discussing the differences between Internal and External Customers in Jira Cloud, you can go and read the articles about that and try to figure it out yourself, if you dare ;).{/Offtopic}
Now that we filtered the users, it is time to create an issue for each of them, and this is how it looks:
What we do here is to create an issue in the new project, set the Summary to be the "accountId" of the user and set a custom field of type User (we create it first and get the customfield_10045 id to use here), using the ID of the user. In this way we have the Jira User set in the new issue, and all that is left now is to create one more automation rule, that will get us the e-mail of the user:
Here you can see how we fetch the user's e-mail from the User field in the issue, using smart values, and store it in the Description field. As a result we will have for each user an issue, that has the user accountID in the Summary and the user e-mail in the Description. Just make sure you restrict this rule to work only on the issues in the "UserEmailMatch" project!!!
And that is it. Now all that was left was to change our integration app to go through these issues and find the e-mail for each user by their accoundID and put it in the resulting JSON. Long live Jira Automation and quick and dirty workarounds!
Boyan Angelov (Nemetschek Bulgaria)
Atlassian Solutions Leader
NEMETSCHEK OOD
Bulgaria
45 accepted answers
7 comments