Setup

  • Build this plugin with mvn clean package -DskipTests. A fat jar will be located in the target folder

  • Create a folder called plugins in your mesh directory if it does not exist yet

  • Put the fat jar inside your plugins folder

  • Create the folders plugins/forms, plugins/forms/templates

  • Create a file plugins/forms/config.yml. See the configuration section for more details

  • Create handlebars templates in your plugins/forms/templates folder

  • To enable mail sending:

    • Configure mail settings in config.yml

    • Add fromAddress in config.yml

    • Create templates for usermails and adminmails

    • Configure paths to templates as adminMailTemplate and userMailTemplate in config.yml (without the .hbs extension)

    • Configure adminMailSubject and userMailSubject in config.yml

API

A specification of the API can be found in the file api.yaml. You can paste the contents of that file to https://editor.swagger.io/ to get a nice overview.

Configuration

Fields

Key Type Description Default value

templatesPath

string

base path to the templates

plugins/forms/templates

elements

map of strings

Definition of custom elements. Each entry maps the type of the custom element to the implementation class

mail

object

Mail settings

fromAddress

string

Address to use as from when sending mails

adminMailTemplate

string

Path to the default template for admin mails, relative to templatesPath. Template name must be set without extension .hbs.

adminMailSubject

string

Subject for admin mails. Placeholder will be replaced with the name of the form

userMailTemplate

string

Path to the default template for user mails, relative to templatesPath. Template name must be set without extension .hbs.

userMailSubject

string

Subject for user mails. Placeholder will be replaced with the name of the form

defaultExportFormat

string

Default export format. Currently, only CSV is supported

CSV

export

object

Export settings

reCaptcha

object

Recaptcha settings

friendlyCaptcha

object

FriendlyRecaptcha settings

proxyOptions

object

Proxy settings, if http proxy is required for accessing the recaptcha/friendlycaptcha verification URL

fileUpload

object

Definition of allowed filetypes/filenames per selected allowed_filetypes attribute of the file element

fileUpload.allowedFileTypes

map of string arrays

Keys are types of allowed files, maps are lists of regular expressions for matching the filetypes against

fileUpload.allowedFileNames

map of string arrays

Keys are types of allowed files, maps are lists of regular expressions for matching the filenames against

fileUpload.defaultAllowed

string array

List of types (from the configuration above), which are allowed by default (unless overwritten by allowed_filetypes of an element)

custom

map of objects

Custom configurations you can use in your extensions and handlebars template

security

object

Security options for rejecting or sanitizing submitted values. Values for security.injectionPreventionMode are NONE (no checks; default value), REJECT (mark invalid data as validation error), REJECT_MARKUP (mark invalid data and text containing markup as validation error), SANITIZE (replace invalid data) and SANITIZE_MARKUP (replace invalid data and markup). Invalid data is specified via security.sanitationRules. A mapping from regex patterns for invalid data to their respective replacements (if the regex contains captured groups, the replace can reference the group with $ (e.g. "\\.(\\S)": ". $1" will place a space after a dot but keep the character immediately after). Note that the plugin will abort its initialization with an error if any of the sanitation rule keys is not a valid regular expression.

poll

object

Overrides for POLL forms. Currently the only field is resultTemplate which defines which .hbs file will be used for rendering poll results.

downloadPurgeInterval

integer

Downloads have to be this days old, to be automatically deleted. The deletion of old downloads happens on every Mesh start, and repeats each day. If the provided value is 0 or a negative number, the download purge will never start.

1, e.g. all the one day old downloads are to be deleted on a next purge schedule.

staleDataPurgeInterval

integer

Stale user data nodes have to be this days old, to be automatically deleted. The deletion of stale data nodes happens on every Mesh start, and repeats each day. If the provided value is 0 or a negative number, the stale data purge will never start.

1, e.g. all the one day old stale data nodes are to be deleted on a next purge schedule.

validateElements

boolean

Should the form be validated, before is gets stored or updated?

false

Example Configuration File

templatesPath: "plugins/forms/templates"
poll:
  resultTemplate: poll-results
elements:
  custom: com.acme.CustomElement
mail:
  hostname: localhost
  port: 25
  authMethods:
  username:
  password:
  ssl: false
  trustAll: false
  keepAlive: true
  maxPoolSize: 10
  ownHostname:
  attachFileUploads: false
fromAddress: "webmaster@gentics.com"
adminMailTemplate: "adminemail"
adminMailSubject: "Formular [[FORMNAME]] ausgefΓΌllt"
userMailTemplate: "useremail"
userMailSubject: "Herzlichen Dank"
defaultExportFormat: CSV
reCaptcha:
  verificationUrl: "your-verification-url"
  siteKey: "your-site-key"
  secretKey: "your-secret-key"
friendlyCaptcha:
  siteKey: "your-site-key"
  secretKey: "your-secret-key"
  verificationUrl: "your-verification-url"
proxyOptions:
  host: proxy.acme.com
  port: 4711
  user: proxyuser
  password: proxypassword
  active: false
fileUpload:
  allowedFileTypes:
    all:
      - ".*"
    image:
      - "image/.*"
    audio:
      - "audio/.*"
    video:
      - "video/.*"
  allowedFileNames:
    archive:
      - ".*\\.zip"
      - ".*\\.rar"
      - ".*\\.7z"
      - ".*\\.bz"
      - ".*\\.bz2"
      - ".*\\.gz"
    documents:
      - ".*\\.doc"
      - ".*\\.docx"
      - ".*\\.xls"
      - ".*\\.xlsx"
      - ".*\\.pdf"
      - ".*\\.txt"
      - ".*\\.ods"
      - ".*\\.odt"
  defaultAllowed:
    - "all"
custom:
  test: "test"
  testobject:
    testfield: "another test field"

Default Elements

Common properties

Key Type Description Default value

name

string

Field name

REQUIRED

type

string

Field type (see the list of element types below)

REQUIRED

label

string

Field label. Localized labels and the rendering subtype are resolved via the form’s uiSchema.

null

active

boolean

Flag to activate/deactivate fields. Deactivated fields will not be rendered in the form any more (but previously POSTed data is still available)

true

isList

boolean

Flag for multivalue fields

false

mandatory

boolean

Flag for mandatory field

false

validation

validation

Validation rules for POSTed data, as a nested object (see Server-side Validation)

null

Every element may have arbitrary additional properties (collected into the element’s properties map), which will only be used for rendering.

Available element types

The plugin ships with the following built-in element types:

  • string

  • number

  • boolean

  • datetime

  • time

  • binary

  • catalog

  • usermail

  • adminmail

Registering custom elements

Element types are discovered automatically at class-load time: the ElementTypeRegistry scans the package com.gentics.mesh.plugin.forms.model for classes annotated with @FormElementType and maps the declared JSON type name(s) to their implementation class. No entry in config.yml is required.

To add a custom element type:

  1. Create a class in the com.gentics.mesh.plugin.forms.model package that extends com.gentics.mesh.plugin.forms.model.FormElement.

  2. Annotate it with @FormElementType(…​), passing the JSON type name(s) the class should handle.

package com.gentics.mesh.plugin.forms.model;

@FormElementType("mytype")
public class MyElement extends FormElement {
    // ...
}

A single class can handle multiple type names by passing an array, e.g. @FormElementType({"c1", "c2"}). If two classes claim the same type name, the last one discovered wins.

Server-side Validation

Server-side validation will check whether the user has filled mandatory fields. Furthermore, entered values will be checked against the field’s validation object. The validation property is a nested object with the following keys:

Key Type Description

minValue

integer

Value must consist of digits and be greater than or equal to minValue

maxValue

integer

Value must consist of digits and be less than or equal to maxValue

minLength

integer

Value strings must have at least length minLength

maxLength

integer

Value strings must have at most length maxLength

regexValidation

object

Object with a single key regex; the value string must match the given regular expression

binary

object

Upload restrictions for binary elements (see below)

The binary object inside validation configures upload restrictions for binary elements:

Key Type Description

maxFilesize

integer

Maximum allowed file size in MB

allowedFileTypes

array of strings

Allowed MIME-type regexes (validated against the detected content type)

allowedFileNames

array of strings

Allowed file-name regexes (validated against the file name)

allowedTypes

array of strings

Keys referencing the configured fileUpload.allowedFileTypes / fileUpload.allowedFileNames groups

Example of a validation object:

{
    "minLength": 3,
    "maxLength": 50,
    "regexValidation": { "regex": "^[A-Za-z ]+$" }
}

Error message translations

The following translations must be available for validation error messages (set via the POST /translations endpoint):

Key Params Description

form_validation_error_missing_mandatory_field_title

-

Title for missing mandatory fields.

form_validation_error_missing_mandatory_field

Field label

Error message for missing mandatory fields.

form_validation_error_invalid_value_title

-

Title for custom validation.

form_validation_error_invalid_value

Field name, invalid value

Error message for custom validation violation.

form_validation_error_unsafe_value_title

-

Title for unsafe value.

form_validation_error_unsafe_value

Invalid field name

Error message for unsafe value.

form_validation_error_min_value_title

-

Title for minimum value error message.

form_validation_error_min_value

Value

Error message for minimum value violation.

form_validation_error_max_value_title

-

Title for maximum value error message.

form_validation_error_max_value

Value

Error message for maximum value violation.

form_validation_error_min_length_title

-

Title for minimum length error message.

form_validation_error_min_length

Value

Error message for minimum length violation.

form_validation_error_max_length_title

-

Title for maximum length error message.

form_validation_error_max_length

Value

Error message for maximum length violation.

form_validation_error_pattern_title

-

Title for pattern error message.

form_validation_error_pattern

Value

Error message for regular expression violation.

form_validation_error_file_size_title

-

Title for file size error message.

form_validation_error_file_size

Filename, filesize

Error message for file size violation.

form_validation_error_file_type_title

-

Title for file type error message.

form_validation_error_file_type

Filename

Error message for file type violation.

form_validation_error_email_title

-

Title for invalid email error message.

form_validation_error_email_type

Email

Error message for invalid email.

ReCaptcha

The plugin supports Google reCAPTCHA (v2). On submission the plugin reads the captcha response token from the configured HTTP request header (responseTokenKey) and verifies it against the verification URL (secret + response are POSTed, and the response must contain success: true). Mandatory settings for reCAPTCHA to work are siteKey and secretKey.

Configuration Options

These are the options available for the reCAPTCHA implementation:

Key Type Description Default value

siteKey

string

Site key from reCAPTCHA

empty

secretKey

string

Secret key from reCAPTCHA

empty

responseTokenKey

string

Name of the HTTP request header carrying the captcha response token

x-recaptcha-token

verificationUrl

string

URL against which the captcha response is verified

https://www.google.com/recaptcha/api/siteverify

Friendly Captcha

Mandatory settings for the friendlyCaptcha to work are siteKey and secretKey

Configuration Options

These are the options available for the FriendlyCaptcha Implementation

Key Type Description Default value

siteKey

string

Key from the FriendlyCaptcha

empty

secretKey

string

Secret from FriendlyCaptcha

empty

solutionKey

string

Key for the field containing the hash of the verification

frc-captcha-solution

verificationUrl

string

URL against which the captcha is verified

https://api.friendlycaptcha.com/api/v1/siteverify

acceptOnErrorStatus

boolean

Activates recommended behaviour as mentioned here

false

Endpoint

The endpoint for the EU which is mentioned here must be activated and the Worldwide one can be deactivated, so check that before using Friendlycaptcha.

Poll rendering

The main handlebars template for rendering poll results is by default <templatesPath>/poll-results.hbs.

The handlebars helper pollResultTemplate will resolve the handlebars partial for a poll result element analogously to the formsElementTemplate helper will resolve partials for normal form elements. Partials for poll result templates must be located in <templatesPath>/poll-results. A dedicated poll-result partial is only resolved for the boolean (checkbox) and catalog element types; all other element types fall back to the generic poll-result partial.

Extending

For extending the forms-plugin, a new maven project must be created, that uses the forms-plugin as dependency and builds a custom mesh-plugin, containing the forms-plugin together with the custom extension classes.

Example pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.gentics</groupId>
  <artifactId>custom-forms-plugin</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <properties>
    <mesh.version>0.31.4</mesh.version>
    <vertx.version>3.5.4</vertx.version>
    <forms.plugin.version>1.6.16</forms.plugin.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.gentics.mesh</groupId>
      <artifactId>mesh-plugin-api</artifactId>
      <version>${mesh.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.gentics.mesh</groupId>
      <artifactId>mesh-rest-client</artifactId>
      <version>${mesh.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web-templ-handlebars</artifactId>
      <version>${vertx.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-mail-client</artifactId>
      <version>${vertx.version}</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
         <groupId>com.gentics.mesh.plugin.commercial</groupId>
         <artifactId>mesh-forms-plugin</artifactId>
         <version>${forms.plugin.version}</version>
     </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <executions>
          <!-- Run shade goal on package phase -->
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer
                  implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Verticle>service:com.gentics.mesh.plugin.plugin-service</Main-Verticle>
                  </manifestEntries>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <repositories>
      <repository>
        <id>gentics.nexus.releases-oss</id>
        <name>Gentics Nexus OSS Maven Repository</name>
        <url>https://repo.gentics.com/repository/maven-releases-oss/</url>
        <releases>
          <enabled>true</enabled>
        </releases>
        <snapshots>
          <enabled>false</enabled>
        </snapshots>
      </repository>
      <repository>
        <id>gentics.nexus.releases</id>
        <name>Gentics Nexus Maven Repository</name>
        <url>https://repo.gentics.com/repository/maven-releases/</url>
        <releases>
          <enabled>true</enabled>
        </releases>
        <snapshots>
          <enabled>false</enabled>
        </snapshots>
      </repository>
      <repository>
        <id>gentics.nexus.snapshots</id>
        <name>Gentics Snapshots Repository</name>
        <url>https://repo.gentics.com/repository/maven-snapshots/</url>
        <releases>
          <enabled>false</enabled>
        </releases>
        <snapshots>
          <enabled>true</enabled>
        </snapshots>
      </repository>
    </repositories>
</project>

Example src/main/resources/mesh-plugin.json

{
  "name": "Custom Forms Plugin",
  "apiName": "forms",
  "description": "Custom Plugin for management of forms",
  "license": "Commercial",
  "inception": "2019-05-14",
  "author": "Gentics",
  "version": "1.0"
}

Custom Elements

  • Custom elements can be implemented by extending class com.gentics.mesh.plugin.forms.model.FormElement

  • Mapping for custom element types to classes must be added to elements in the configuration file config.yml

Handlebars helpers

The following helpers are available for rendering mail bodies or HTML markup:

  • formsElementTemplate ELEMENT_TYPE: returns the path to the template partial for the given type (when rendering forms)

  • pollResultTemplate ELEMENT_TYPE: returns the path to the template partial for the given type (when rendering poll results)

  • formsInputType INPUT_ELEMENT: returns the suggested input type for the given element

  • formatDate DATE TARGET_FORMAT [SOURCE_FORMAT]: returns the given date formatted with TARGET_FORMAT. When no SOURCE_FORMAT is specified, the input is assumed to be in the form YYY-MM-DD.

  • formatTime TIME TARGET_FORMAT [SOURCE_FORMAT]: same as formatDate for a time. When no SOURCE_FORMAT is specified the input is assumed to be in the form HH:mm. Note that both formatDate and formatTime can be used to format with any pattern parsable by the DateTimeFormatter class. The distinct helpers are just provided with different default source formats for convenience reasons.

  • startsWith checks if string variable starts with match string

{{#startsWith element.name 'hidden_element'}}
    <!-- true action here -->
  {{else}}
    <!-- false action here -->
{{/startsWith}}

Data structure

The internal data structure in Mesh consists of the following nodes for every project, where the forms-plugin is activated.

.
└── "Forms Plugin" (forms_plugin)
    β”œβ”€β”€ "Form #1" (form)
    β”‚   β”œβ”€β”€ "Data" (form_folder)
    β”‚   β”‚   β”œβ”€β”€ Form Post Data (form_[uuid])
    β”‚   β”‚   └── ...
    β”‚   └── "Downloads" (form_folder)
    β”‚       β”œβ”€β”€ "form-export_Form #1_2023-10-16_081237" (form_download)
    β”‚       └── ...
    β”œβ”€β”€ "Form #2" (form)
    β”‚   └── ...
    └── "Form #3" (form)
        └── ...

The forms plugin uses the following schemas:

Schema Description

forms_plugin

Root node of the data structure. Contains the languages, the forms plugin uses for the project.

form

Schema for form definitions. Contains the JSON definition of the form and is container for form specific data.

form_folder

Schema for containers (children of form nodes) holding data of specific types. Currently used for "Downloads" and "Data".

form_[uuid]

Schema for POSTed form data for a specific form. The form uuid is used as part of the schema name. Nodes will be created under the "Data" form_folder.

form_download

Schema for downloads, which either contain the uploaded binaries, or exports of POSTed data. Nodes will be created under the "Downloads" form_folder.