Table of Contents

Bureaucracy Plugin

Compatible with DokuWiki

  • 2024-02-06 "Kaos" yes
  • 2023-04-04 "Jack Jackrum" yes
  • 2022-07-31 "Igor" yes
  • 2020-07-29 "Hogfather" yes

plugin Easily create HTML forms to collect data which can be sent via email or used to create pages

Last updated on
2023-05-16
Provides
Syntax, Action
Repository
Source
Conflicts with
bureaucracyau, form

The bureaucracy plugin allows you to create a HTML form right within DokuWiki. Input format validation is automatically handled by the plugin and requires no coding. User input can be emailed to a preconfigured address or used to create new pages using a template.

Download and Installation

Search and install the plugin using the Extension Manager. Refer to Plugins on how to install plugins manually.

Changes

Build Status

On an open wiki, you might want to use the CAPTCHA plugin to avoid automated spam. When it is installed, Bureaucracy automatically integrates the captcha check in its form submission handling.

The SMTP plugin may help when your DokuWiki can't send mails.

When you use Bureaucracy's template action, you can add in the template a dataentry of the Data plugin that structures and stores your information for good accessibility, whereas the dataentry you can use placeholders of bureaucracy to place information from the form.

The recent Struct plugin draws heavy inspiration from the data plugin and allows for central management of wanted structured data while keeping the functionality of the data plugin. The struct plugin supports integration with the Bureaucracy Plugin. This allows reusing the input mechanisms of the different types in Bureaucracy forms and creation of structured data when pages are created through Bureaucracy's template action.

Additional Actions

An additional plugin to look at is pagemod, which adds a pagemod action for the Bureaucracy plugin to add data to an existing page (in addition to the current templating and mailing functionality)

Additional Fields

The Data plugin can not only be useful in templates as mentioned above, but it also provides a data_aliastextbox field that lets you create fields with types and type aliases of the data plugin. Some of these types have a nice layout e.g. pagesuggestions or listing using predefined options from type aliases. See example.

With Struct plugin, you can use any field from any defined schema as a field in a bureaucracy form. You can also add a whole schema to the form.

Warning

Without the CAPTCHA, this plugin should only be used on closed wikis, because it could easily be abused as a spam gateway.

Usage

Let's start with an example:

A sample form with validation errors

<form>
Action mail me@example.com
Thanks "Thanks for submitting your valuable data."

Fieldset "A set of fields"
Textbox  "Employee Name" "=Your Name"
number "Your Age" >13 <99
email "Your E-Mail Address"
textbox "Occupation (optional)" !
password "Some password"

fieldset "even more fields"
select "Please select an option" "Peaches|Apples|Oranges"
static "Some static text that could be an agreement"
yesno "Read the agreement?"
textarea "Tell me about your self"
textbox "You need to write 'agree' here" /^agree$/
submit "Submit Query"
</form>

As you can see, you can define a email address where the data should be sent to and a thank you text to be shown when a user submitted the form. What follows are the various fields to fill in.

Field definitions

The plugin takes care of validating the form, the field types, and set constraints.

Fields

Constraints and Defaults

A simple guide to Regular Expressions

A regular expression is used to define a pattern of text. In its simplest case (as used here) if the pattern can be found then the text is accepted, if the test fails then the text is rejected. Under bureaucracy, when the submit button is pushed text boxes are compared to their regular expressions. If the test passes, then submit can continue, if the test fails then submit rejects the form and asks for a correction.

The simplest possible regular expression (regex) is a single character: /a/. This states that the input text (the string) must contain somewhere within it the letter “a”. “access” would pass, as would “backups” but “Hello World” would fail.

The regex may contain a number of characters: /abc/ which requires that the string “abc” be found somewhere. “Learn your abc” passes but “a bc” fails (there is a space between the “a” and “b”).

Frequently you want to select one of a number of characters. Square brackets group a number of alternatives together: /[abc]/ means that either “a” or “b” or “c” must occur somewhere within the string. Ranges are possible, [a-z] means any lowercase letter. Putting things together, /rfc[0-9][0-9][0-9][0-9]/ matches any four digit request for comments such as “rfc0248” or “rfc4027”.

The brackets are called meta-characters, that is they don't represent real characters (like for instance “a”) but do affect how the string is interpreted. There are a number of meta-characters the most important of which are:

For example /^[yn]$/ means that the string must start with a “y” or and “n” and have no characters following. “y” and “n” are therefore the only possible strings. /^I[0-9]+$/ matches US interstate roads: “I12”, “I66” and so forth. Somewhat confusingly “^” has another meaning when it occurs immediately after a left bracket, it negates the contents. /[^ab]/ matches any character other than and “a” or “b”.

Looking now at the examples above. /^[^\/:]+$/ starts at the beginning of the string (“^”) accepts any character other than “/” or “:” (“[^\/:]”, note the “\” to make the “/” into a normal slash), accepts these characters 1 or more times (“+”) and then needs to see the end of the string “$”. “/home/doc.txt” fails, there are slashes present. “ puzzled ” is acceptable.

Finally /^[0-9 \/()+\-]+$/. The whole string consists of a one or more characters (“^” to “+$”). These characters must be (“[” to “]”) numbers (“0-9”), spaces (“ ”), slashes and parenthesis (“\/” and “()”), pluses and minuses (“+\-”).

For more information:

External Label Names

By default all labels are used as provided. Eg. they are displayed in the form and they are used as placeholders for the template mode. In some cases you might want to use simpler names for the fields but still have more extensive labels displayed in the form.

This can be achieved with defining label translations in a separate wiki page and give this page in the labels field:

<form>
action mail me@example.com
labels mylabels

fieldset "field"
textbox  "name"
number   "age" >13 <99
submit   "submit"
</form>

The translation page needs to contain a single wiki list with items named label = translation:

  * field  = Tell us about yourself
  * name   = Your Name
  * age    = Your Age
  * submit = Send your Data

The above would result in the following form:

Note: double slashes // cannot be used in the translation field on the translation page — SFITCS 2016-12-15 22:27

Dependencies with Fieldsets

Sometimes part of a form should only be asked when a certain answer was picked for a previous question. Simple dependencies like that can be created by using Fieldsets.

Consider the following example:

<form>
action    mail me@example.com

fieldset  "Your Order"
textbox   "Your Name"
select    "What do you want"  "Car|Blimp"

fieldset  "Car Parameters" "What do you want" "Car"
number    "Number of Wheels"
textbox   "Extras"

fieldset  "Blimp Parameters" "What do you want" "Blimp"
select    "Filling" "Helium|Hot Air"
number    "Size"

fieldset  "Payment"
yesno     "Can you pay right now?"

fieldset  "Details" "Can you pay right now?"
textbox   "Name"
number    "Amount"

fieldset  "Confirm Order"
submit "Submit Query"
</form>

In this example, a user can select to order a car or a blimp. Depending on his choice, the second or third fieldset will be hidden or shown accordingly. The second parameter for the fieldset field references a previously defined field and the third parameter the value that field shall have to display the fieldset. Only exact matches are supported here, so best combine this feature with a select field as shown above.

When the user marks the checkbox of the yesno field in the fourth fieldset the fifth fieldset is shown, so the correct details can be noted. Here is no third parameter given to the fieldset, because it will check if the referred yesno field is set (It will not look for the default values eventually set by “=Value” “!Not Value”. If you need the value of the yesno in a template, you have to provide the default values explicitly.).

NOTE:

Dependencies with Fieldsets - creating two levels of selects

How to use dependencies to adapt a select list. Example:

First level “select” list

select "Vehicule" "Car|Motorbike"

Second level “select” lists:

fieldset  "Car spareparts" "Vehicule" "Car"
select "Sparepart1" "4 wheels|steering wheel"

and

fieldset  "Motorbike spareparts" "Vehicule" "Motorbike"
select "Sparepart2" "3 wheels|handle bar"

To show only the shown value of both select fields “Sparepart1” and “Sparepart2” in a template, use the construct

@@Sparepart1|@@@@Sparepart2|@@

The chosen one will be filled out and the not chosen one will be replaced by an empty string (“”).

Sometimes you may want to link to a bureaucracy form and pre-fill one or more fields. This can be easily achieved by adding parameters to your link using @-wrapped field names.

Imagining the form given in the previous section is on a page called orderform. Here is how you could link to a form for ordering Hot Air blimps:

[[orderform?@What do you want@=Blimp&@Filling@=Hot Air|Order a Hot Air Blimp!]]

Action Modes

Bureaucracy does three things:

  1. it displays a neat form
  2. it validates user input
  3. it sends the user's input to an action mode

The last step is where the data is processed. The action to use is defined in the action field, as described above. Currently three modes are supported: mail, template, and script. Additional modes (e.g. to store the data in a database) can easily be added.

Mail Mode

This is a simple action. When used default, all user input will be sent by email to the configured email address. See the example above how to use it. You may specify multiple recipient mail addresses separated by commas.

Example to automate email to an address which the user enters:

Fieldset "Some Information"
Textbox "Employee Name"
email Email_Address
 
 
Action mail @@email_address@@

Example:

action mail @MAIL@ forename@surname.name 
usemailtemplate your:template
subject "new special subject"
your:template
======Mail template page======

<code html>
Dear @@Your Name@@,</br>
</br>
You are <b>great</b>, you just <i>purchased</i> our @@What do you want@@!</br>
</br>
We will deliver it fast as possible, see the </br>
<a href="http://example.com/conditions">conditions</a>.</br>
</br>
Kind regards,</br>
Future Machines company</br>
</code>

<code text>
Dear @@Your Name@@,

You are great, you just purchased our @@What do you want@@!

We will deliver it fast as possible, see [1].

Kind regards,
Future Machines company

[1] http://example.com/conditions
</code>

Template Mode

This action uses given pages as template, will replace defined placeholders with the user input and create wiki pages. This is a very powerful, but somewhat complex concept.

The action line looks as follows:

action template [template] [destination] [separator]

Defining the destination(s)

When using the template mode you need to define where resulting pages should be created. There are multiple ways to do this.

Method 1 The simplest way is to specify an output namespace and mark up your naming fields using the @ character. Here's an example:

<form>
action   template userstpl users: :

fieldset "Create Your User Page"
select   "What's your Continent?" "Europe|N. America|S. America|Asia|Australia|Africa" @
textbox  "What's your Name?" @
textarea "Enter a short bio" !
submit
</form>

This would create a new page using the continent and name fields. Eg. if I fill in “Europe” and “Andi” for those fields, the resulting page would be users:europe:andi.

Method 2 Sometimes you want some more control over the resulting pagename(s). This can be achieved by using placeholders in the destination parameter and omitting the @ marker in the field definitions.

Placeholders are the field names surrounded by @@ characters. Additionally any strftime parameters can be used. Let's have another example:

<form>
action   template userstpl "users:%Y:@@What's your Name?@@:start"

fieldset "Create Your User Page"
select   "What's your Continent?" "Europe|N. America|S. America|Asia|Australia"
textbox  "What's your Name?"
textarea "Enter a short bio" !
yesno    "Do have publication?"

fieldset "Add your publications" "Do have publication?"
textarea "Publications:"
addpage   users:publicationtemplate publications

fieldset "Finish"
submit
</form>

The above would create a namespace based on the current year and my name and create a start page within it: users:2012:andi:start

Method 3 When working with Dependencies with Fieldsets you might want to add additional pages when a fieldset is shown, but skip the page when the fieldset is hidden. This can be achieved with the special addpage field.

Just put it in the fieldset of question:

addpage additionaltpl somepage

The second fieldset from the example above adds a publication page, via a checkbox. Here the template for additional page is located on absolute path: users:publicationtemplate. Only when the yesno field is checked, the additional page is created on users:2012:andy:start:publications

Creating Templates

The templates need to contain the same fields as your form, and some other placeholders are available too. Some of them can be used as default values for form fields:

Placeholder action
@@Field label@@
##Field label##
Will be replaced by the actual values the user filled into
the form.
@curNS(arg)@
@getNS(arg)@
@noNS(arg)@
@p_get_first_heading(arg)@
Will be replaced with a result of the corresponding dokuwiki function. arg can be both a static value, eg. @curNS(some:test:value)@ or the placeholder of a field, eg. @p_get_first_heading(@@field@@)@.
@@Field label|Nice alternative@@ For empty field the text Nice alternative is shown
@NSBASE@ (only template action) Namespace that contains new page.
eg. if the new page is foo:bar:baz:bang, @NSBASE@ will contain baz
%Y %F %a %Y-%m-%d %s… etc strftime parameters to refer to current time
%% Replaced by % char, needed to avoid accidental time replacements in your template.
@DATE(<datetime>,%%Y-%%m-%%d)@
@DATE(<datetime>)@
Accepts different datetime formats, which are outputted in the requested strftime format. If no format is provided, date is returned with format of the dformat setting. (Example)
@ID@ @USER@ @MAIL@ … etc DokuWiki replacement patterns for templates are available too
@FORMPAGE_ID@ @FORMPAGE_NS@ @FORMPAGE_CURNS@ … etc Works like replacement patterns but refers to the page with the form
@YEAR@, @MONTH@, @DAY@, @TIME@, @TIMESEC@ Print current: year, month, day, time as hh:mm
and time as hh:mm:ss
@TABLEHTML@, @TABLETEXT@ (only mail action) html or text table of all field values
<noinclude>…</noinclude> Tags with their content are removed
<noreplace>…</noreplace> The content between <noreplace>…</noreplace> is preserved without performing any replacements but tags itself are removed.
@LANG@ Languagecode as configured
@TRANS@ Languagecode obtained from page id of form

For the userstpl from the example above, you could have the following page:

====== @@What's your Name?@@ ======

I'm living in @@What's your Continent?@@. I'm a user since %Y-%m-%d.

@@Enter a short bio|FIXME please fill in your biography@@

The result then would look somewhat like this with all the user data filled in:

====== Andreas Gohr ======

I'm living in Europe. I'm a user since 2007-12-23.

It's me :-)

ACL Checking & runas Option

By default this plugin will check for ACLs in template mode using the permissions of the user filling the form. This means the user needs to have at least read permissions for the template and create permissions for the namespace where the new page should be saved.

However sometimes you may want to give anonymous users a way to create pages in a restricted namespace without giving them any direct access. This is where the runas option comes into play. With this option you can specify a username in the config manager. The user you specify here will always be used for checking the permissions mentioned above, regardless of the user filling the form. This way you can specify the needed access for this particular virtual user in the ACL manager.

Note: the runas user does not need to exist. In fact it is recommended to use a non existing user. Even when it exists, permission checks are done on user level only, groups of the user will be ignored.

Accessing user field infos

When using a user or users field, additional data of the selected users can be used in the template:

Script Mode

This action gives the data to a PHP script supplied by the administrator. The script then can do whatever it wants with the data.

The script must be placed in conf/plugin/bureaucracy/ directory. It must contain one class that is named helper_plugin_bureaucracy_handler_scriptname and implements the interface dokuwiki\plugin\bureaucracy\interfaces\bureaucracy_handler_interface

That means the class has to have the handleData($fields, $thanks) method with the fields and the thanks-message as parameters. It returns a thanks-message on success or false on error.

Example

This is a simple script handler that will just print the form's arguments in DokuWiki's debug log.

<form>
action script example.php
textbox "Type something"
submit "Write to log"
</form>
conf/plugin/bureaucracy/example.php
<?php
use dokuwiki\plugin\bureaucracy\interfaces\bureaucracy_handler_interface;
 
class helper_plugin_bureaucracy_handler_example implements bureaucracy_handler_interface {
 
    /**
     * Log the form fields to DokuWiki's debug log
     */
    public function handleData($fields, $thanks)
    {
        dbglog($fields, __FILE__ . ': ' . __LINE__);
        dbglog($thanks, __FILE__ . ': ' . __LINE__);
 
        return $thanks;
    }
}

Examples

Checkbox field

Example code for checkbox field:

yesno     "Are you happy?" "=Yes sir" "!No sir"

yesno     "Show fieldset?"
fieldset  "Shown on checking the box" "Show fieldset?"
textbox   "Share your praise"

Number field

number "One"
number "Two" ++
number "Third" >3 <40
hiddenautoinc "Four (notice: conflicts with Two)"
number "Fifth" 000
number "Sixth" ++ 000

Template placeholder @DATE@

hidden "today" "=%Y-%m-%d"
hidden "backtrack" "=@DATE(now -3 years,%%Y-%%m-%%d)@"

Development

Adding a new field type

To add a new type, you need to implement a Helper Plugin inheriting from helper_plugin_bureaucracy_field. There you probably want to overwrite the renderfield() method and probably some other methods as well. Your field will automatically be available as type <plugin>_<component>. Eg. lib/plugins/foo/helper/bang.php creates a new type foo_bang.

If you need more control over adding one or more fields, you can implement an Action Plugin hooking to PLUGIN_BUREAUCRACY_FIELD_UNKNOWN. This event only has a BEFORE event and provides the following data:

$data = array(
   'fields' => &array(), // the fields initialized so far - add yours here
   'args' => array() // the tokenized line, args[0] should be your plugin
);

In your handler you need to check that args[0] is the field type you want to register. If it is, you need to call preventDefault() and add your own field(s) to the fields array. The added field has to be a descendant of helper_plugin_bureaucracy_field!

Adding a new action

To add a new action create a new Helper Plugin inheriting from helper_plugin_bureaucracy_action. This works similar to adding a new field described above.

Theres is also an Event you can hook called PLUGIN_BUREAUCRACY_ACTION_UNKNOWN. Again, there's only a preventable BEFORE event.

FIXME describe passed data in detail. For now check the source.

Influence Template mode

Saving the final page in template mode triggers an event called PLUGIN_BUREAUCRACY_TEMPLATE_SAVE. In the before mode you can prevent saving the page or modify it's content. The after event is triggered after a page has been created.

Passed data:

$data = array(
  'patterns' => &array(), // list of PREG patterns to be replaced
  'values' => &array(), // values for the above patterns
  'id' => string, // ID of the page being written
  'template' => &string, // the loaded template text
  'form' => string, // the page the bureaucracy form was on
  'fields' => helper_plugin_bureaucracy_field[], // all the fields of the form
);

Hook into email action

The event PLUGIN_BUREAUCRACY_EMAIL_SEND gives developers of other plugins access to the submitted form data before it is actually sent in the actionmail.php.

This makes it easier to provide custom fields in bureaucracy emails.

The event data includes the form fields info and all the values, so they can be processed by third-party plugins:

$evdata = [
    'fields' => $fields,
    'values' => &$this->values
];

Customisations

Important! These are hacks - there is no guarantee they'll always work, and they will not survive updates.

If it breaks you get to keep the pieces. :-)

Customise the Date Format

NOTE: The configuration setting for the PHP strftime function in /conf/dokuwiki.php also need to be changed (can also be changed via Admin→Configuration)

$conf['dformat']     = '%d/%m/%Y %H:%M';

To change the default date format from yy-mm-dd to dd-mm-yy (e.g. for Australia)

Change the jQuery datepicker format /plugins/bureaucracy/script/datepicker.js from:-

/**
 * Init datepicker for all date fields
 */
 
jQuery(function(){
    jQuery('.bureaucracy__plugin .datepicker').datepicker({
        dateFormat: "yy-mm-dd",
        changeMonth: true,
        changeYear: true
    });
});

to this:-

/**
 * Init datepicker for all date fields
 */
 
jQuery(function(){
    jQuery('.bureaucracy__plugin .datepicker').datepicker({
        dateFormat: "dd-mm-yy",
        changeMonth: true,
        changeYear: true
    });
});

Change the Bureaucracy error message in /bureaucracy/lang/en/lang.php from:-

$lang['e_date']          = '"%s" needs to be a valid date in the format yyyy-mm-dd.';

to this:-

$lang['e_date']          = '"%s" needs to be a valid date in the format dd-mm-yyyy.';

Change the Bureaucracy date validation in /bureaucracy/helper/fielddate.php from:-

     * Validate field input
     *
     * @throws Exception when empty or wrong date format
     */
    protected function _validate() {
        parent::_validate();
 
        $value = $this->getParam('value');
        if (!is_null($value) && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
            throw new Exception(sprintf($this->getLang('e_date'),hsc($this->getParam('display'))));
        }
    }
}

to this:-

     * Validate field input
     *
     * @throws Exception when empty or wrong date format
     */
    protected function _validate() {
        parent::_validate();
 
        $value = $this->getParam('value');
        if (!is_null($value) && !preg_match('/^\d{2}-\d{2}-\d{4}$/', $value)) {
            throw new Exception(sprintf($this->getLang('e_date'),hsc($this->getParam('display'))));
        }
    }
}

As of release 2016-03-11 it is also necessary to change this:-

if(preg_match('/^(\d\d\d\d)-(\d\d?)-(\d\d?)$/', $value, $m)) {

to this:-

if(preg_match('/^(\d\d?)-(\d\d?)-(\d\d\d\d)$/', $value, $m)) {

SFITCS 2016-11-26 01:16

Now packaged as a plugin - bureaucracy-auSFITCS 2017-03-10 08:23

Customise the Thankyou message

To allow inserting DokuWiki code into the Thankyou field.

Change the syntax in bureaucracy/syntax.php from:-

$thanks .= '<p>' . $thanks_string . '</p>';

to this:-

$thanks .= p_render('xhtml',p_get_instructions($data['thanks']),$info);

Which then allows the use of a link back to the same page when processing a Bureaucracy form:-

Thanks [[$examplepage|Continue]]

NOTE: If form creates a data plugin edit table the wiki code needs to be quoted (surrounded by “ ” quotes as in the example below)

Thanks "[[$page|Continue]]"

CSS Formatting

Issues

Please report bug or feature request on the Github bugtracker.