diff --git a/doc/md/Community-and-related-software.md b/doc/md/Community-and-related-software.md index e1e255fc..a9ba00c2 100644 --- a/doc/md/Community-and-related-software.md +++ b/doc/md/Community-and-related-software.md @@ -32,9 +32,27 @@ See [REST API](REST-API.md) for a list of official and community clients. - [webhooks](https://gitlab.com/flow.gunso/shaarli-webhooks) by [@flow.gunso](https://gitlab.com/flow.gunso) - Shaarli plugin that enables user-defined callback URL, i.e. webhooks, for specific Shaarli events (link saving, deletion...) -### Third-party themes +### Custom CSS -See [Theming](dev/Theming.md) for a list of community-contributed themes, and an installation guide. +- [mrjovanovic/serious-theme-shaarli](https://github.com/mrjovanovic/serious-theme-shaarli) - A serious theme for Shaarli +- [shaarli/shaarli-themes](https://github.com/shaarli/shaarli-themes) + + +### Themes + +- [AkibaTech/Shaarli Superhero Theme](https://github.com/AkibaTech/Shaarli---SuperHero-Theme) - A template/theme for Shaarli +- [alexisju/albinomouse-template](https://github.com/alexisju/albinomouse-template) - A full template for Shaarli +- [ArthurHoaro/shaarli-launch](https://github.com/ArthurHoaro/shaarli-launch) - Customizable Shaarli theme +- [dhoko/ShaarliTemplate](https://github.com/dhoko/ShaarliTemplate) - A template/theme for Shaarli +- [kalvn/shaarli-blocks](https://github.com/kalvn/shaarli-blocks) - A template/theme for Shaarli +- [kalvn/Shaarli-Material](https://github.com/kalvn/Shaarli-Material) - A theme (template) based on Google's Material Design for Shaarli, the superfast delicious clone +- [ManufacturaInd/shaarli-2004licious-theme](https://github.com/ManufacturaInd/shaarli-2004licious-theme) - A template/theme as a humble homage to the early looks of the del.icio.us site +- [xfnw/shaarli-default-dark](https://github.com/xfnw/shaarli-default-dark) - The default theme but nice and dark for your eyeballs + +### Shaarli forks + +- [misterair/Limonade](https://github.com/misterair/limonade) - A fork of (legacy) Shaarli with a new template +- [vivienhaese/shaarlitheme](https://github.com/vivienhaese/shaarlitheme) - A Shaarli fork meant to be run in an openshift instance ### Integration with other platforms diff --git a/doc/md/dev/Development.md b/doc/md/dev/Development.md index 6afbd0df..948fc451 100644 --- a/doc/md/dev/Development.md +++ b/doc/md/dev/Development.md @@ -3,14 +3,6 @@ Please read [Contributing to Shaarli](https://github.com/shaarli/Shaarli/tree/master/CONTRIBUTING.md) -## Guidelines - - -- [Unit tests](Unit-tests.md) -- Javascript linting - Shaarli uses [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript). -Run `make eslint` to check JS style. -- [GnuPG signature](GnuPG-signature.md) for tags/releases - ## Third-party libraries @@ -140,9 +132,11 @@ A [`Makefile`](https://github.com/shaarli/Shaarli/blob/master/Makefile) is avail - [Static analysis](#Static-analysis) - check that the code is compliant to PHP conventions - [Unit tests](#Unit-tests) - ensure there are no regressions introduced by new commits +- Javascript linting - Shaarli uses [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript). Run `make eslint` to check JS style. - Documentation - generate a local HTML copy of the markdown documentation -### Continuous Integration + +## Continuous Integration [Github Actions](https://github.com/shaarli/Shaarli/actions) is a Continuous Integration build server, that runs a build: @@ -159,7 +153,7 @@ Github Actions is also used to build and push [Docker](../Docker.md) images to < See [`.github/workflows/`](https://github.com/shaarli/Shaarli/tree/master/.github/workflows). -### Documentation +## Documentation [Sphinx](https://www.sphinx-doc.org/en/master/) is used to convert markdown documentation to HTML pages. The [public documentation](https://shaarli.readthedocs.io/en/master/) website is rendered and hosted by [readthedocs.org](https://readthedocs.org/). A copy of the documentation is also included in prebuilt [release archives](https://github.com/shaarli/Shaarli/releases) (`doc/html/` path in your Shaarli installation). To generate the HTML documentation locally, run `make htmldoc`. @@ -180,3 +174,1482 @@ For an overview of the available features, see: - [Code quality: Makefile to run static code checkers](https://github.com/shaarli/Shaarli/pull/124) (#124) - [Apply PHP Code Sniffer to Shaarli code base](https://github.com/shaarli/Shaarli/pull/1635) (#1635) + +## Unit tests + +Shaarli uses the [PHPUnit](https://phpunit.de/) test framework; it can be installed with [Composer](../Installation.md#from-sources), which is a dependency management tool. + +### Install composer + +You can either use: + +- a system-wide version, e.g. installed through your distro's package manager +- a local version, downloadable [here](https://getcomposer.org/download/). + +```bash +# for Debian-based distros +sudo apt install composer +``` + +### Install Shaarli dev dependencies + +After installing [required PHP extensions](../Server-configuration.md#php), install development dependencies: + +```bash +$ cd /path/to/shaarli +$ make composer_dependencies_dev +``` + +### Install and enable Xdebug to generate PHPUnit coverage reports + +[Xdebug](http://xdebug.org/docs/install) is a PHP extension which provides debugging and profiling capabilities. Install Xdebug: + +```bash +# for Debian-based distros: +sudo apt install php-xdebug + +# for ArchLinux: +pacman -S xdebug + +# then add the following line to /etc/php/php.ini +zend_extension=xdebug.so +``` + +### Run unit tests + +Ensure tests pass successfully: + +```bash +make test +# ... +# OK (36 tests, 65 assertions) +``` + +In case of failure the test suite will point you to actual errors and output a summary: + +```bash +make test +# ... +# FAILURES! +# Tests: 36, Assertions: 63, Errors: 1, Failures: 2. +``` + +By default, PHPUnit will run all suitable tests found under the `tests` directory. Each test has 3 possible outcomes: + +- `.` - success +- `F` - failure: the test was run but its results are invalid + - the code does not behave as expected + - dependencies to external elements: globals, session, cache... +- `E` - error: something went wrong and the tested code has crashed + - typos in the code, or in the test code + - dependencies to missing external elements + +If Xdebug has been installed and activated, two coverage reports will be generated: + +- a summary in the console +- a detailed HTML report with metrics for tested code + - to open it in a web browser: `firefox coverage/index.html &` + + +### Executing specific tests + +Add a [`@group`](https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.group) annotation in a test class or method comment: + +```php +/** + * Netscape bookmark import + * @group WIP + */ +class BookmarkImportTest extends PHPUnit_Framework_TestCase +{ + [...] +} +``` + +To run all tests annotated with `@group WIP`: +```bash +$ vendor/bin/phpunit --group WIP tests/ +``` + +### Running tests inside Docker containers + +Unit tests can be run inside [Docker](../Docker.md) containers. + +Test Dockerfiles are located under `tests/docker//Dockerfile`, and can be used to build Docker images to run Shaarli test suites under commonLinux environments. Dockerfiles are provided for the following environments: + +- [`alpine316`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/alpine36/Dockerfile) - [Alpine Linux 3.16](https://www.alpinelinux.org/downloads/) +- [`debian8`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/debian8/Dockerfile) - [Debian 8 Jessie](https://www.debian.org/DebianJessie) (oldoldstable) +- [`debian9`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/debian9/Dockerfile) - [Debian 9 Stretch](https://wiki.debian.org/DebianStretch) (oldstable) +- [`ubuntu16`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/ubuntu16/Dockerfile) - [Ubuntu 16.04 Xenial Xerus](http://releases.ubuntu.com/16.04/) (old LTS) + +Each image provides: +- a base Linux OS +- Shaarli PHP dependencies (OS packages) +- test PHP dependencies (OS packages) +- Composer +- Tests that run inside the container using a standard Linux user account (running tests as `root` would bypass permission checks and may hide issues) + +Build a test image: + +```bash +# build the Debian 9 Docker image +cd /path/to/shaarli/tests/docker/debian9 +docker build -t shaarli-test:debian9 . +``` + +Run unit tests in a container: + +```bash +cd /path/to/shaarli +# install/update 3rd-party test dependencies +composer install --prefer-dist +# run tests using the freshly built image +docker run -v $PWD:/shaarli shaarli-test:debian9 docker_test +# run the full test campaign +docker run -v $PWD:/shaarli shaarli-test:debian9 docker_all_tests +``` + +## GnuPG Signature + +[Gnu Privacy Guard](https://gnupg.org/) (GnuPG) is an Open Source implementation of the [Pretty Good Privacy](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP) (OpenPGP) specification. Its main purposes are digital authentication, signature and encryption. It is often used by the [FLOSS](https://en.wikipedia.org/wiki/Free_and_open-source_software) community to verify: + +- Linux package signatures: Debian [SecureApt](https://wiki.debian.org/SecureApt), ArchLinux [Master Keys](https://www.archlinux.org/master-keys/) +- [Version control](https://en.wikipedia.org/wiki/Revision_control) releases & maintainer identity + +> You MUST understand that presence of data in the keyserver (pools) in no way connotes trust. Anyone can generate a key, with any name or email address, and upload it. All security and trust comes from evaluating security at the “object level”, via PGP [Web of trust](https://en.wikipedia.org/wiki/Web_of_trust) signatures. This keyserver makes it possible to retrieve keys, looking them up via various indices, but the collection of keys in this public pool is KNOWN to contain malicious and fraudulent keys. It is the common expectation of server operators that users understand this and use software which, like all known common OpenPGP implementations, evaluates trust accordingly. This expectation is so common that it is not normally explicitly stated. + +-- Phil Pennock (author of the [SKS](https://bitbucket.org/skskeyserver/sks-keyserver/wiki/Home) key server - http://sks.spodhuis.org/) + +Trust can be gained by having your key signed by other people (and signing their key back, too :) ), for instance during [key signing parties](https://en.wikipedia.org/wiki/Key_signing_party): [Keysigning party HOWTO](http://www.cryptnet.net/fdp/crypto/keysigning_party/en/keysigning_party.html), + + +### Generate a GPG key + +- [Generating a GPG key for Git tagging](http://stackoverflow.com/a/16725717) (StackOverflow) +- [Generating a GPG key](https://help.github.com/articles/generating-a-gpg-key/) (GitHub) + +```bash +$ gpg --gen-key + +gpg (GnuPG) 2.1.6; Copyright (C) 2015 Free Software Foundation, Inc. +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Note: Use "gpg2 --full-gen-key" for a full featured key generation dialog. + +GnuPG needs to construct a user ID to identify your key. + +Real name: Marvin the Paranoid Android +Email address: marvin@h2g2.net +You selected this USER-ID: + "Marvin the Paranoid Android " + +Change (N)ame, (E)mail, or (O)kay/(Q)uit? o +We need to generate a lot of random bytes. It is a good idea to perform +some other action (type on the keyboard, move the mouse, utilize the +disks) during the prime generation; this gives the random number +generator a better chance to gain enough entropy. +``` + +At this point, you will: +- be prompted for a secure password to protect your key (the input method will depend on your Desktop Environment and configuration) +- be asked to use your machine's input devices (mouse, keyboard, etc.) to generate random entropy; this step _may take some time_ + +GnuPG will the confirm key creation: + +```bash +gpg: key A9D53A3E marked as ultimately trusted +public and secret key created and signed. + +gpg: checking the trustdb +gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model +gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u +pub rsa2048/A9D53A3E 2015-07-31 + Key fingerprint = AF2A 5381 E54B 2FD2 14C4 A9A3 0E35 ACA4 A9D5 3A3E +uid [ultimate] Marvin the Paranoid Android +sub rsa2048/8C0EACF1 2015-07-31 +``` + +Optionally, you can submit your public key to a PGP server: + +``` bash +$ gpg --keyserver pgp.mit.edu --send-keys A9D53A3E +gpg: sending key A9D53A3E to hkp server pgp.mit.edu +``` + +## Release Shaarli + +This guide assumes that you have: + +- a GPG key matching your GitHub authentication credentials/email (the email address identified by the GPG key is the same as the one in your `~/.gitconfig`) +- a GitHub fork of Shaarli +- a local clone of your Shaarli fork, with the following remotes: + - `origin` pointing to your GitHub fork + - `upstream` pointing to the main Shaarli repository +- maintainer permissions on the main Shaarli repository, to: + - push the signed tag + - create a new release +- [Composer](https://getcomposer.org/) needs to be installed +- The [venv](https://docs.python.org/3/library/venv.html) Python 3 module needs to be installed for HTML documentation generation. +- Make sure you have GNU `tar` installed (not BSD `tar`). On macOS, you can install it with `brew install gnu-tar`. + +### Release notes and `CHANGELOG.md` + +GitHub allows drafting the release notes for the upcoming release, from the [Releases](https://github.com/shaarli/Shaarli/releases) page. This way, the release note can be drafted while contributions are merged to `master`. See http://keepachangelog.com/en/0.3.0/ for changelog formatting. + +`CHANGELOG.md` should contain the same information as the release note draft for the upcoming version. Update it to: + +- add new entries (additions, fixes, etc.) +- mark the current version as released by setting its date and link +- add a new section for the future unreleased version + +```bash +## [v0.x.y](https://github.com/shaarli/Shaarli/releases/tag/v0.x.y) - UNRELEASES + +### Added + +### Changed + +### Fixed + +### Removed + +### Deprecated + +### Security + +``` + +### Update the list of Git contributors + +```bash +$ make generate_authors +$ git commit -s -m "Update AUTHORS" +``` + +### Create and merge a Pull Request + +Create a Pull Request to marge changes from your remote, into `master` in the community Shaarli repository, and have it merged. + + +### Create the release branch and update shaarli_version.php + +```bash +# fetch latest changes from master to your local copy +git checkout master +git pull upstream master + +# If releasing a new minor version, create a release branch +$ git checkout -b v0.x +# Otherwise just use the existing one +$ git checkout v0.x + +# Get the latest changes +$ git merge master + +# Check that everything went fine: +$ make test + +# Bump shaarli_version.php from dev to 0.x.0, **without the v** +$ vim shaarli_version.php +$ git add shaarli_version +$ git commit -s -m "Bump Shaarli version to v0.x.0" +$ git push upstream v0.x +``` + +### Create and push a signed tag + +Git [tags](http://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project#Tagging-Your-Releases) are used to identify specific revisions with a unique version number that follows [semantic versioning](https://semver.org/) + +```bash +# update your local copy +git checkout v0.5 +git pull upstream v0.5 + +# create a signed tag +git tag -s -m "Release v0.5.0" v0.5.0 + +# push the tag to upstream +git push --tags upstream +``` + +Here is how to verify a signed tag. [`v0.5.0`](https://github.com/shaarli/Shaarli/releases/tag/v0.5.0) is the first GPG-signed tag pushed on the Community Shaarli. Let's have a look at its signature! + +```bash +# update the list of available tags +git fetch upstream + +# get the SHA1 reference of the tag +git show-ref tags/v0.5.0 +# gives: f7762cf803f03f5caf4b8078359a63783d0090c1 refs/tags/v0.5.0 + +# verify the tag signature information +git verify-tag f7762cf803f03f5caf4b8078359a63783d0090c1 +# gpg: Signature made Thu 30 Jul 2015 11:46:34 CEST using RSA key ID 4100DF6F +# gpg: Good signature from "VirtualTam " [ultimate] +``` + +### Publish the GitHub release + +- In the `master` banch, update version badges in `README.md` to point to the newly released Shaarli version +- Update the previously drafted [release](https://github.com/shaarli/Shaarli/releases) (notes, tag) and publish it +- Profit! + + +### Generate full release zip archives + +Release archives will contain Shaarli code plus all required third-party libraries. They are useful for users who: + +- have no SSH access, no possibility to install PHP packages/server extensions, no possibility to run scripts (shared hosting) +- do not want to install build/dev dependencies on their server + + `git checkout` the appropriate branch, then: + +```bash +# checkout the appropriate branch +git checkout 0.x.y +# generate zip archives +make release_archive +``` + +This will create `shaarli-v0.x.y-full.tar`, `shaarli-v0.x.y-full.zip`. These archives need to be manually uploaded on the previously created GitHub [release](https://github.com/shaarli/Shaarli/releases). + + +### Update the `release` branch + +```bash +# checkout the 'release' branch +git checkout release +# merge changes from your newly published release branch +git merge v0.x.y +# fix eventual conflicts with git mergetool... +# run tests +make test +# push the latest branch +git push upstream release +``` + +## Plugin system + +The plugin system lets you: + +- insert content into specific places across templates. +- alter data before templates rendering. +- alter data before saving new links. + +### How to create a plugin for Shaarli + +First, chose a plugin name, such as `demo_plugin`. + +Under `plugin` folder, create a folder named with your plugin name. Then create a .meta file and a .php file in that folder. + +You should have the following tree view: + +``` +| index.php +| plugins/ +|---| demo_plugin/ +| |---| demo_plugin.meta +| |---| demo_plugin.php +``` + +### Plugin initialization + +At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the .php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter. + + _init($conf) + +This function can be used to create initial data, load default settings, etc. But also to set *plugin errors*. If the initialization function returns an array of strings, they will be understand as errors, and displayed in the header to logged in users. + +The plugin system also looks for a `description` variable in the .meta file, to be displayed in the plugin administration page. + + description="The plugin does this and that." + +### Understanding hooks + +A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution. + +These functions need to be named with this pattern: + +``` +hook__($data, $conf) +``` + +Parameters: + +- data: see [$data section](#plugins-data) +- conf: the `ConfigManager` instance. + +For example, if my plugin want to add data to the header, this function is needed: + + hook_demo_plugin_render_header + +If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header. + + +### Plugin's data + +#### Parameters + +Every hook function has a `$data` parameter. Its content differs for each hooks. + +**This parameter needs to be returned every time**, otherwise data is lost. + + return $data; + +#### Special data + +Special additional data are passed to every hook through the +`$data` parameter to give you access to additional context, and services. + +Complete list: + + * `_PAGE_` (string): if the current hook is used to render a template, its name is passed through this additional parameter. + * `_LOGGEDIN_` (bool): whether the user is logged in or not. + * `_BASE_PATH_` (string): if Shaarli instance is hosted under a subfolder, contains the subfolder path to `index.php` (e.g. `https://domain.tld/shaarli/` -> `/shaarli/`). + * `_BOOKMARK_SERVICE_` (`BookmarkServiceInterface`): bookmark service instance, for advanced usage. + +Example: + +```php +if ($data['_PAGE_'] === TemplatePage::LINKLIST && $data['LOGGEDIN'] === true) { + // Do something for logged in users when the link list is rendered +} +``` + +#### Filling templates placeholder + +Template placeholders are displayed in template in specific places. + +RainTPL displays every element contained in the placeholder's array. These element can be added by plugins. + +For example, let's add a value in the placeholder `top_placeholder` which is displayed at the top of my page: + +```php +$data['top_placeholder'][] = 'My content'; +# OR +array_push($data['top_placeholder'], 'My', 'content'); + +return $data; +``` + + +#### Data manipulation + +When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`. + +The data contained by this array can be altered before template rendering. + +For example, in linklist, it is possible to alter every title: + +```php +// mind the reference if you want $data to be altered +foreach ($data['links'] as &$value) { + // String reverse every title. + $value['title'] = strrev($value['title']); +} + +return $data; +``` + + +### Metadata + +Every plugin needs a `.meta` file, which is in fact an `.ini` file (`KEY="VALUE"`), to be listed in plugin administration. + +Each file contain two keys: + +- `description`: plugin description +- `parameters`: user parameter names, separated by a `;`. +- `parameter.`: add a text description the specified parameter. + +> Note: In PHP, `parse_ini_file()` seems to want strings to be between by quotes `"` in the ini file. + + +### Register plugin's routes + +Shaarli lets you register custom Slim routes for your plugin. + +To register a route, the plugin must include a function called `function _register_routes(): array`. + +This method must return an array of routes, each entry must contain the following keys: + + - `method`: HTTP method, `GET/POST/PUT/PATCH/DELETE` + - `route` (path): without prefix, e.g. `/up/{variable}` + It will be later prefixed by `/plugin//`. + - `callable` string, function name or FQN class's method to execute, e.g. `demo_plugin_custom_controller`. + +Callable functions or methods must have `Slim\Http\Request` and `Slim\Http\Response` parameters +and return a `Slim\Http\Response`. We recommend creating a dedicated class and extend either +`ShaarliVisitorController` or `ShaarliAdminController` to use helper functions they provide. + +A dedicated plugin template is available for rendering content: `pluginscontent.html` using `content` placeholder. + +> **Warning**: plugins are not able to use RainTPL template engine for their content due to technical restrictions. +> RainTPL does not allow to register multiple template folders, so all HTML rendering must be done within plugin +> custom controller. + +Check out the `demo_plugin` for a live example: `GET /plugin/demo_plugin/custom`. + + +### Understanding relative paths + +Because Shaarli is a self-hosted tool, an instance can either be installed at the root directory, or under a subfolder. +This means that you can *never* use absolute paths (eg `/plugins/mything/file.png`). + +If a file needs to be included in server end, use simple relative path: +`PluginManager::$PLUGINS_PATH . '/mything/template.html'`. + +If it needs to be included in front end side (e.g. an image), +the relative path must be prefixed with special data: + + * if it's a link that will need to be processed by Shaarli, use `_BASE_PATH_`: + for e.g. `$data['_BASE_PATH_'] . '/admin/tools`. + * if you want to include an asset, you need to add the root URL (base path without `/index.php`, for people using Shaarli without URL rewriting), then use `_ROOT_PATH_`: + for e.g +`$['_ROOT_PATH_'] . '/' . PluginManager::$PLUGINS_PATH . '/mything/picture.png`. + +Note that special placeholders for CSS and JS files (respectively `css_files` and `js_files`) are already prefixed +with the root path in template files. + + +### It's not working! + +Use `demo_plugin` as a functional example. It covers most of the plugin system features. + +If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new). + + +### Hooks + +| Hooks | Description | +| ------------- |:-------------:| +| [render_header](#render-header) | Allow plugin to add content in page headers. | +| [render_includes](#render-includes) | Allow plugin to include their own CSS files. | +| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. | +| [render_linklist](#render-linklist) | It allows to add content at the begining and end of the page, after every link displayed and to alter link data. | +| [render_editlink](#render-editlink) | Allow to add fields in the form, or display elements. | +| [render_tools](#render-tools) | Allow to add content at the end of the page. | +| [render_picwall](#render-picwall) | Allow to add content at the top and bottom of the page. | +| [render_tagcloud](#render-tagcloud) | Allow to add content at the top and bottom of the page, and after all tags. | +| [render_taglist](#render-taglist) | Allow to add content at the top and bottom of the page, and after all tags. | +| [render_daily](#render-daily) | Allow to add content at the top and bottom of the page, the bottom of each link and to alter data. | +| [render_feed](#render-feed) | Allow to do add tags in RSS and ATOM feeds. | +| [save_link](#save-link) | Allow to alter the link being saved in the datastore. | +| [delete_link](#delete-link) | Allow to do an action before a link is deleted from the datastore. | +| [save_plugin_parameters](#save-plugin-parameters) | Allow to manipulate plugin parameters before they're saved. | +| [filter_search_entry](#filter-search-entry) | Add custom filters to Shaarli search engine | + + +#### render_header + +Triggered on every page - allows plugins to add content in page headers. + + +##### Data + +`$data` is an array containing: + + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `buttons_toolbar`: after the list of buttons in the header. + +![buttons_toolbar_example](http://i.imgur.com/ssJUOrt.png) + +- `fields_toolbar`: after search fields in the header. + +> Note: This will only be called in linklist. + +![fields_toolbar_example](http://i.imgur.com/3GMifI2.png) + + +#### render_includes + +Triggered on every page - allows plugins to include their own CSS files. + + +##### data + +`$data` is an array containing: + + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `css_files`: called after loading default CSS. + +> Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`. + + +#### render_footer + +Triggered on every page. + +Allow plugin to add content in page footer and include their own JS files. + + +##### data + +`$data` is an array containing: + + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `text`: called after the end of the footer text. +- `endofpage`: called at the end of the page. + +![text_example](http://i.imgur.com/L5S2YEH.png) + +- `js_files`: called at the end of the page, to include custom JS scripts. + +> Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`. + + +#### render_linklist + +Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.). + +It allows to add content at the begining and end of the page, after every link displayed and to alter link data. + + +##### data + +`$data` is an array containing: + + - All templates data, including links. + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `action_plugin`: next to the button "private only" at the top and bottom of the page. + +![action_plugin_example](http://i.imgur.com/Q12PWg0.png) + +- `link_plugin`: for every link, between permalink and link URL. + +![link_plugin_example](http://i.imgur.com/3oDPhWx.png) + +- `plugin_start_zone`: before displaying the template content. + +![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png) + +- `plugin_end_zone`: after displaying the template content. + +![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png) + + +#### render_editlink + +Triggered when the link edition form is displayed. + +Allow to add fields in the form, or display elements. + + +##### data + +`$data` is an array containing: + + - All templates data. + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `edit_link_plugin`: after tags field. + +![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png) + + +#### render_tools + +Triggered when the "tools" page is displayed. + +Allow to add content at the end of the page. + + +##### data + +`$data` is an array containing: + + - All templates data. + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `tools_plugin`: at the end of the page. + +![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png) + + +#### render_picwall + +Triggered when picwall is displayed. + +Allow to add content at the top and bottom of the page. + + +##### data + +`$data` is an array containing: + + - All templates data. + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `plugin_start_zone`: before displaying the template content. +- `plugin_end_zone`: after displaying the template content. + +![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png) + + +#### render_tagcloud + +Triggered when tagcloud is displayed. + +Allow to add content at the top and bottom of the page. + + +##### data + +`$data` is an array containing: + + - All templates data. + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `plugin_start_zone`: before displaying the template content. +- `plugin_end_zone`: after displaying the template content. + +For each tag, the following placeholder can be used: + +- `tag_plugin`: after each tag + +![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png) + + +#### render_taglist + +Triggered when taglist is displayed - allows to add content at the top and bottom of the page. + + +##### data + +`$data` is an array containing: + + - All templates data. + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `plugin_start_zone`: before displaying the template content. +- `plugin_end_zone`: after displaying the template content. + +For each tag, the following placeholder can be used: + +- `tag_plugin`: after each tag + + +#### render_daily + +Triggered when tagcloud is displayed. + +Allow to add content at the top and bottom of the page, the bottom of each link and to alter data. + + +##### data + +`$data` is an array containing: + + - All templates data, including links. + - [Special data](#special-data) + + +##### Template placeholders + +Items can be displayed in templates by adding an entry in `$data['']` array. + +List of placeholders: + +- `link_plugin`: used at bottom of each link. + +![link_plugin_example](http://i.imgur.com/hzhMfSZ.png) + +- `plugin_start_zone`: before displaying the template content. +- `plugin_end_zone`: after displaying the template content. + + +#### render_feed + +Triggered when the ATOM or RSS feed is displayed. + +Allow to add tags in the feed, either in the header or for each items. Items (links) can also be altered before being rendered. + + +##### data + +`$data` is an array containing: + + - All templates data, including links. + - [Special data](#special-data) + + +##### Template placeholders + +Tags can be added in feeds by adding an entry in `$data['']` array. + +List of placeholders: + +- `feed_plugins_header`: used as a header tag in the feed. + +For each links: + +- `feed_plugins`: additional tag for every link entry. + + +#### save_link + +Triggered when a link is save (new link or edit). + +Allow to alter the link being saved in the datastore. + + +##### data + +`$data` is an array containing the link being saved: + +- id +- title +- url +- shorturl +- description +- private +- tags +- created +- updated + +Also [special data](#special-data). + + +#### delete_link + +Triggered when a link is deleted. + +Allow to execute any action before the link is actually removed from the datastore + + +##### data + +`$data` is an array containing the link being deleted: + +- id +- title +- url +- shorturl +- description +- private +- tags +- created +- updated + +Also [special data](#special-data). + + +#### save_plugin_parameters + +Triggered when the plugin parameters are saved from the plugin administration page. + +Plugins can perform an action every times their settings are updated. +For example it is used to update the CSS file of the `default_colors` plugins. + + +##### data + +`$data` input contains the `$_POST` array. + +So if the plugin has a parameter called `MYPLUGIN_PARAMETER`, +the array will contain an entry with `MYPLUGIN_PARAMETER` as a key. + +Also [special data](#special-data). + + +#### filter_search_entry + +Triggered for *every* bookmark when Shaarli's BookmarkService method `search()` is used. +Any custom filter can be added to filter out bookmarks from search results. + +The hook **must** return either: + - `true` to keep bookmark entry in search result set + - `false` to discard bookmark entry in result set + +> Note: custom filters are called *before* default filters are applied. + + +##### Parameters + +- `Shaarli\Bookmark\Bookmark` object: entry to evaluate +- $context `array`: additional information provided depending on what search is currently used, +the user request, etc. + + +## Guide for template designers + +### Plugin administration + +Your theme must include a plugin administration page: `pluginsadmin.html`. + +> Note: repo's template link needs to be added when the PR is merged. + +Use the default one as an example. + +Aside from classic RainTPL loops, plugins order is handle by JavaScript. You can just include `plugin_admin.js`, only if: + +- you're using a table. +- you call orderUp() and orderUp() onclick on arrows. +- you add data-line and data-order to your rows. + +Otherwise, you can use your own JS as long as this field is send by the form: + + + + +### Placeholder system + +In order to make plugins work with every custom themes, you need to add variable placeholder in your templates. + +It's a RainTPL loop like this: + + {loop="$plugin_variable"} + {$value} + {/loop} + +You should enable `demo_plugin` for testing purpose, since it uses every placeholder available. + + +### List of placeholders + +**page.header.html** + +At the end of the menu: + + {loop="$plugins_header.buttons_toolbar"} + {$value} + {/loop} + +At the end of file, before clearing floating blocks: + + {if="!empty($plugin_errors) && $is_logged_in"} +
    + {loop="plugin_errors"} +
  • {$value}
  • + {/loop} +
+ {/if} + +**includes.html** + +At the end of the file: + +```html +{loop="$plugins_includes.css_files"} + +{/loop} +``` + +**page.footer.html** + +At the end of your footer notes: + +```html +{loop="$plugins_footer.text"} + {$value} +{/loop} +``` + +At the end of file: + +```html +{loop="$plugins_footer.js_files"} + +{/loop} +``` + +**linklist.html** + +After search fields: + +```html +{loop="$plugins_header.fields_toolbar"} + {$value} +{/loop} +``` + +Before displaying the link list (after paging): + +```html +{loop="$plugin_start_zone"} + {$value} +{/loop} +``` + +For every links (icons): + +```html +{loop="$value.link_plugin"} + {$value} +{/loop} +``` + +Before end paging: + +```html +{loop="$plugin_end_zone"} + {$value} +{/loop} +``` + +**linklist.paging.html** + +After the "private only" icon: + +```html +{loop="$action_plugin"} + {$value} +{/loop} +``` + +**editlink.html** + +After tags field: + +```html +{loop="$edit_link_plugin"} + {$value} +{/loop} +``` + +**tools.html** + +After the last tool: + +```html +{loop="$tools_plugin"} + {$value} +{/loop} +``` + +**picwall.html** + +Top: + +```html +
+ {loop="$plugin_start_zone"} + {$value} + {/loop} +
+``` + +Bottom: + +```html +
+ {loop="$plugin_end_zone"} + {$value} + {/loop} +
+``` + +**tagcloud.html** + +Top: + +```html +
+ {loop="$plugin_start_zone"} + {$value} + {/loop} +
+``` + +Bottom: + +```html +
+ {loop="$plugin_end_zone"} + {$value} + {/loop} +
+``` + +**daily.html** + +Top: + +```html +
+ {loop="$plugin_start_zone"} + {$value} + {/loop} +
+``` + +After every link: + +```html +
+ {loop="$link.link_plugin"} + {$value} + {/loop} +
+``` + +Bottom: + +```html +
+ {loop="$plugin_end_zone"} + {$value} + {/loop} +
+``` + +**feed.atom.xml** and **feed.rss.xml**: + +In headers tags section: +```xml +{loop="$feed_plugins_header"} + {$value} +{/loop} +``` + +After each entry: +```xml +{loop="$value.feed_plugins"} + {$value} +{/loop} +``` + +## Theming + +There are two ways of customizing how Shaarli looks: + +1. by using a custom CSS to override Shaarli's CSS +2. by using a full theme that provides its own RainTPL templates, CSS and Javascript resources + +### Custom CSS + +Shaarli's appearance can be modified by adding CSS rules to: + +- Shaarli < `v0.9.0`: `inc/user.css` +- Shaarli >= `v0.9.0`: `data/user.css` + +This file allows overriding rules defined in the template CSS files (only add changed rules), or define a whole new theme. + +**Note**: Do not edit `tpl/default/css/shaarli.css`! Your changes would be overridden when updating Shaarli. + +### Themes + +Installation: + +- find a theme you'd like to install +- copy or clone the theme folder under `tpl/` +- enable the theme: + - Shaarli < `v0.9.0`: edit `data/config.json.php` and set the value of `raintpl_tpl` to the new theme name: + `"raintpl_tpl": "tpl\/my-template\/"` + - Shaarli >= `v0.9.0`: select the theme through the _Tools_ page + +#### Example installation: AlbinoMouse theme + +With the following configuration: + +- Apache 2 / PHP 5.6 +- user sites are enabled, e.g. `/home/user/public_html/somedir` is served as `http://localhost/~user/somedir` +- `http` is the name of the Apache user + +```bash +$ cd ~/public_html + +# clone repositories +$ git clone https://github.com/shaarli/Shaarli.git shaarli +$ pushd shaarli/tpl +$ git clone https://github.com/alexisju/albinomouse-template.git +$ popd + +# set access rights for Apache +$ chgrp -R http shaarli +$ chmod g+rwx shaarli shaarli/cache shaarli/data shaarli/pagecache shaarli/tmp +``` + +Get config written: +- go to the freshly installed site +- fill the install form +- log in to Shaarli + +Edit Shaarli's [configuration](../Shaarli-configuration.md): +```bash +# the file should be owned by Apache, thus not writeable => sudo +$ sudo sed -i s=tpl=tpl/albinomouse-template=g shaarli/data/config.php +``` + +## Translations + +Shaarli supports [gettext](https://www.gnu.org/software/gettext/manual/gettext.html) translations since `>= v0.9.2`. + +Note that only the `default` theme supports translations. + +We encourage the community to contribute to Shaarli translations, either by improving existing translations or submitting a new language. + +Contributing to the translation does not require software development knowledge. + +Please submit a pull request with the `.po` file updated/created. Note that the compiled file (`.mo`) is not stored on the repository, and is generated during the release process. + +Install [Poedit](https://poedit.net/) (used to extract strings to translate from the PHP source code, and generate `.po` files). + +Due to the usage of a template engine, it's important to generate PHP cache files to extract every translatable string. You can either use [this script](https://gist.github.com/ArthurHoaro/5d0323f758ab2401ef444a53f54e9a07) (recommended) or visit every template page in your browser to generate cache files, while logged in. Here is a list : + +``` +http:/// +http:///login +http:///daily +http:///tags/cloud +http:///tags/list +http:///picture-wall +http:///?nonope +http:///admin/add-shaare +http:///admin/password +http:///admin/tags +http:///admin/configure +http:///admin/tools +http:///admin/shaare +http:///admin/export +http:///admin/import +http:///admin/plugins +``` + + +### Improve existing translations + +- In Poedit, click on "Edit a Translation +- Open `inc/languages//LC_MESSAGES/shaarli.po` under Shaarli's directory +- The existing list of translatable strings should load +- Click on the "Update" button. +- Start editing translations. + +![poedit-screenshot](images/poedit-1.jpg) + +Save when you're done, then you can submit a pull request containing the updated `shaarli.po`. + + +### Add a new language + +- In Poedit select "Create New Translation" +- Open `inc/languages//LC_MESSAGES/shaarli.po` under Shaarli's directory +- Select the language you want to create. +- Click on `File > Save as...`, save your file in `/inc/language//LC_MESSAGES/shaarli.po` (`` here should be the language code respecting the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-2) format in lowercase - e.g. `de` for German) +- Click on the "Update" button +- Start editing translations. + +Save when you're done, then you can submit a pull request containing the new `shaarli.po`. + + +### Theme translations + +[Theme](#theming) translation extensions are loaded automatically if they're present. + +As a theme developer, all you have to do is to add the `.po` and `.mo` compiled file like this: + +``` +tpl//language//LC_MESSAGES/.po +tpl//language//LC_MESSAGES/.mo +``` + +Where `` is the ISO 3166-1 alpha-2 language code. + +Read the following section "Extend Shaarli's translation" to learn how to generate those files. + + +### Extend Shaarli's translation + +If you're writing a custom theme, or a non official plugin, you might want to use the translation system, +but you won't be able to able to override Shaarli's translation. + +However, you can add your own translation domain which extends the main translation list. + +> Note that you can find a live example of translation extension in the `demo_plugin`. + +First, create your translation files tree directory: + +``` +/languages//LC_MESSAGES/ +``` + +Your `.po` files must be named like your domain. E.g. if your translation domain is `my_theme`, then your file will be +`my_theme.po`. + +Users have to register your extension in their configuration with the parameter +`translation.extensions.: `. + +Example: + +```php +if (! $conf->exists('translation.extensions.my_theme')) { + $conf->set('translation.extensions.my_theme', '/languages/'); + $conf->write(true); +} +``` + +> Note that the page needs to be reloaded after the registration. + +It is then recommended to create a custom translation function which will call the `t()` function with your domain. +For example : + +```php +function my_theme_t($text, $nText = '', $nb = 1) +{ + return t($text, $nText, $nb, 'my_theme'); // the last parameter is your translation domain. +} +``` + +All strings which can be translated should be processed through your function: + +```php +my_theme_t('Comment'); +my_theme_t('Comment', 'Comments', 2); +``` + +Or in templates: + +```php +{'Comment'|my_theme_t} +{function="my_theme_t('Comment', 'Comments', 2)"} +``` + +> Note than in template, you need to visit your page at least once to generate a cache file. + +When you're done, open Poedit and load translation strings from sources: + + 1. `File > New` + 2. Choose your language + 3. Save your `PO` file in `/languages//LC_MESSAGES/my_theme.po`. + 4. Go to `Catalog > Properties...` + 5. Fill the `Translation Properties` tab + 6. Add your source path in the `Sources Paths` tab + 7. In the `Sources Keywords` tab uncheck "Also use default keywords" and add the following lines: + +``` +my_theme_t +my_theme_t:1,2 +``` + +Click on the "Update" button and you're free to start your translations! + +## Versioning + +If you're maintaining a 3rd party tool for Shaarli (theme, plugin, etc.), It's important to understand how Shaarli branches work ensure your tool stays compatible. + + +### `master` branch + +The `master` branch is the development branch. Any new change MUST go through this branch using Pull Requests. + +Remarks: + +- This branch shouldn't be used for production as it isn't necessary stable. +- 3rd party aren't required to be compatible with the latest changes. +- Official plugins, themes and libraries (contained within Shaarli organization repos) must be compatible with the master branch. + + +### `v0.x` branch + +The `v0.x` branch points to the latest `v0.x.y` release. + +If a major bug affects the original `v0.x.0` release, we may [backport](https://en.wikipedia.org/wiki/Backporting) a fix for this bug from master, to the `v0.x` branch, and create a new bugfix release (eg. `v0.x.1`) from this branch. + +This allows users of the original release to upgrade to the fixed version, without having to upgrade to a completely new minor/major release. + + +## `release` branch + +This branch point the latest release. It recommended to use it to get the latest tested changes. + + +### Releases + +For every release, we manually generate a .zip file which contains all Shaarli dependencies, making Shaarli's installation only one step. + + +### Advices on 3rd party git repos workflow + +Any time a new Shaarli release is published, you should publish a new release of your repo if the changes affected you since the latest release (take a look at the [changelog](https://github.com/shaarli/Shaarli/releases) (*Draft* means not released yet) and the commit log (like [`tpl` folder](https://github.com/shaarli/Shaarli/commits/master/tpl/default) for themes)). You can either: + + - use the Shaarli version number, with your repo version. For example, if Shaarli `v0.8.3` is released, publish a `v0.8.3-1` release, where `v0.8.3` states Shaarli compatibility and `-1` is your own version digit for the current Shaarli version. + - use your own versioning scheme, and state Shaarli compatibility in the release description. + +Using this, any user will be able to pick the release matching his own Shaarli version. + +### Major bugfix backport releases + +To be able to support backported fixes, it recommended to use our workflow: + +```bash +# In master, fix the major bug +git commit -m "Katastrophe" +git push origin master +# Get your commit hash +git log --format="%H" -n 1 +# Create a new branch from your latest release, let's say v0.8.2-1 (the tag name) +git checkout -b katastrophe v0.8.2-1 +# Backport the fix commit to your brand new branch +git cherry-pick +git push origin katastrophe +# Then you just have to make a new release from the `katastrophe` branch tagged `v0.8.3-1` +``` diff --git a/doc/md/dev/GnuPG-signature.md b/doc/md/dev/GnuPG-signature.md deleted file mode 100644 index 03e331e6..00000000 --- a/doc/md/dev/GnuPG-signature.md +++ /dev/null @@ -1,70 +0,0 @@ -## Introduction -### PGP and GPG -[Gnu Privacy Guard](https://gnupg.org/) (GnuPG) is an Open Source implementation of the [Pretty Good Privacy](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP) (OpenPGP) specification. Its main purposes are digital authentication, signature and encryption. It is often used by the [FLOSS](https://en.wikipedia.org/wiki/Free_and_open-source_software) community to verify: - -- Linux package signatures: Debian [SecureApt](https://wiki.debian.org/SecureApt), ArchLinux [Master Keys](https://www.archlinux.org/master-keys/) -- [Version control](https://en.wikipedia.org/wiki/Revision_control) releases & maintainer identity - -> You MUST understand that presence of data in the keyserver (pools) in no way connotes trust. Anyone can generate a key, with any name or email address, and upload it. All security and trust comes from evaluating security at the “object level”, via PGP [Web of trust](https://en.wikipedia.org/wiki/Web_of_trust) signatures. This keyserver makes it possible to retrieve keys, looking them up via various indices, but the collection of keys in this public pool is KNOWN to contain malicious and fraudulent keys. It is the common expectation of server operators that users understand this and use software which, like all known common OpenPGP implementations, evaluates trust accordingly. This expectation is so common that it is not normally explicitly stated. - --- Phil Pennock (author of the [SKS](https://bitbucket.org/skskeyserver/sks-keyserver/wiki/Home) key server - http://sks.spodhuis.org/) - -Trust can be gained by having your key signed by other people (and signing their key back, too :) ), for instance during [key signing parties](https://en.wikipedia.org/wiki/Key_signing_party): [Keysigning party HOWTO](http://www.cryptnet.net/fdp/crypto/keysigning_party/en/keysigning_party.html), - - -## Generate a GPG key -- [Generating a GPG key for Git tagging](http://stackoverflow.com/a/16725717) (StackOverflow) -- [Generating a GPG key](https://help.github.com/articles/generating-a-gpg-key/) (GitHub) - -### gpg - provide identity information -```bash -$ gpg --gen-key - -gpg (GnuPG) 2.1.6; Copyright (C) 2015 Free Software Foundation, Inc. -This is free software: you are free to change and redistribute it. -There is NO WARRANTY, to the extent permitted by law. - -Note: Use "gpg2 --full-gen-key" for a full featured key generation dialog. - -GnuPG needs to construct a user ID to identify your key. - -Real name: Marvin the Paranoid Android -Email address: marvin@h2g2.net -You selected this USER-ID: - "Marvin the Paranoid Android " - -Change (N)ame, (E)mail, or (O)kay/(Q)uit? o -We need to generate a lot of random bytes. It is a good idea to perform -some other action (type on the keyboard, move the mouse, utilize the -disks) during the prime generation; this gives the random number -generator a better chance to gain enough entropy. -``` - -### gpg - entropy interlude -At this point, you will: -- be prompted for a secure password to protect your key (the input method will depend on your Desktop Environment and configuration) -- be asked to use your machine's input devices (mouse, keyboard, etc.) to generate random entropy; this step _may take some time_ - -### gpg - key creation confirmation -```bash -gpg: key A9D53A3E marked as ultimately trusted -public and secret key created and signed. - -gpg: checking the trustdb -gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model -gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u -pub rsa2048/A9D53A3E 2015-07-31 - Key fingerprint = AF2A 5381 E54B 2FD2 14C4 A9A3 0E35 ACA4 A9D5 3A3E -uid [ultimate] Marvin the Paranoid Android -sub rsa2048/8C0EACF1 2015-07-31 -``` - -### gpg - submit your public key to a PGP server (Optional) -``` bash -$ gpg --keyserver pgp.mit.edu --send-keys A9D53A3E -gpg: sending key A9D53A3E to hkp server pgp.mit.edu -``` - -## Create and push a GPG-signed tag - -See [Release Shaarli](Release-Shaarli.md). diff --git a/doc/md/dev/Plugin-system.md b/doc/md/dev/Plugin-system.md deleted file mode 100644 index 8fda0817..00000000 --- a/doc/md/dev/Plugin-system.md +++ /dev/null @@ -1,819 +0,0 @@ -# Plugin system - -## Developer API - -### What can I do with plugins? - -The plugin system lets you: - -- insert content into specific places across templates. -- alter data before templates rendering. -- alter data before saving new links. - - -### How can I create a plugin for Shaarli? - -First, chose a plugin name, such as `demo_plugin`. - -Under `plugin` folder, create a folder named with your plugin name. Then create a .meta file and a .php file in that folder. - -You should have the following tree view: - -``` -| index.php -| plugins/ -|---| demo_plugin/ -| |---| demo_plugin.meta -| |---| demo_plugin.php -``` - -### Plugin initialization - -At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the .php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter. - - _init($conf) - -This function can be used to create initial data, load default settings, etc. But also to set *plugin errors*. If the initialization function returns an array of strings, they will be understand as errors, and displayed in the header to logged in users. - -The plugin system also looks for a `description` variable in the .meta file, to be displayed in the plugin administration page. - - description="The plugin does this and that." - -### Understanding hooks - -A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution. - -These functions need to be named with this pattern: - -``` -hook__($data, $conf) -``` - -Parameters: - -- data: see [$data section](https://shaarli.readthedocs.io/en/master/Plugin-System/#plugins-data) -- conf: the `ConfigManager` instance. - -For example, if my plugin want to add data to the header, this function is needed: - - hook_demo_plugin_render_header - -If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header. - - -### Plugin's data - -#### Parameters - -Every hook function has a `$data` parameter. Its content differs for each hooks. - -**This parameter needs to be returned every time**, otherwise data is lost. - - return $data; - -#### Special data - -Special additional data are passed to every hook through the -`$data` parameter to give you access to additional context, and services. - -Complete list: - - * `_PAGE_` (string): if the current hook is used to render a template, its name is passed through this additional parameter. - * `_LOGGEDIN_` (bool): whether the user is logged in or not. - * `_BASE_PATH_` (string): if Shaarli instance is hosted under a subfolder, contains the subfolder path to `index.php` (e.g. `https://domain.tld/shaarli/` -> `/shaarli/`). - * `_BOOKMARK_SERVICE_` (`BookmarkServiceInterface`): bookmark service instance, for advanced usage. - -Example: - -```php -if ($data['_PAGE_'] === TemplatePage::LINKLIST && $data['LOGGEDIN'] === true) { - // Do something for logged in users when the link list is rendered -} -``` - -#### Filling templates placeholder - -Template placeholders are displayed in template in specific places. - -RainTPL displays every element contained in the placeholder's array. These element can be added by plugins. - -For example, let's add a value in the placeholder `top_placeholder` which is displayed at the top of my page: - -```php -$data['top_placeholder'][] = 'My content'; -# OR -array_push($data['top_placeholder'], 'My', 'content'); - -return $data; -``` - - -#### Data manipulation - -When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`. - -The data contained by this array can be altered before template rendering. - -For example, in linklist, it is possible to alter every title: - -```php -// mind the reference if you want $data to be altered -foreach ($data['links'] as &$value) { - // String reverse every title. - $value['title'] = strrev($value['title']); -} - -return $data; -``` - -### Metadata - -Every plugin needs a `.meta` file, which is in fact an `.ini` file (`KEY="VALUE"`), to be listed in plugin administration. - -Each file contain two keys: - -- `description`: plugin description -- `parameters`: user parameter names, separated by a `;`. -- `parameter.`: add a text description the specified parameter. - -> Note: In PHP, `parse_ini_file()` seems to want strings to be between by quotes `"` in the ini file. - -### Register plugin's routes - -Shaarli lets you register custom Slim routes for your plugin. - -To register a route, the plugin must include a function called `function _register_routes(): array`. - -This method must return an array of routes, each entry must contain the following keys: - - - `method`: HTTP method, `GET/POST/PUT/PATCH/DELETE` - - `route` (path): without prefix, e.g. `/up/{variable}` - It will be later prefixed by `/plugin//`. - - `callable` string, function name or FQN class's method to execute, e.g. `demo_plugin_custom_controller`. - -Callable functions or methods must have `Slim\Http\Request` and `Slim\Http\Response` parameters -and return a `Slim\Http\Response`. We recommend creating a dedicated class and extend either -`ShaarliVisitorController` or `ShaarliAdminController` to use helper functions they provide. - -A dedicated plugin template is available for rendering content: `pluginscontent.html` using `content` placeholder. - -> **Warning**: plugins are not able to use RainTPL template engine for their content due to technical restrictions. -> RainTPL does not allow to register multiple template folders, so all HTML rendering must be done within plugin -> custom controller. - -Check out the `demo_plugin` for a live example: `GET /plugin/demo_plugin/custom`. - -### Understanding relative paths - -Because Shaarli is a self-hosted tool, an instance can either be installed at the root directory, or under a subfolder. -This means that you can *never* use absolute paths (eg `/plugins/mything/file.png`). - -If a file needs to be included in server end, use simple relative path: -`PluginManager::$PLUGINS_PATH . '/mything/template.html'`. - -If it needs to be included in front end side (e.g. an image), -the relative path must be prefixed with special data: - - * if it's a link that will need to be processed by Shaarli, use `_BASE_PATH_`: - for e.g. `$data['_BASE_PATH_'] . '/admin/tools`. - * if you want to include an asset, you need to add the root URL (base path without `/index.php`, for people using Shaarli without URL rewriting), then use `_ROOT_PATH_`: - for e.g -`$['_ROOT_PATH_'] . '/' . PluginManager::$PLUGINS_PATH . '/mything/picture.png`. - -Note that special placeholders for CSS and JS files (respectively `css_files` and `js_files`) are already prefixed -with the root path in template files. - -### It's not working! - -Use `demo_plugin` as a functional example. It covers most of the plugin system features. - -If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new). - - -### Hooks - -| Hooks | Description | -| ------------- |:-------------:| -| [render_header](#render-header) | Allow plugin to add content in page headers. | -| [render_includes](#render-includes) | Allow plugin to include their own CSS files. | -| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. | -| [render_linklist](#render-linklist) | It allows to add content at the begining and end of the page, after every link displayed and to alter link data. | -| [render_editlink](#render-editlink) | Allow to add fields in the form, or display elements. | -| [render_tools](#render-tools) | Allow to add content at the end of the page. | -| [render_picwall](#render-picwall) | Allow to add content at the top and bottom of the page. | -| [render_tagcloud](#render-tagcloud) | Allow to add content at the top and bottom of the page, and after all tags. | -| [render_taglist](#render-taglist) | Allow to add content at the top and bottom of the page, and after all tags. | -| [render_daily](#render-daily) | Allow to add content at the top and bottom of the page, the bottom of each link and to alter data. | -| [render_feed](#render-feed) | Allow to do add tags in RSS and ATOM feeds. | -| [save_link](#save-link) | Allow to alter the link being saved in the datastore. | -| [delete_link](#delete-link) | Allow to do an action before a link is deleted from the datastore. | -| [save_plugin_parameters](#save-plugin-parameters) | Allow to manipulate plugin parameters before they're saved. | -| [filter_search_entry](#filter-search-entry) | Add custom filters to Shaarli search engine | - - -#### render_header - -Triggered on every page - allows plugins to add content in page headers. - - -##### Data - -`$data` is an array containing: - - - [Special data](#special-data) - -##### Template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `buttons_toolbar`: after the list of buttons in the header. - -![buttons_toolbar_example](http://i.imgur.com/ssJUOrt.png) - -- `fields_toolbar`: after search fields in the header. - -> Note: This will only be called in linklist. - -![fields_toolbar_example](http://i.imgur.com/3GMifI2.png) - - -#### render_includes - -Triggered on every page - allows plugins to include their own CSS files. - -##### data - -`$data` is an array containing: - - - [Special data](#special-data) - -##### Template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `css_files`: called after loading default CSS. - -> Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`. - - -#### render_footer - -Triggered on every page. - -Allow plugin to add content in page footer and include their own JS files. - -##### data - -`$data` is an array containing: - - - [Special data](#special-data) - -##### Template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `text`: called after the end of the footer text. -- `endofpage`: called at the end of the page. - -![text_example](http://i.imgur.com/L5S2YEH.png) - -- `js_files`: called at the end of the page, to include custom JS scripts. - -> Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`. - - -#### render_linklist - -Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.). - -It allows to add content at the begining and end of the page, after every link displayed and to alter link data. - -##### data - -`$data` is an array containing: - - - All templates data, including links. - - [Special data](#special-data) - -##### template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `action_plugin`: next to the button "private only" at the top and bottom of the page. - -![action_plugin_example](http://i.imgur.com/Q12PWg0.png) - -- `link_plugin`: for every link, between permalink and link URL. - -![link_plugin_example](http://i.imgur.com/3oDPhWx.png) - -- `plugin_start_zone`: before displaying the template content. - -![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png) - -- `plugin_end_zone`: after displaying the template content. - -![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png) - - -#### render_editlink - -Triggered when the link edition form is displayed. - -Allow to add fields in the form, or display elements. - -##### data - -`$data` is an array containing: - - - All templates data. - - [Special data](#special-data) - -##### template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `edit_link_plugin`: after tags field. - -![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png) - - -#### render_tools - -Triggered when the "tools" page is displayed. - -Allow to add content at the end of the page. - -##### data - -`$data` is an array containing: - - - All templates data. - - [Special data](#special-data) - -##### template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `tools_plugin`: at the end of the page. - -![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png) - - -#### render_picwall - -Triggered when picwall is displayed. - -Allow to add content at the top and bottom of the page. - -##### data - -`$data` is an array containing: - - - All templates data. - - [Special data](#special-data) - -##### template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `plugin_start_zone`: before displaying the template content. -- `plugin_end_zone`: after displaying the template content. - -![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png) - - -#### render_tagcloud - -Triggered when tagcloud is displayed. - -Allow to add content at the top and bottom of the page. - -##### data - -`$data` is an array containing: - - - All templates data. - - [Special data](#special-data) - -##### Template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `plugin_start_zone`: before displaying the template content. -- `plugin_end_zone`: after displaying the template content. - -For each tag, the following placeholder can be used: - -- `tag_plugin`: after each tag - -![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png) - - -#### render_taglist - -Triggered when taglist is displayed - allows to add content at the top and bottom of the page. - -##### data - -`$data` is an array containing: - - - All templates data. - - [Special data](#special-data) - -##### Template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `plugin_start_zone`: before displaying the template content. -- `plugin_end_zone`: after displaying the template content. - -For each tag, the following placeholder can be used: - -- `tag_plugin`: after each tag - -#### render_daily - -Triggered when tagcloud is displayed. - -Allow to add content at the top and bottom of the page, the bottom of each link and to alter data. - - -##### data - -`$data` is an array containing: - - - All templates data, including links. - - [Special data](#special-data) - -##### Template placeholders - -Items can be displayed in templates by adding an entry in `$data['']` array. - -List of placeholders: - -- `link_plugin`: used at bottom of each link. - -![link_plugin_example](http://i.imgur.com/hzhMfSZ.png) - -- `plugin_start_zone`: before displaying the template content. -- `plugin_end_zone`: after displaying the template content. - - -#### render_feed - -Triggered when the ATOM or RSS feed is displayed. - -Allow to add tags in the feed, either in the header or for each items. Items (links) can also be altered before being rendered. - -##### data - -`$data` is an array containing: - - - All templates data, including links. - - [Special data](#special-data) - -##### Template placeholders - -Tags can be added in feeds by adding an entry in `$data['']` array. - -List of placeholders: - -- `feed_plugins_header`: used as a header tag in the feed. - -For each links: - -- `feed_plugins`: additional tag for every link entry. - - -#### save_link - -Triggered when a link is save (new link or edit). - -Allow to alter the link being saved in the datastore. - -##### data - -`$data` is an array containing the link being saved: - -- id -- title -- url -- shorturl -- description -- private -- tags -- created -- updated - -Also [special data](#special-data). - - -#### delete_link - -Triggered when a link is deleted. - -Allow to execute any action before the link is actually removed from the datastore - -##### data - -`$data` is an array containing the link being deleted: - -- id -- title -- url -- shorturl -- description -- private -- tags -- created -- updated - -Also [special data](#special-data). - -#### save_plugin_parameters - -Triggered when the plugin parameters are saved from the plugin administration page. - -Plugins can perform an action every times their settings are updated. -For example it is used to update the CSS file of the `default_colors` plugins. - -##### data - -`$data` input contains the `$_POST` array. - -So if the plugin has a parameter called `MYPLUGIN_PARAMETER`, -the array will contain an entry with `MYPLUGIN_PARAMETER` as a key. - -Also [special data](#special-data). - -#### filter_search_entry - -Triggered for *every* bookmark when Shaarli's BookmarkService method `search()` is used. -Any custom filter can be added to filter out bookmarks from search results. - -The hook **must** return either: - - `true` to keep bookmark entry in search result set - - `false` to discard bookmark entry in result set - -> Note: custom filters are called *before* default filters are applied. - -##### Parameters - -- `Shaarli\Bookmark\Bookmark` object: entry to evaluate -- $context `array`: additional information provided depending on what search is currently used, -the user request, etc. - -## Guide for template designers - -### Plugin administration - -Your theme must include a plugin administration page: `pluginsadmin.html`. - -> Note: repo's template link needs to be added when the PR is merged. - -Use the default one as an example. - -Aside from classic RainTPL loops, plugins order is handle by JavaScript. You can just include `plugin_admin.js`, only if: - -- you're using a table. -- you call orderUp() and orderUp() onclick on arrows. -- you add data-line and data-order to your rows. - -Otherwise, you can use your own JS as long as this field is send by the form: - - - -### Placeholder system - -In order to make plugins work with every custom themes, you need to add variable placeholder in your templates. - -It's a RainTPL loop like this: - - {loop="$plugin_variable"} - {$value} - {/loop} - -You should enable `demo_plugin` for testing purpose, since it uses every placeholder available. - -### List of placeholders - -**page.header.html** - -At the end of the menu: - - {loop="$plugins_header.buttons_toolbar"} - {$value} - {/loop} - -At the end of file, before clearing floating blocks: - - {if="!empty($plugin_errors) && $is_logged_in"} -
    - {loop="plugin_errors"} -
  • {$value}
  • - {/loop} -
- {/if} - -**includes.html** - -At the end of the file: - -```html -{loop="$plugins_includes.css_files"} - -{/loop} -``` - -**page.footer.html** - -At the end of your footer notes: - -```html -{loop="$plugins_footer.text"} - {$value} -{/loop} -``` - -At the end of file: - -```html -{loop="$plugins_footer.js_files"} - -{/loop} -``` - -**linklist.html** - -After search fields: - -```html -{loop="$plugins_header.fields_toolbar"} - {$value} -{/loop} -``` - -Before displaying the link list (after paging): - -```html -{loop="$plugin_start_zone"} - {$value} -{/loop} -``` - -For every links (icons): - -```html -{loop="$value.link_plugin"} - {$value} -{/loop} -``` - -Before end paging: - -```html -{loop="$plugin_end_zone"} - {$value} -{/loop} -``` - -**linklist.paging.html** - -After the "private only" icon: - -```html -{loop="$action_plugin"} - {$value} -{/loop} -``` - -**editlink.html** - -After tags field: - -```html -{loop="$edit_link_plugin"} - {$value} -{/loop} -``` - -**tools.html** - -After the last tool: - -```html -{loop="$tools_plugin"} - {$value} -{/loop} -``` - -**picwall.html** - -Top: - -```html -
- {loop="$plugin_start_zone"} - {$value} - {/loop} -
-``` - -Bottom: - -```html -
- {loop="$plugin_end_zone"} - {$value} - {/loop} -
-``` - -**tagcloud.html** - -Top: - -```html -
- {loop="$plugin_start_zone"} - {$value} - {/loop} -
-``` - -Bottom: - -```html -
- {loop="$plugin_end_zone"} - {$value} - {/loop} -
-``` - -**daily.html** - -Top: - -```html -
- {loop="$plugin_start_zone"} - {$value} - {/loop} -
-``` - -After every link: - -```html -
- {loop="$link.link_plugin"} - {$value} - {/loop} -
-``` - -Bottom: - -```html -
- {loop="$plugin_end_zone"} - {$value} - {/loop} -
-``` - -**feed.atom.xml** and **feed.rss.xml**: - -In headers tags section: -```xml -{loop="$feed_plugins_header"} - {$value} -{/loop} -``` - -After each entry: -```xml -{loop="$value.feed_plugins"} - {$value} -{/loop} -``` diff --git a/doc/md/dev/Release-Shaarli.md b/doc/md/dev/Release-Shaarli.md deleted file mode 100644 index c56654c9..00000000 --- a/doc/md/dev/Release-Shaarli.md +++ /dev/null @@ -1,154 +0,0 @@ -# Release Shaarli - -## Requirements - -This guide assumes that you have: - -- a GPG key matching your GitHub authentication credentials/email (the email address identified by the GPG key is the same as the one in your `~/.gitconfig`) -- a GitHub fork of Shaarli -- a local clone of your Shaarli fork, with the following remotes: - - `origin` pointing to your GitHub fork - - `upstream` pointing to the main Shaarli repository -- maintainer permissions on the main Shaarli repository, to: - - push the signed tag - - create a new release -- [Composer](https://getcomposer.org/) needs to be installed -- The [venv](https://docs.python.org/3/library/venv.html) Python 3 module needs to be installed for HTML documentation generation. -- Make sure you have GNU `tar` installed (not BSD `tar`). On macOS, you can install it with `brew install gnu-tar`. - -## Release notes and `CHANGELOG.md` - -GitHub allows drafting the release notes for the upcoming release, from the [Releases](https://github.com/shaarli/Shaarli/releases) page. This way, the release note can be drafted while contributions are merged to `master`. See http://keepachangelog.com/en/0.3.0/ for changelog formatting. - -`CHANGELOG.md` should contain the same information as the release note draft for the upcoming version. Update it to: - -- add new entries (additions, fixes, etc.) -- mark the current version as released by setting its date and link -- add a new section for the future unreleased version - -```bash -## [v0.x.y](https://github.com/shaarli/Shaarli/releases/tag/v0.x.y) - UNRELEASES - -### Added - -### Changed - -### Fixed - -### Removed - -### Deprecated - -### Security - -``` - - -## Update the list of Git contributors - -```bash -$ make generate_authors -$ git commit -s -m "Update AUTHORS" -``` - -## Create and merge a Pull Request - -Create a Pull Request to marge changes from your remote, into `master` in the community Shaarli repository, and have it merged. - - -## Create the release branch and update shaarli_version.php - -```bash -# fetch latest changes from master to your local copy -git checkout master -git pull upstream master - -# If releasing a new minor version, create a release branch -$ git checkout -b v0.x -# Otherwise just use the existing one -$ git checkout v0.x - -# Get the latest changes -$ git merge master - -# Check that everything went fine: -$ make test - -# Bump shaarli_version.php from dev to 0.x.0, **without the v** -$ vim shaarli_version.php -$ git add shaarli_version -$ git commit -s -m "Bump Shaarli version to v0.x.0" -$ git push upstream v0.x -``` - -## Create and push a signed tag - -Git [tags](http://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project#Tagging-Your-Releases) are used to identify specific revisions with a unique version number that follows [semantic versioning](https://semver.org/) - -```bash -# update your local copy -git checkout v0.5 -git pull upstream v0.5 - -# create a signed tag -git tag -s -m "Release v0.5.0" v0.5.0 - -# push the tag to upstream -git push --tags upstream -``` - -Here is how to verify a signed tag. [`v0.5.0`](https://github.com/shaarli/Shaarli/releases/tag/v0.5.0) is the first GPG-signed tag pushed on the Community Shaarli. Let's have a look at its signature! - -```bash -# update the list of available tags -git fetch upstream - -# get the SHA1 reference of the tag -git show-ref tags/v0.5.0 -# gives: f7762cf803f03f5caf4b8078359a63783d0090c1 refs/tags/v0.5.0 - -# verify the tag signature information -git verify-tag f7762cf803f03f5caf4b8078359a63783d0090c1 -# gpg: Signature made Thu 30 Jul 2015 11:46:34 CEST using RSA key ID 4100DF6F -# gpg: Good signature from "VirtualTam " [ultimate] -``` - -## Publish the GitHub release - -- In the `master` banch, update version badges in `README.md` to point to the newly released Shaarli version -- Update the previously drafted [release](https://github.com/shaarli/Shaarli/releases) (notes, tag) and publish it -- Profit! - - -## Generate full release zip archives - -Release archives will contain Shaarli code plus all required third-party libraries. They are useful for users who: - -- have no SSH access, no possibility to install PHP packages/server extensions, no possibility to run scripts (shared hosting) -- do not want to install build/dev dependencies on their server - - `git checkout` the appropriate branch, then: - -```bash -# checkout the appropriate branch -git checkout 0.x.y -# generate zip archives -make release_archive -``` - -This will create `shaarli-v0.x.y-full.tar`, `shaarli-v0.x.y-full.zip`. These archives need to be manually uploaded on the previously created GitHub [release](https://github.com/shaarli/Shaarli/releases). - - -### Update the `release` branch - -```bash -# checkout the 'release' branch -git checkout release -# merge changes from your newly published release branch -git merge v0.x.y -# fix eventual conflicts with git mergetool... -# run tests -make test -# push the latest branch -git push upstream release -``` diff --git a/doc/md/dev/Theming.md b/doc/md/dev/Theming.md deleted file mode 100644 index a7f73d28..00000000 --- a/doc/md/dev/Theming.md +++ /dev/null @@ -1,86 +0,0 @@ -# Theming - -## Foreword - -There are two ways of customizing how Shaarli looks: - -1. by using a custom CSS to override Shaarli's CSS -2. by using a full theme that provides its own RainTPL templates, CSS and Javascript resources - -## Custom CSS - -Shaarli's appearance can be modified by adding CSS rules to: - -- Shaarli < `v0.9.0`: `inc/user.css` -- Shaarli >= `v0.9.0`: `data/user.css` - -This file allows overriding rules defined in the template CSS files (only add changed rules), or define a whole new theme. - -**Note**: Do not edit `tpl/default/css/shaarli.css`! Your changes would be overridden when updating Shaarli. - -## Themes - -Installation: - -- find a theme you'd like to install -- copy or clone the theme folder under `tpl/` -- enable the theme: - - Shaarli < `v0.9.0`: edit `data/config.json.php` and set the value of `raintpl_tpl` to the new theme name: - `"raintpl_tpl": "tpl\/my-template\/"` - - Shaarli >= `v0.9.0`: select the theme through the _Tools_ page - -## Community CSS & themes - -### Custom CSS - -- [mrjovanovic/serious-theme-shaarli](https://github.com/mrjovanovic/serious-theme-shaarli) - A serious theme for Shaarli -- [shaarli/shaarli-themes](https://github.com/shaarli/shaarli-themes) - -### Themes - -- [AkibaTech/Shaarli Superhero Theme](https://github.com/AkibaTech/Shaarli---SuperHero-Theme) - A template/theme for Shaarli -- [alexisju/albinomouse-template](https://github.com/alexisju/albinomouse-template) - A full template for Shaarli -- [ArthurHoaro/shaarli-launch](https://github.com/ArthurHoaro/shaarli-launch) - Customizable Shaarli theme -- [dhoko/ShaarliTemplate](https://github.com/dhoko/ShaarliTemplate) - A template/theme for Shaarli -- [kalvn/shaarli-blocks](https://github.com/kalvn/shaarli-blocks) - A template/theme for Shaarli -- [kalvn/Shaarli-Material](https://github.com/kalvn/Shaarli-Material) - A theme (template) based on Google's Material Design for Shaarli, the superfast delicious clone -- [ManufacturaInd/shaarli-2004licious-theme](https://github.com/ManufacturaInd/shaarli-2004licious-theme) - A template/theme as a humble homage to the early looks of the del.icio.us site -- [xfnw/shaarli-default-dark](https://github.com/xfnw/shaarli-default-dark) - The default theme but nice and dark for your eyeballs - -### Shaarli forks - -- [misterair/Limonade](https://github.com/misterair/limonade) - A fork of (legacy) Shaarli with a new template -- [vivienhaese/shaarlitheme](https://github.com/vivienhaese/shaarlitheme) - A Shaarli fork meant to be run in an openshift instance - -## Example installation: AlbinoMouse theme - -With the following configuration: - -- Apache 2 / PHP 5.6 -- user sites are enabled, e.g. `/home/user/public_html/somedir` is served as `http://localhost/~user/somedir` -- `http` is the name of the Apache user - -```bash -$ cd ~/public_html - -# clone repositories -$ git clone https://github.com/shaarli/Shaarli.git shaarli -$ pushd shaarli/tpl -$ git clone https://github.com/alexisju/albinomouse-template.git -$ popd - -# set access rights for Apache -$ chgrp -R http shaarli -$ chmod g+rwx shaarli shaarli/cache shaarli/data shaarli/pagecache shaarli/tmp -``` - -Get config written: -- go to the freshly installed site -- fill the install form -- log in to Shaarli - -Edit Shaarli's [configuration](../Shaarli-configuration.md): -```bash -# the file should be owned by Apache, thus not writeable => sudo -$ sudo sed -i s=tpl=tpl/albinomouse-template=g shaarli/data/config.php -``` diff --git a/doc/md/dev/Translations.md b/doc/md/dev/Translations.md deleted file mode 100644 index f0365649..00000000 --- a/doc/md/dev/Translations.md +++ /dev/null @@ -1,157 +0,0 @@ -## Translations - -Shaarli supports [gettext](https://www.gnu.org/software/gettext/manual/gettext.html) translations -since `>= v0.9.2`. - -Note that only the `default` theme supports translations. - -### Contributing - -We encourage the community to contribute to Shaarli translations, either by improving existing translations or submitting a new language. - -Contributing to the translation does not require software development knowledge. - -Please submit a pull request with the `.po` file updated/created. Note that the compiled file (`.mo`) is not stored on the repository, and is generated during the release process. - - -### How to - -Install [Poedit](https://poedit.net/) (used to extract strings to translate from the PHP source code, and generate `.po` files). - -Due to the usage of a template engine, it's important to generate PHP cache files to extract every translatable string. You can either use [this script](https://gist.github.com/ArthurHoaro/5d0323f758ab2401ef444a53f54e9a07) (recommended) or visit every template page in your browser to generate cache files, while logged in. Here is a list : - -``` -http:/// -http:///login -http:///daily -http:///tags/cloud -http:///tags/list -http:///picture-wall -http:///?nonope -http:///admin/add-shaare -http:///admin/password -http:///admin/tags -http:///admin/configure -http:///admin/tools -http:///admin/shaare -http:///admin/export -http:///admin/import -http:///admin/plugins -``` - - -#### Improve existing translations - -- In Poedit, click on "Edit a Translation -- Open `inc/languages//LC_MESSAGES/shaarli.po` under Shaarli's directory -- The existing list of translatable strings should load -- Click on the "Update" button. -- Start editing translations. - -![poedit-screenshot](images/poedit-1.jpg) - -Save when you're done, then you can submit a pull request containing the updated `shaarli.po`. - - -#### Add a new language - -- In Poedit select "Create New Translation" -- Open `inc/languages//LC_MESSAGES/shaarli.po` under Shaarli's directory -- Select the language you want to create. -- Click on `File > Save as...`, save your file in `/inc/language//LC_MESSAGES/shaarli.po` (`` here should be the language code respecting the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-2) format in lowercase - e.g. `de` for German) -- Click on the "Update" button -- Start editing translations. - -Save when you're done, then you can submit a pull request containing the new `shaarli.po`. - - -### Theme translations - -[Theme](Theming.md) translation extensions are loaded automatically if they're present. - -As a theme developer, all you have to do is to add the `.po` and `.mo` compiled file like this: - -``` -tpl//language//LC_MESSAGES/.po -tpl//language//LC_MESSAGES/.mo -``` - -Where `` is the ISO 3166-1 alpha-2 language code. - -Read the following section "Extend Shaarli's translation" to learn how to generate those files. - - -### Extend Shaarli's translation - -If you're writing a custom theme, or a non official plugin, you might want to use the translation system, -but you won't be able to able to override Shaarli's translation. - -However, you can add your own translation domain which extends the main translation list. - -> Note that you can find a live example of translation extension in the `demo_plugin`. - -First, create your translation files tree directory: - -``` -/languages//LC_MESSAGES/ -``` - -Your `.po` files must be named like your domain. E.g. if your translation domain is `my_theme`, then your file will be -`my_theme.po`. - -Users have to register your extension in their configuration with the parameter -`translation.extensions.: `. - -Example: - -```php -if (! $conf->exists('translation.extensions.my_theme')) { - $conf->set('translation.extensions.my_theme', '/languages/'); - $conf->write(true); -} -``` - -> Note that the page needs to be reloaded after the registration. - -It is then recommended to create a custom translation function which will call the `t()` function with your domain. -For example : - -```php -function my_theme_t($text, $nText = '', $nb = 1) -{ - return t($text, $nText, $nb, 'my_theme'); // the last parameter is your translation domain. -} -``` - -All strings which can be translated should be processed through your function: - -```php -my_theme_t('Comment'); -my_theme_t('Comment', 'Comments', 2); -``` - -Or in templates: - -```php -{'Comment'|my_theme_t} -{function="my_theme_t('Comment', 'Comments', 2)"} -``` - -> Note than in template, you need to visit your page at least once to generate a cache file. - -When you're done, open Poedit and load translation strings from sources: - - 1. `File > New` - 2. Choose your language - 3. Save your `PO` file in `/languages//LC_MESSAGES/my_theme.po`. - 4. Go to `Catalog > Properties...` - 5. Fill the `Translation Properties` tab - 6. Add your source path in the `Sources Paths` tab - 7. In the `Sources Keywords` tab uncheck "Also use default keywords" and add the following lines: - -``` -my_theme_t -my_theme_t:1,2 -``` - -Click on the "Update" button and you're free to start your translations! diff --git a/doc/md/dev/Unit-tests.md b/doc/md/dev/Unit-tests.md deleted file mode 100644 index f9fa394d..00000000 --- a/doc/md/dev/Unit-tests.md +++ /dev/null @@ -1,135 +0,0 @@ -# Unit tests - -Shaarli uses the [PHPUnit](https://phpunit.de/) test framework; it can be installed with [Composer](../Installation.md#from-sources), which is a dependency management tool. - -## Install composer - -You can either use: - -- a system-wide version, e.g. installed through your distro's package manager -- a local version, downloadable [here](https://getcomposer.org/download/). - -```bash -# for Debian-based distros -sudo apt install composer -``` - - -## Install Shaarli dev dependencies - -After installing [required PHP extensions](../Server-configuration.md#php), install development dependencies: - -```bash -$ cd /path/to/shaarli -$ make composer_dependencies_dev -``` - -## Install and enable Xdebug to generate PHPUnit coverage reports - - -[Xdebug](http://xdebug.org/docs/install) is a PHP extension which provides debugging and profiling capabilities. Install Xdebug: - -```bash -# for Debian-based distros: -sudo apt install php-xdebug - -# for ArchLinux: -pacman -S xdebug - -# then add the following line to /etc/php/php.ini -zend_extension=xdebug.so -``` - -## Run unit tests - -Ensure tests pass successfully: - -```bash -make test -# ... -# OK (36 tests, 65 assertions) -``` - -In case of failure the test suite will point you to actual errors and output a summary: - -```bash -make test -# ... -# FAILURES! -# Tests: 36, Assertions: 63, Errors: 1, Failures: 2. -``` - -By default, PHPUnit will run all suitable tests found under the `tests` directory. Each test has 3 possible outcomes: - -- `.` - success -- `F` - failure: the test was run but its results are invalid - - the code does not behave as expected - - dependencies to external elements: globals, session, cache... -- `E` - error: something went wrong and the tested code has crashed - - typos in the code, or in the test code - - dependencies to missing external elements - -If Xdebug has been installed and activated, two coverage reports will be generated: - -- a summary in the console -- a detailed HTML report with metrics for tested code - - to open it in a web browser: `firefox coverage/index.html &` - - -### Executing specific tests - -Add a [`@group`](https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.group) annotation in a test class or method comment: - -```php -/** - * Netscape bookmark import - * @group WIP - */ -class BookmarkImportTest extends PHPUnit_Framework_TestCase -{ - [...] -} -``` - -To run all tests annotated with `@group WIP`: -```bash -$ vendor/bin/phpunit --group WIP tests/ -``` - -## Running tests inside Docker containers - -Unit tests can be run inside [Docker](../Docker.md) containers. - -Test Dockerfiles are located under `tests/docker//Dockerfile`, and can be used to build Docker images to run Shaarli test suites under commonLinux environments. Dockerfiles are provided for the following environments: - -- [`alpine316`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/alpine36/Dockerfile) - [Alpine Linux 3.16](https://www.alpinelinux.org/downloads/) -- [`debian8`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/debian8/Dockerfile) - [Debian 8 Jessie](https://www.debian.org/DebianJessie) (oldoldstable) -- [`debian9`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/debian9/Dockerfile) - [Debian 9 Stretch](https://wiki.debian.org/DebianStretch) (oldstable) -- [`ubuntu16`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/ubuntu16/Dockerfile) - [Ubuntu 16.04 Xenial Xerus](http://releases.ubuntu.com/16.04/) (old LTS) - -Each image provides: -- a base Linux OS -- Shaarli PHP dependencies (OS packages) -- test PHP dependencies (OS packages) -- Composer -- Tests that run inside the container using a standard Linux user account (running tests as `root` would bypass permission checks and may hide issues) - -Build a test image: - -```bash -# build the Debian 9 Docker image -cd /path/to/shaarli/tests/docker/debian9 -docker build -t shaarli-test:debian9 . -``` - -Run unit tests in a container: - -```bash -cd /path/to/shaarli -# install/update 3rd-party test dependencies -composer install --prefer-dist -# run tests using the freshly built image -docker run -v $PWD:/shaarli shaarli-test:debian9 docker_test -# run the full test campaign -docker run -v $PWD:/shaarli shaarli-test:debian9 docker_all_tests -``` diff --git a/doc/md/dev/Versioning.md b/doc/md/dev/Versioning.md deleted file mode 100644 index 32c80a5c..00000000 --- a/doc/md/dev/Versioning.md +++ /dev/null @@ -1,63 +0,0 @@ -# Versioning - -If you're maintaining a 3rd party tool for Shaarli (theme, plugin, etc.), It's important to understand how Shaarli branches work ensure your tool stays compatible. - - -## `master` branch - -The `master` branch is the development branch. Any new change MUST go through this branch using Pull Requests. - -Remarks: - -- This branch shouldn't be used for production as it isn't necessary stable. -- 3rd party aren't required to be compatible with the latest changes. -- Official plugins, themes and libraries (contained within Shaarli organization repos) must be compatible with the master branch. - - -## `v0.x` branch - -The `v0.x` branch points to the latest `v0.x.y` release. - -If a major bug affects the original `v0.x.0` release, we may [backport](https://en.wikipedia.org/wiki/Backporting) a fix for this bug from master, to the `v0.x` branch, and create a new bugfix release (eg. `v0.x.1`) from this branch. - -This allows users of the original release to upgrade to the fixed version, without having to upgrade to a completely new minor/major release. - - -## `latest` branch - -This branch point the latest release. It recommended to use it to get the latest tested changes. - - -## Releases - -For every release, we manually generate a .zip file which contains all Shaarli dependencies, making Shaarli's installation only one step. - - -## Advices on 3rd party git repos workflow - -### Versioning - -Any time a new Shaarli release is published, you should publish a new release of your repo if the changes affected you since the latest release (take a look at the [changelog](https://github.com/shaarli/Shaarli/releases) (*Draft* means not released yet) and the commit log (like [`tpl` folder](https://github.com/shaarli/Shaarli/commits/master/tpl/default) for themes)). You can either: - - - use the Shaarli version number, with your repo version. For example, if Shaarli `v0.8.3` is released, publish a `v0.8.3-1` release, where `v0.8.3` states Shaarli compatibility and `-1` is your own version digit for the current Shaarli version. - - use your own versioning scheme, and state Shaarli compatibility in the release description. - -Using this, any user will be able to pick the release matching his own Shaarli version. - -### Major bugfix backport releases - -To be able to support backported fixes, it recommended to use our workflow: - -```bash -# In master, fix the major bug -git commit -m "Katastrophe" -git push origin master -# Get your commit hash -git log --format="%H" -n 1 -# Create a new branch from your latest release, let's say v0.8.2-1 (the tag name) -git checkout -b katastrophe v0.8.2-1 -# Backport the fix commit to your brand new branch -git cherry-pick -git push origin katastrophe -# Then you just have to make a new release from the `katastrophe` branch tagged `v0.8.3-1` -``` diff --git a/doc/md/index.md b/doc/md/index.md index 65e82b9b..195b2696 100644 --- a/doc/md/index.md +++ b/doc/md/index.md @@ -29,6 +29,7 @@ Community-and-related-software.md Plugins.md REST-API.md Troubleshooting.md +dev/Development.md ``` ## Demo @@ -111,16 +112,11 @@ The original Shaarli instance is still available [here](https://sebsauvage.net/l ### Contributing and getting help -Feedback is very appreciated! Feel free to propose solutions to existing problems, help us improve the documentation and translations, and submit pull requests :-) +Feedback is very appreciated! Feel free to propose solutions to existing problems, help us improve the documentation and [translations](dev/Development.md#translations), and submit pull requests :-) See [Support](Troubleshooting.md#support) to get in touch with the Shaarli community. ### License -Shaarli is [Free Software](http://en.wikipedia.org/wiki/Free_software). See -[COPYING](https://github.com/shaarli/Shaarli/blob/master/COPYING) for a detail -of the contributors and licenses for each individual component. A list of -contributors is available -[here](https://github.com/shaarli/Shaarli/blob/master/AUTHORS). - +Shaarli is [Free Software](http://en.wikipedia.org/wiki/Free_software). See [COPYING](https://github.com/shaarli/Shaarli/blob/master/COPYING) for a detail of the contributors and licenses for each individual component. A list of contributors is available [here](https://github.com/shaarli/Shaarli/blob/master/AUTHORS).