In a bid to contribute more to the Atlassian Community, I took a look at the most recent requests and questions on the Forums. One that caught my eye was a request for a Confluence Macro that would:
“…display on the restricted page exactly who has access (including a breakout of all group members, not just the group name) to create transparency and build confidence in the selected user group that they are posting in the appropriately restricted area.”
I’d never created a Confluence Macro before, and this seemed like a challenge I could meet.
Please note that this isn’t a how-to on creating Macros, but really just an accounting of my experience learning the tool.
The first thing I did was check to see what Atlassian has to say on the subject. Confluence Macros are written in Apache Velocity, which is quite different from the Groovy that I’m used to working with.
All of the functional lines in Velocity start with a #, which makes a Velocity script look like one big page of commented-out code. The truth is that Velocity is very old and pretty clunky. The last news update to the project was over two years ago. All but one of the links to development tools in the “Dev Tools” section of the Velocity website are dead links. Is it a dead platform? Maybe! In the meantime, it’s what we have to work with.
So I took a look at the documentation. The actual process of writing a Macro seemed pretty straightforward. Mostly because there was literally no tooling to work with, so writing it just a matter of firing up Notepad and iteratively working out the process. Trial-and-error was the only path forward that I could take.
The most useful resource I found was this document on available Confluence objects in Velocity. The actual syntax was pretty basic: functional lines start with #, and variables are preceded by a dollar $ign.
A basic example of a Macro would be something like this:
## @noparams #set($permissions = $content.permissions) #foreach($permission in $permissions) $permission<br> #end
It feels like a mix between writing in BASIC and PowerShell. As you can see above, we set a variable to be the permissions on the page, and then looped through the page to write out each permission. $content is the object that stores the attributes of the current page. If I wanted to get the ID of the current page, I’d reference $content.id and so on.
$content is an implementation of the ContentEntityObject class in Confluence. The documentation for this class is here. Were I to look into making further use of this class, I’d start by looking at the methods outlined in the documentation.
The Actual Macro
Okay so here’s the actual Macro that I came up with. It prints the names of individual users with access to the page, as well as the groups with access to the page and the members of those groups.
## @noparams #set($permissions = $content.permissions) #set($userNamesArray = ) #set($groupNamesArray = ) #foreach ($permission in $permissions) #if($permission.userSubject && $permission.userSubject.name && !$userNamesArray.contains($permission.userSubject.name)) #set($unused = $userNamesArray.add($permission.userSubject.name)) #end #if(!$permission.userSubject.name) #if(!$groupNamesArray.contains($permission.groupName)) #set($unused = $groupNamesArray.add($permission.groupName)) #end #end #end <h3>Users With Page Access</h3><br> #foreach ($userName in $userNamesArray) $userName<br> #end #foreach ($groupName in $groupNamesArray) <h3>Groups With Page Access:<br> <b> $groupName</b></h3><br> #set($group = $userAccessor.getGroup($groupName)) #set($members = $userAccessor.getMemberNames($group)) Group Members:<br> #foreach($member in $members) $member <br> #end #end
Most of this is pretty straightforward. You may be wondering why we added values to the two arrays and set them to be the value of $unused at the same time. This is because we need to pipe that value into an unused string. If we don’t, Velocity prints the results of the boolean check to the page. That is, without this extra step, it prints “true true true true” to the macro body on the Confluence page.