.. include:: /globals.rst Getting started =============== This page is a how-to to help you write a dummy plugin. Directory organization ---------------------- Your plugin should take place in *{fd-directory}/plugins/addons/yourpluginname* for an addon. Plugins adding a user tab should go into *{fd-directory}/plugins/personal/yourpluginname*. Plugins adding a system tab should go into *{fd-directory}/plugins/admin/systems/yourpluginname*. Plugins adding a service should go into *{fd-directory}/plugins/admin/systems/services/yourpluginname*. Your main file should be named *class_MyPluginClass.inc*. Icons ----- If your plugin packs some icons, they need to be placed in the breezy icon theme: *{fd-directory}/html/themes/breezy/icons/{size}/{category}* Most of the time your icons are those of an application and should therefore be placed in the *apps* folder, which is for the category *applications*. For instance if the small icon for apache goes in *{fd-directory}/html/themes/breezy/icons/16/apps/apache.png* and is used in the code as *geticon.php?context=applications&icon=apache&size=16* Basic plugin writing -------------------- This is the code for an empty plugin: .. code-block:: php _('Demo Plugin'), 'plTitle' => _('Demo Plugin informations'), 'plDescription' => _('Edit some useless personal information'), 'plSelfModify' => TRUE, // Does this plugin have an owner that might be able to edit its entry 'plObjectType' => ['user'], 'plObjectClass' => ['demoPlugin'], // simplePlugin can generate the ACL list for us 'plProvidedAcls' => parent::generatePlProvidedAcls(self::getAttributesInfo()) ]; } // The main function : information about attributes static function getAttributesInfo (): array { return [ ]; } } With this code you'll have an empty plugin, just adding the "demoPlugin" objectClass. The :ref:`pl-info` static function must provide informations about your plugin. Please fill **plShortName** and **plDescription** with something meaningful (and **plTitle** as well if your plugin have its own page). See :ref:`pl-info` for more details about other fields Attributes ---------- You might have noticed the empty getAttributesInfo method. This is where the magic happens. You should fill this function with an array of sections containing attributes. Available attribute types are BooleanAttribute, IntAttribute, FloatAttribute, StringAttribute, SelectAttribute, PasswordAttribute… The names are pretty clear about what these attributes are. There are also three special kind of attributes, SetAttribute, ArrayAttribute and CompositeAttribute. SetAttribute and ArrayAttribute might both be used for multi-valuated attribute. Array will allow several identical values while Set won't. A composite attribute is a unique LDAP attribute composed of several displayed attributes. You'll see one in the following example. For more information about each type of attribute, see :ref:`attributes` Example ------- .. code-block:: php [ 'name' => _('Hair Information'), 'attrs' => [ new SetAttribute( // This attribute is multi-valuated new SelectAttribute ( _('Color'), // Label of the attribute _('Color of the hair'), // Description 'hairColor', // LDAP name TRUE, // Mandatory ['blond','black','brown'], // [SelectAttribute] Choices '', // We don't set any default value, it will be the first one ['Blond','Black','Brown'] // [SelectAttribute] Output choices ) ), new FloatAttribute ( _('Length'), // Label _('Length of the hair in cm'), // Description 'hairLength', // LDAP name FALSE, // Not mandatory 0, // [FloatAttribute] Minimum value FALSE, // [FloatAttribute] No maximum value 10 // [FloatAttribute] Default value ), ] ], 'section2' => [ 'name' => _('Bicycle'), 'attrs' => [ new StringAttribute ( _('Brand'), // Label _('Brand of the bicycle'), // Description 'bicycleBrand', // LDAP name TRUE, // Mandatory 'GreatBicycleBrand' // Default value ), new BooleanAttribute ( _('Has a bell'), // Label _('Does the bicycle have a bell'), // Description 'bicycleBell', // LDAP name FALSE, // Not mandatory FALSE // Default value ), ] ], 'ftp' => [ 'name' => _('FTP informations'), 'attrs' => [ new CompositeAttribute ( _('Informations for ftp login'), 'ftpLoginInfo', [ new StringAttribute (_('Login'), _('Login for FTP'), 'ftpLogin'), new StringAttribute (_('Password'), _('Password for FTP'), 'ftpPassword'), new StringAttribute (_('Host'), _('Host for FTP'), 'ftpHost'), new IntAttribute (_('Port'), _('Port for FTP'), 'ftpPort', FALSE, 0, FALSE, 21), ], 'ftp://%[^@:]:%[^@:]@%[^@:]:%d', // scanf format 'ftp://%s:%s@%s:%d' // printf format ) ] ], ]; } As you can see, attribute constructor take 5 arguments being label, description, ldap name, whether this attribute is mandatory or not, default value. Some attributes takes other arguments before and after the default value. For each section you might also specify keys 'icon' with a section icon path, or 'class' with an array of css class this section should have. (Only useful class for now is 'fullwidth' which means your section will fill the whole page width) Displaying the plugin in FusionDirectory ---------------------------------------- * Put the plugin code into a directory FusionDirectory is reading (see above). * Run :shell:`fusiondirectory-configuration-manager --update-cache` as root. * Log out, log in. A tab should now shows in user edition mode, with the attributes we specified: .. image:: /_static/images/demoplugin.png