This tutorial will take you through the steps to enhance your plugin to render an additional tab in the user's account 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 account 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 and retrieve the ApplicationUser respectively.
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.UserManager
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 account tab, you will first need to create a Java class that implements the HttpServlet
interface. Let's call it AccountServlet
.
Execute atlas-create-bitbucket-plugin-module
and choose the option for Servlet
, name it AccountServlet
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 /account/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 AccountServlet.java
and locate the doGet()
method. This is executed when the servlet url pattern is matched,
namely /plugins/servlet/account/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 AccountServlet(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 account.soy
inside of it.
1 2{namespace plugin.account} /** * @param user ApplicationUser object which is in the context provided by AccountServlet */ {template .accountTab} <html> <head> <meta name="decorator" content="bitbucket.users.account"> <meta name="userSlug" content="{$user.slug}"> <meta name="activeTab" content="account-plugin-tab"> <title>{$user.displayName} / Account Tab</title> </head> <body> <h3>Hello, {$user.displayName}</h3> <p>Welcome to my plugin tab in the account 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.account` decorator which provides the scaffolding around the user account page |
userSlug | The 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 account 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="account-plugin-tab" name="Account navigation tab" section="bitbucket.user.account.nav" weight="20"> <label key="account.plugin.tab">My Plugin</label> <link>/plugins/servlet/account/users/${accountUser.name}</link> <tooltip key="account.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.$accountUser
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="account-soy" name="Account 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 AccountServlet
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:account-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.account.accountTab", ImmutableMap.<String, Object>of("user", user));
That is, render the plugin.account.accountTab
template (as defined in account.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 user account 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: