Decorating the user profile allows a plugin writer to add information to a public user profile page in Bitbucket Data Center, to provide valuable information to the user which may not be available in a default Bitbucket Data Center installation.
Some examples of what you might build into Bitbucket Data Center's user profile page could include:
This tutorial will take you through the steps to enhance your plugin to render an additional tab in the user profile page.
After completing this tutorial you will have learned to do the following:
Ensure you have installed the Atlassian SDK on your system as described in this tutorial.
Once installed, create a Bitbucket Data Center plugin project by running atlas-create-bitbucket-plugin
and supplying the
following values when prompted:
groupId | artifactId | version | package |
---|---|---|---|
com.mycompany.bitbucket | bitbucket-profile-plugin | 1.0.0-SNAPSHOT | com.mycompany.bitbucket.plugin.profile |
To create a plugin which decorates the User profile with Soy, we need to add a set of dependencies to our plugin.
We can do this using the atlas-create-bitbucket-plugin-module
which is bundled with the Atlassian SDK.
We need to import the SoyTemplateRenderer
and the UserService
to render Soy templates and retrieve the ApplicationUser
respectively.
From inside the bitbucket-profile-plugin
folder that we just created, run atlas-create-bitbucket-plugin-module
and choose the option for Component Import
, using the following interfaces:
com.atlassian.soy.renderer.SoyTemplateRenderer
com.atlassian.bitbucket.user.UserService
Our Atlassian plugin can now import these interfaces from Bitbucket Data Center, however we still need to add a dependency to
import the SoyTemplateRenderer
in the pom.xml
file.
Open pom.xml
, locate the <dependencies>
element and add the following lines:
1 2<dependency> <groupId>com.atlassian.soy</groupId> <artifactId>soy-template-renderer-api</artifactId> <scope>provided</scope> </dependency>
In order to implement a new profile tab, you will first need to create a Java class that implements the HttpServlet
interface. Let's call it ProfileServlet
.
Execute atlas-create-bitbucket-plugin-module
and choose the option for Servlet
, name it ProfileServlet
and choose
the default package name (or change it, if you want).
When prompted to show advanced setup, choose yes. You can use the default options for all if you want - however change
the URL Pattern to be /profile/users/*
. This is the url that the servlet will respond to - we want to namespace
this servlet to listen to the users
component with any proceeding path components. We will use this to extract the
user from the URL.
Note: if you don't choose advanced setup, you can change the url-pattern for your servlet in atlassian-plugin.xml
.
Open ProfileServlet.java
and locate the doGet()
method. This is executed when the servlet url pattern is matched,
namely /plugins/servlet/profile/users/*
. Let's delete the default implementation, and replace it with the following code:
1 2// Get userSlug from path String pathInfo = req.getPathInfo(); String userSlug = pathInfo.substring(1); // Strip leading slash ApplicationUser user = userService.getUserBySlug(userSlug); if (user == null) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // todo: render result
User Slugs
The user slug is a URL safe version of the user's username. It should always be used in preference to the username value.
We send a 404 not found response if either we can't understand the URL, or the user is not found.
In this implementation, we are using the UserService
component to retrieve the user. We're also going to use the
SoyTemplateRenderer
that we imported, so let's go ahead and inject both into the constructor of this Servlet, as follows:
1 2private final SoyTemplateRenderer soyTemplateRenderer; private final UserService userService; public ProfileServlet(SoyTemplateRenderer soyTemplateRenderer, UserService userService) { this.soyTemplateRenderer = soyTemplateRenderer; this.userService = userService; }
In order to render a soy template from our servlet, we need to create it. Navigate to the directory called
src/main/resources
, create a directory called templates
and create profile.soy
inside of it.
1 2{namespace plugin.profile} /** * @param user ApplicationUser object which is in the context provided by ProfileServlet */ {template .profileTab} <html> <head> <meta name="decorator" content="bitbucket.users.profile"> <meta name="userSlug" content="{$user.slug}"> <meta name="activeTab" content="profile-plugin-tab"> <title>{$user.displayName} / Profile Tab</title> </head> <body> <h3>Hello, {$user.displayName}</h3> <p>Welcome to my plugin tab in the profile page.</p> </body> </html> {/template}
The <meta>
tags are important - they instruct Bitbucket Data Center which decorator to use, and provide important
information on how to build the page. Let's break them down:
Meta tag | Description |
---|---|
decorator | Use the `bitbucket.users.profile` decorator which provides the scaffolding around the user profile page |
userSlug | The profile user which this page is decorating. This should be passed to your template from your `Servlet` which extracts the user from the URL |
activeTab | Informs the decorator which navigation tab is active on the profile page. We retrieve this value from the web item which is defined below |
In atlassian-plugin.xml
, we need to define the location for our navigation item.
1 2<web-item key="profile-plugin-tab" name="Profile navigation tab" section="bitbucket.user.profile.secondary.tabs" weight="20"> <label key="profile.plugin.tab">My Plugin</label> <link>/plugins/servlet/profile/users/${profileUser.name}</link> <tooltip key="profile.plugin.tab.description">Hooray, we have a tab!</tooltip> </web-item>
Hints:
<meta>
tag activeTab
which we put into our soy template above needs to match the key
value of
our web item.$profileUser
variable is available on the context for this web item location - learn more about web fragments.We need to add our resources to atlassian-plugin.xml
.
1 2<client-resource key="profile-soy" name="Profile Tab Soy Templates"> <directory location="/templates/" /> </client-resource>
This will add a resource which finds all files in the /templates
directory.
Let's head back to ProfileServlet
and wire up the template rendering.
Create a method called render()
. It's going to have three arguments: the HttpServletResponse
to send data down the
wire with, the templateName
of the soy template to render, and finally the arguments to the template in the form of a Map.
1 2private void render(HttpServletResponse resp, String templateName, Map<String, Object> data) throws IOException, ServletException { resp.setContentType("text/html;charset=UTF-8"); try { soyTemplateRenderer.render(resp.getWriter(), "com.mycompany.bitbucket.bitbucket-profile-plugin:profile-soy", templateName, data); } catch (SoyException e) { Throwable cause = e.getCause(); if (cause instanceof IOException) { throw (IOException) cause; } throw new ServletException(e); } }
The second argument to soyTemplateRenderer.render()
is the fully qualified resource name that we just created. It is
made up of group.artifact:resource-name
.
Finally, let's hook up the doGet()
method to render()
, by adding the following line to the bottom:
1 2render(resp, "plugin.profile.profileTab", ImmutableMap.<String, Object>of("user", user));
That is, render the plugin.profile.profileTab
template (as defined in profile.soy
with the user as the only argument)
From the command line run atlas-run. Then you should connect to http://localhost:7990/bitbucket
, logging in as admin/admin
and visit the profile page. You should see a tab provided by your new plugin!
Congratulations!
You can view the source of this plugin on Bitbucket.
Rate this page: