Skip to content

Developing Plugins

Nicholis edited this page Jun 21, 2024 · 3 revisions

javadoc

The SnowMail API module is published to Maven Central.

<dependencies>
  <dependency>
    <groupId>dev.truewinter.snowmail</groupId>
    <artifactId>api</artifactId>
    <!-- Replace VERSION with the version of SnowMail you have installed -->
    <version>VERSION</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

Plugin Information File

You will need to create a resource file called plugin.yml. The contents of the file should be as follows:

# A unique name for your plugin. Please only use alphanumeric characters and dashes.
name: ExamplePlugin

# The plugin's main class
main_class: com.example.exampleplugin.ExamplePlugin

Developing Your Plugin

Warning

The plugin API is a beta feature. Breaking changes may be made at any time.

Now you can start developing your plugin. The plugin's main class must extend Plugin.

public class ExamplePlugin extends Plugin {
  // Important: It is not safe to interact with SnowMail until the onLoad() method is called
  @Override
  public void onLoad() {
    getLogger().info("Loaded plugin");
    registerListeners(this, new EventListener());
    getLogger().info("Registered event listeners");
  }

  @Override
  public void onUnload() {
    getLogger().info("Unloaded plugin");
  }
}

Registering event listeners requires an instance of a class that implements Listener.

public class EventListener implements Listener {
  /*
    The method can be called anything you'd like, but it must be annotated with
    @EventHandler and there must be one parameter (and no more) with the Event
    you want to subscribe to.
  */
  @EventHandler
  public void onFormSubmit(FormSubmissionEvent e) {
    // Handle the form submission

    /*
      If your plugin needs to handle a custom input server-side, it's a good idea to
      check if the input was added to the form. `getForm()` returns the inputs stored
      in the database at the time of the submission, so it's safe from client-side tampering.
    */
    if (!Form.recursivelyGetInputs(e.getForm().getInputs()).containsKey("myinput")) return;

    /*
      Some events are cancellable. Cancelled events prevent SnowMail from
      handling the event (e.g. cancelling a FormSubmissionEvent event will
      stop SnowMail from sending an email for the submission) and prevent
      other plugins from receiving the event (unless they opted to receive
      cancelled events by passing `receiveCancelled = true` to the
      EventHandler annotation).
    */
    e.setCancelled(true);
  }
}

Note that all listeners are blocking, so please ensure your plugin does what it needs to as quickly as possible.

Example: Registering an Input

Important

If you change an input, users will need to remove and re-add the input for changes to take effect. This is because forms are designed to continue working even if a plugin is removed. It is possible to use the API to edit forms after an update, but this is not recommended as users may have customized the input.

// In the onLoad() method

TextInput email = new TextInput();
email.setType(TextInput.TextInputTypes.EMAIL);
// Make sure you set the required properties
email.setLabel("Email");
email.setName("email");
/*
  Plugins can set custom display names for inputs
  which cannot be modified through the dashboard
  (except for the Multiple input). Modifying the
  custom display name through the REST API is possible.
*/
email.setCustomDisplayName("Email");
email.setPattern("^.+@.+\\..+$");
email.setPatternError("Invalid email address");

/*
  You should always check if your input is valid
  before adding it to the custom input registry.
*/
if (!email.isValid()) {
  getLogger().error("Email input failed validation");
  return;
}

getApi().registerInput(email);

Note

At this time, a custom input can only be used once in a form.

Example: Creating a Settings Form

If you require users to configure an input, you can add a settings form.

firefox_7Q3QEMD4B6

// Your custom input
Input input;
LinkedList<Input> settings = new LinkedList<>();

TextInput foo = new TextInput();
// It is recommended to prefix settings with your plugin name
foo.setName("myplugin-foo");
foo.setLabel("Foo");
foo.setRequired(true);
settings.add(foo);

input.getSettings().addAll(settings);
getApi().registerInput(input);

If you need the setting value client-side, add %metadata:myplugin-foo% to the input and this will automatically be replaced by the value the user set.

Example: Plugin with Config File

SnowMail uses BoostedYAML for plugin configuration files. Add a config.yml file in your plugin's resources with your configuration defaults.

# config.yml

foo: bar
// In the onLoad() method

// Default config file copied to `data/plugins/{plugin_name}/config.yml
copyDefaultConfig();
YamlDocument config = YamlDocument.create(getConfig());
// The value of foo is "bar"
String foo = config.getString("foo");

Using Other Installed Plugins

SnowMail allows plugins to interact with other plugins installed on the same instance. To do so, your main class must implement ExternalPlugin. Only after the onAllPluginsLoaded() method has been called, can you use the getPluginByName() method to get an instance of another plugin.

Clone this wiki locally