# Decorating the user account

## Goals

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 learnt to do the following:

 * Create a Servlet that extracts a user's profile
 * Add a new tab to the user profile page
 * Decorate the user account using Soy to render its content

## Steps

### Generate a Bitbucket Server plugin using the Atlassian SDK

Ensure you have installed the Atlassian SDK on your system as described in [this tutorial](https://developer.atlassian.com/display/DOCS/Set+up+the+Atlassian+Plugin+SDK+and+Build+a+Project).
Once installed, create a Bitbucket Server plugin project by running `atlas-create-stash-plugin` and supplying the 
following values when prompted:

<table>
    <tr><th>groupId</th><th>artifactId</th><th>version</th><th>package</th></tr>
    <tr><td>com.mycompany.bitbucket</td><td>bitbucket-profile-plugin</td><td>1.0.0-SNAPSHOT</td><td>com.mycompany.bitbucket.plugin.profile</td></tr>
</table>

### Add dependencies

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-stash-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-stash-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 Server, 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:

```xml
<dependency>
    <groupId>com.atlassian.soy</groupId>
    <artifactId>soy-template-renderer-api</artifactId>
    <version>3.3.5</version>
    <scope>provided</scope>
</dependency>
```

### Create a servlet

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-stash-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`.

#### Locate the ApplicationUser

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:

```java
// 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
```

<div class="aui-message info shadowed">
    <p class="title">User Slugs</p>
    <span class="aui-icon icon-info"></span>
    <p>
        The user slug is a URL safe version of the user's username. It should <i>always</i> be used in preference to the 
        username value.
    </p>
</div>

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:

```java
private final SoyTemplateRenderer soyTemplateRenderer;
private final UserService userService;

public AccountServlet(SoyTemplateRenderer soyTemplateRenderer, UserService userService) {
    this.soyTemplateRenderer = soyTemplateRenderer;
    this.userService = userService;
}
```

### Create a Soy Template

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.

```soy
{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 Server which decorator to use, and provide important information 
on how to build the page. Let's break them down:

<table>
<tr><th>Meta tag</th><th>Description</th></tr>
<tr><td>decorator</td><td>Use the `bitbucket.users.account` decorator which provides the scaffolding around the user account page</td></tr>
<tr><td>userSlug</td><td>The user which this page is decorating. This should be passed to your template from your `Servlet` which extracts the user from the URL</td></tr>
<tr><td>activeTab</td><td>Informs the decorator which navigation tab is active on the account page. We retrieve this value from the web item which is defined below</td></tr>
</table>

#### Add an account tab item

In `atlassian-plugin.xml`, we need to define the location for our navigation item.

```xml
    <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:

* The value of the `<meta>` tag `activeTab` which we put into our soy template above needs to match the `key` value of 
our web item.
* The link which is used needs to match the url-pattern of the servlet which we defined at the beginning of this tutorial. 
The `$accountUser` variable is available on the context for this web item location - learn more about [web fragments](../reference/web-fragments.html).

### Render the Template

#### Add a resource

We need to add our resources to `atlassian-plugin.xml`.

```xml
<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.

#### Render the template

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.

```java
private 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:

```java
render(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)

### Try it out!

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!

## Resources

You can view the source of this plugin on [Bitbucket](https://bitbucket.org/atlassian/bitbucket-example-plugin).
