How to update an xhtml-macro's parameters via JavaScript?

I’m developing my first plugin using the Atlassian Plugin SDK, and I’m also new to Java. Please forgive my newbishness.

I am developing a plugin for Confluence that uses the xhtml-macro module and has two parameters: Name and Date:

<xhtml-macro name="validator" class="com.vimeo.community.validator.macro.validator" key='validator-macro'>
    <description key="validator.macro.desc"/>
    <category name="formatting"/>
    <parameters>
        <parameter name="Name" type="string" />
        <parameter name="Date" type="string" />
    </parameters>
</xhtml-macro>

The macro uses these parameters to display the following message in articles:

{Name} validated this article on {Date}.
[Validate now]

When the end-user clicks the [Validate now] button, I want to update the two macro parameters with the current user’s name, and the timestamp on which the button was clicked. I’ve set up an event handler in the JS for that button click, but now I am stumped.

I imagine that maybe there’s a way to build an API endpoint for the macro that would be able to modify the parameters based on values sent with the request. If that’s the best way forward, should I be using the rest module? Or am I barking completely up the wrong tree?

Also, which method(s) can I use to set the values of my macro’s parameters programmatically?

Finally, if anyone knows of any examples of plugins that perform a similar task to mine, and can point me toward the source code, I’d be very grateful.

Thanks in advance!

Hi @zena,

You can create your own API endpoint using the atlas-create-confluence-plugin-module and choose the REST. That’ll automatically create the endpoint for you. And there you can return a JSON object to the requester, I’m assuming you’d be doing this via ajax? If you’re using jquery:

$.get('/rest/my-endpoint/1.0/endpoint', function(response) { // do some DOM manipulation here to modify the name and date });
PS. You can play around with the endpoint by going to your Confluence’s REST browser, and tick off “Show public API only”.

Thanks!

Cheers,
Anne Calantog

1 Like

Thank you so much, @acalantog! Ultimately, I think I’ll end up making a POST request (rather than GET) because I want to update the macro’s parameters internally (not in the DOM).

Just a few more follow up questions:

  1. How can I determine what the url for the endpoint is? (What values should replace my-endpoint and endpoint?

  2. What methods can I use to update the macro’s parameters from within the endpoint’s Java handler?

Thanks again!

Hi, that doesn’t make much of sense, at least to me.

Macro params VALUES are tied to page, macro param NAMES are tied to macro. What do you change values or param names?
Can you elaborate what you want to achieve?

Confluence in documentation can be a bit** so, when you use the command @acalantog wrote you are asked for resource name, package, REST path and version. Leave version as suggested, adjust the rest. The result of this command is two classes tied to the REST api, two classes tied to the test of the REST api and one element in the atlassian-plugin.xml.
The element in the xml looks like

<rest key="dcim-rest" name="DCIM REST API" path="/dcim" version="1.0">
        <description key="dcim-rest.description">DCIMSupport REST api</description>
    </rest>

The path corresponds to my-endpoint and the @Path within the generated classes corresponds to endpoint
I hope it helps

@Panos, thanks for your help. So my rest element looks like this:

<rest name="Validator Rest" i18n-name-key="validator-rest.name" key="validator-rest" path="/validator" version="1.0">
    <description key="validator-rest.description">The Validator Rest Plugin</description>
</rest>

The generated class is pretty much left as the default:

/**
 * A resource of message.
 */
@Path("/message")
public class ValidatorRest {

    @GET
    @AnonymousAllowed
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Response getMessage()
    {
       return Response.ok(new ValidatorRestModel("Hello World")).build();
    }
}

And yet when I make the request, using this JS…

$.get('/rest/validator/1.0/message', function (response) {
    console.log(response);
});

…I get a 404 error. Here’s a screenshot of my network tab:

As for what I am ultimately trying to achieve: I want to update the values of the macro’s parameters. Using the GUI, an end-user could edit an article, then edit the instance of the macro within to update the macro’s parameter values. I want to edit these values programmatically, as the result of a request to my endpoint. For example, I might eventually have something that looks like this:

$.post('/rest/validator/1.0/update_validation', 
    { name: "Zena", date: '2017-10-05T18:08:54.385Z' }, 
    function (response) {
        console.log(response);
    }
);

I’d then have a Java method to handle this POST request, and update the macro’s parameters to the given values. But I’m not sure which built-in Atlassian method(s) to use to update those values.

I hope that’s clearer… and again, thank you so much for your patience and help!

Zena

Try this:

@Path("/")
public class ValidatorRest {

    @GET
    @AnonymousAllowed
    @Path("/message")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Response getMessage()
    {
       return Response.ok(new ValidatorRestModel("Hello World")).build();
    }
}

But I’m not sure which built-in Atlassian method(s) to use to update those values.

None as far as I know.

I want to edit these values programmatically, as the result of a request to my endpoint. For example, I might eventually have something that looks like this

You will not do it like this cause it gets complicated for no reason. Your macro should read variables from database/persistance and javascript/rest should update those values.

Take a look on bandanamanger for quick solution.

@Panos, I made the changes you suggested, but my endpoint is still returning a 404. Here are the relevant files—is there anything else I am missing?

/src/main/resources/atlassian-plugin.xml

<?xml version="1.0" encoding="UTF-8"?>

<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">
  <plugin-info>
    <description>${project.description}</description>
    <version>${project.version}</version>
    <vendor name="${project.organization.name}" url="${project.organization.url}"/>
    <param name="plugin-icon">images/pluginIcon.png</param>
    <param name="plugin-logo">images/pluginLogo.png</param>
  </plugin-info>
  <!-- add our i18n resource -->
  <resource type="i18n" name="i18n" location="validator"/>
  <!-- add our web resources -->
  <web-resource key="validator-resources" name="validator Web Resources">
    <dependency>com.atlassian.auiplugin:ajs</dependency>
    <resource type="download" name="validator.css" location="/css/validator.css"/>
    <resource type="download" name="validator.js" location="/js/validator.js"/>
    <resource type="download" name="images/" location="/images"/>
    <context>validator</context>
  </web-resource>
  <xhtml-macro name="validator" class="com.vimeo.community.validator.macro.validator" key="validator-macro">
    <description key="validator.macro.desc"/>
    <category name="formatting"/>
    <parameters>
      <parameter name="Name" type="string"/>
      <parameter name="Date" type="string"/>
    </parameters>
  </xhtml-macro>
  <rest name="Validator Rest" i18n-name-key="validator-rest.name" key="validator-rest" path="/validator" version="1.0">
    <description key="validator-rest.description">The Validator Rest Plugin</description>
  </rest>
</atlassian-plugin>

/src/main/java/com/vimeo/community/validator/rest/ValidatorRest.java

package com.vimeo.community.validator.rest;

import com.atlassian.plugins.rest.common.security.AnonymousAllowed;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

/**
 * A resource of message.
 */
@Path("/")
public class ValidatorRest {

    @GET
    @AnonymousAllowed
    @Path("/message")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Response getMessage()
    {
       return Response.ok(new ValidatorRestModel("Hello World")).build();
    }
}

/src/main/resources/js/validator.js

document.addEventListener('DOMContentLoaded', function () {
    const validateButton = document.querySelector('.validate-button');

    function updateValidator () {
        $.get('/rest/validator/1.0/message', function (response) {
            console.log(response);
        });
    }

    validateButton.addEventListener('click', function () {
        console.log('button was clicked');
        updateValidator();
    });
});

And the output:

I don’t have access to comp now but will check later.

Are you maybe getting exceptions in the backend logs?

Update: Just checked your code, works as expected. Why is not working for you, unknown. Check the error logs, should contain something helpful the moment you upload the plugin as well as when you run the ajax call