diff --git a/doc/conf.py b/doc/conf.py deleted file mode 100644 index afce5360..00000000 --- a/doc/conf.py +++ /dev/null @@ -1,49 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# https://www.sphinx-doc.org/en/master/usage/configuration.html -project = 'shaarli' -author = 'shaarli community' -version = '0.13.0' -release = '0.13.0' -copyright = '2011-2023, the shaarli community' -language = 'en' -html_title = 'Shaarli documentation' -html_theme = 'furo' -html_show_sphinx = False -html_show_search_summary = True -html_copy_source = False -html_show_copyright = True -html_use_opensearch = 'https://shaarli.readthedocs.io/' -html_logo = 'md/images/doc-logo.svg' -html_favicon = 'md/images/icon.png' -extensions = ['myst_parser', 'sphinx_design'] -source_suffix = ['.md'] -templates_path = ['_templates'] -exclude_patterns = [] -suppress_warnings = ["myst.xref_missing"] - -# myst-parser configuration (https://myst-parser.readthedocs.io/en/latest/configuration.html) -myst_enable_extensions = ['fieldlist'] -myst_html_meta = { - "description lang=en": "The personal, minimalist, super fast, database-free bookmarking service", - "charset": "UTF-8" -} - -# theme configuration (https://pradyunsg.me/furo/customisation/) -html_theme_options = { - "top_of_page_button": None, - # "announcement": "Example announcement!" - "source_repository": "https://github.com/shaarli/shaarli", - "source_branch": "master", - "footer_icons": [ - { - "name": "GitHub", - "url": "https://github.com/shaarli/shaarli", - "html": """ - - - - """, - "class": "", - }, - ] -} diff --git a/doc/markdown.php b/doc/markdown.php deleted file mode 100644 index 093d9304..00000000 --- a/doc/markdown.php +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - '; - } - ?> - Markdown help - - -
-

Headings

-

- #Heading 1 -
- ##Heading 2 -
- ###Heading 3 -
- ####Heading 4 -
- #####Heading 5 -
- ######Heading 6 -
-

- Result -
- text("#Heading 1 \n##Heading 2 \n###Heading 3 \n####Heading 4 \n#####Heading 5 \n######Heading 6 \n "); - ?> -
-

Phrase Emphasis

-

- *italic* **bold** ~~strike~~ -

- Result -
- text('*italic* **bold** ~~strike~~'); - ?> -
-

Links

-

- [Shaarli original homepage](http://sebsauvage.net/wiki/doku.php?id=php:shaarli "php:shaarli [sebsauvage]") -
- or simply put link http://sebsauvage.net/wiki/doku.php?id=php:shaarli -

- Result -
- text('[Shaarli original homepage](http://sebsauvage.net/wiki/doku.php?id=php:shaarli "php:shaarli [sebsauvage]") or simply put link http://sebsauvage.net/wiki/doku.php?id=php:shaarli'); - ?> -
-

Lists

-

- Ordered list : -
- 1. item -
- 2. item -
-   1. item -
-   2. item -
- 3. item -

- Result -
- text(" 1. item \n 2. item \n 1. item \n 2. item \n 3. item"); - ?> -
-

- Unordered list : -
- * item -
- * item -
-   * item -
-   * item -

- Result -
- text("* item \n* item \n * item \n * item"); - ?> -
-

Images

-

- ![Shaarli logo](/images/logo.png "Shaarli logo") -

- Result -
- text('![Shaarli logo](/images/logo.png "Shaarli logo")'); - ?> -
-

Blockquotes

-

- >You want to share the links you discover ? Shaarli is a minimalist delicious clone you can install on your own website. It is designed to be personal (single-user), fast and handy. -
- >> Citation under citation -

- Result -
- text(">You want to share the links you discover ? Shaarli is a minimalist delicious clone you can install on your own website. It is designed to be personal (single-user), fast and handy. - \n - >> Citation under citation"); - ?> -
-

Inline code

-

- Try this command ``uptime`` in Linux terminal -

- Result -
- text('Try this command ``uptime`` in Linux terminal'); - ?> -
-

Block code

-

- Try this command -
- ``` -
- uptime -
- ``` -
- in Linux terminal -

- Result -
- text("Try this command \n ``` \n uptime \n ``` \n in Linux terminal"); - ?> -
-

Horizontal Rules

- * * * or -
- *** or -
- ***** or -
- - - - or -
- --------------------------------------- -
- Result -
- text('* * *'); - ?> -
-

Manual Line Breaks

-

- Add two space at endline -
- This line break => -
- here -

- Result -
- setMarkupEscaped(true) -> setBreaksEnabled(true) -> text("This line break =>    - here"); - ?> -
-
- - - \ No newline at end of file diff --git a/doc/md/Backup-and-restore.md b/doc/md/Backup-and-restore.md deleted file mode 100644 index 0b92aee0..00000000 --- a/doc/md/Backup-and-restore.md +++ /dev/null @@ -1,11 +0,0 @@ -## Backup and restore - -All data and [configuration](Shaarli-configuration.md) is kept in the `data` directory. Backup this directory: - -```bash -rsync -avzP my.server.com:/var/www/shaarli.mydomain.org/data ~/backups/shaarli-data-$(date +%Y-%m-%d_%H%M) -``` - -It is strongly recommended to do periodic, automatic backups to a separate machine. You can automate the command above using a cron job or full-featured backup solutions such as [rsnapshot](https://rsnapshot.org/) - -To restore a backup, simply put back the `data/` directory in place, overwriting any existing files. diff --git a/doc/md/Community-and-related-software.md b/doc/md/Community-and-related-software.md deleted file mode 100644 index 15f9363e..00000000 --- a/doc/md/Community-and-related-software.md +++ /dev/null @@ -1,117 +0,0 @@ -# Community & related software - -_Unofficial but related work on Shaarli. If you maintain one of these, -please get in touch with us to help us find a way to adapt your work to our fork._ - - -## Related software - -### REST API clients -See [REST API](REST-API.md) for a list of official and community clients. - - -### Third party plugins - -- [autosave](https://github.com/kalvn/shaarli-plugin-autosave) by [@kalvn](https://github.com/kalvn): Automatically saves data when editing a Shaare to avoid any loss in case of crash or unexpected shutdown. -- [clickat](https://forge.tourmentine.com/n/shaarli-plugin-clickat) by [@n](https://forge.tourmentine.com/n): Makes Twitter and Fediverse addresses clickable. -- [code-coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter. -- [custom-css](https://github.com/immanuelfodor/shaarli-custom-css) by [@immanuelfodor](https://github.com/immanuelfodor) - Customize the look and feel of the UI with custom CSS rules -- [disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli. -- [emojione](https://github.com/immanuelfodor/emojione) by [@immanuelfodor](https://github.com/immanuelfodor) - Resurrected fork of the original emojione project -- [favicons](https://github.com/trailjeep/shaarli-favicons) by [@trailjeep](https://github.com/trailjeep) - Shaarli plugin to add favicon/filetype icons to Shaares. -- [google analytics](https://github.com/ericjuden/Shaarli-Google-Analytics-Plugin) by [@ericjuden](https://github.com/ericjuden): Adds Google Analytics tracking support -- [launch](https://github.com/ArthurHoaro/launch-plugin) - Launch Plugin is a plugin designed to enhance and customize Launch Theme for Shaarli. -- [markdown-toolbar](https://github.com/immanuelfodor/shaarli-markdown-toolbar) by [@immanuelfodor](https://github.com/immanuelfodor) - Easily insert markdown syntax into the Description field when editing a Shaare. -- [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related Shaares based on the number of identical tags. -- [shaargem](https://forge.tourmentine.com/n/shaarli-plugin-shaargem) by [@n](https://forge.tourmentine.com/n): Allow to shaare gemini capsules. -- [shaarli-descriptor](https://github.com/immanuelfodor/shaarli-descriptor) by [@immanuelfodor](https://github.com/immanuelfodor) - Customize the default height/number of rows of the Description field when editing a Shaare. -- [shaarli2mastodon](https://github.com/kalvn/shaarli2mastodon) by [@kalvn](https://github.com/kalvn) - This Shaarli plugin allows you to automatically publish links you post on your Mastodon timeline. -- [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your Shaares from Shaarli -- [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks. -- [urlextern](https://github.com/trailjeep/shaarli-urlextern) by [@trailjeep](https://github.com/trailjeep) - Shaarli plugin to open external links in a new tab/window. -- [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...) - - -### Themes - -- [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 -- [RolandTi/shaarli-stack](https://github.com/RolandTi/shaarli-stack) - A miminalist template/theme for Shaarli -- [xfnw/shaarli-default-dark](https://github.com/xfnw/shaarli-default-dark) - The default theme but nice and dark for your eyeballs -- [mrjovanovic/serious-theme-shaarli](https://github.com/mrjovanovic/serious-theme-shaarli) - A serious theme for Shaarli (custom CSS) - - -### Integration with other platforms - -- [tt-rss-shaarli](https://github.com/jcsaaddupuy/tt-rss-shaarli) - [Tiny-Tiny RSS](https://tt-rss.org/) plugin that adds support for sharing articles with Shaarli -- [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli Shaares on the sidebar -- [Scuttle to Shaarli](https://github.com/q2apro/scuttle-to-shaarli) - Import bookmarks from Scuttle -- [Shaarli app for Cloudron](https://www.cloudron.io/button.html?app=com.github.shaarli) - [![](https://img.shields.io/badge/Cloudron-03A9F4?logo=Buffer)](https://www.cloudron.io/button.html?app=com.github.shaarli) Effortlessly run Shaarli with the help of [Cloudron](https://www.cloudron.io/) -- [Shaarli_ynh](https://github.com/YunoHost-Apps/shaarli_ynh) - [![](https://img.shields.io/badge/YunoHost-black?logo=Buffer)](https://install-app.yunohost.org/?app=shaarli) Shaarli is available as a [Yunohost](https://yunohost.org) app -- [shaarli_poster](https://github.com/getpelican/pelican-plugins/tree/master/shaarli_poster) - [pelican](https://getpelican.com) static blog generator plugin to auto-post articles on a Shaarli instance -- [shaarli .deb package](https://packages.debian.org/search?keywords=shaarli) - for [Debian](https://www.debian.org/) and [Freedombox](https://www.freedombox.org/) - - -### Mobile apps - -- [ShaarliOS](https://github.com/mro/ShaarliOS) - [![](https://img.shields.io/badge/App%20Store-black?logo=apple)](https://apps.apple.com/app/shaarlios/id1027441388) Apple iOS share extension. -- [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - [![](https://img.shields.io/badge/Play%20Store-3EB7C0?logo=Google%20Play)](https://play.google.com/store/apps/details?id=com.dimtion.shaarlier) Android application to simply add Shaares directly into your Shaarli via Sharing. Free software. -- [Stakali for Android](https://stakali.toneiv.eu) - [![](https://img.shields.io/badge/Play%20Store-3EB7C0?logo=Google%20Play)](https://play.google.com/store/apps/details?id=eu.toneiv.stakali) Stakali is a personal bookmark manager which synchronizes with Shaarli. Support offline work without instance, sync, browsing within app. Free use of up to 20 results. -- [Shaarli for Android](https://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider. - - -### Desktop apps - -- [Ulauncher Extension](https://github.com/sebw/ulauncher-shaarli) - Ulauncher is an an application launcher for Linux, this extension allows research in your Shaarli - - -### Browser extensions - -- [Shaarli Firefox Extension](https://github.com/ikipatang/shaarli-web-extension) - [![](https://img.shields.io/badge/Firefox%20Add--ons-414141?logo=Firefox)](https://addons.mozilla.org/en-US/firefox/addon/shaarli/) toolbar button to share your current tab with Shaarli. -- [Add to Shaarli](https://github.com/burgyl/AddToShaarli) - [![](https://img.shields.io/badge/Chrome%20Web%20Store-white?logo=Google%20Chrome)](https://chrome.google.com/webstore/detail/add-to-shaarli/jhfblapoehcfajokolimghdfmeeakbee) lets you add the current tab or a note to your Shaarli instance. -- [WebLinks Ext](https://chrome.google.com/webstore/detail/weblinks-ext/pnejcofgljlklmmjkocipnanfdbaclke) - [![](https://img.shields.io/badge/Chrome%20Web%20Store-white?logo=Google%20Chrome)](https://chrome.google.com/webstore/detail/weblinks-ext/pnejcofgljlklmmjkocipnanfdbaclke) Save, edit and use your Shaarli. Support work offline, sync, trash, etc. Free software. -- [Shaarli Chrome Extension](https://github.com/octplane/Shiny-Shaarli) - toolbar button to share your current tab with Shaarli. (Removed from Chrome web store). - - -### Server apps - -- [Shaarli Archiver](https://github.com/sebw/shaarli-archiver) - Shaarli and SingleFile to archive your bookmarks -- [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content -- [shaarli-river](https://github.com/mknexen/shaarli-river) - An aggregator for shaarlis with many features -- [Shaarlo](https://github.com/DMeloni/shaarlo) - An aggregator for shaarlis with many features -- [Shaarlimages](https://github.com/BoboTiG/shaarlimages) - An image-oriented aggregator for Shaarlis -- [mknexen/shaarli-api](https://github.com/mknexen/shaarli-api) - A REST API for Shaarli -- [Self dead link](https://framagit.org/qwertygc/shaarli-dev-code/blob/master/self-dead-link.php) - Detect dead links on shaarli. This version use the database of shaarli. [Another version](https://framagit.org/qwertygc/shaarli-dev-code/blob/master/dead-link.php), can be used for other shaarli instances (but is more resource consuming). -- [Bookmark Archiver](https://github.com/ArchiveBox/ArchiveBox) - Save an archived copy of all websites starred using browser bookmarks/Shaarli/Delicious/Instapaper/Unmark.it/Pocket/Pinboard. Outputs browseable html. - - -## Alternatives to Shaarli - -See [awesome-selfhosted: bookmarks & link sharing](https://awesome-selfhosted.net/tags/bookmarks-and-link-sharing.html). - - -## Community - -- [Liens en vrac de sebsauvage](https://sebsauvage.net/links/) - the original Shaarli -- [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html) -- [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json) -- [A list of some known Shaarlis](https://github.com/Oros42/shaarlis_list) -- [Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net](https://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-) (fr) _16/09/2011 - the original post about Shaarli_ -- [Original ideas/fixme/TODO page](https://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas) -- [Original discussion page](https://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion) (fr) -- [Original revisions history](https://sebsauvage.net/wiki/doku.php?id=php:shaarli:history) - - -### Articles and social media discussions -- 2020-04-05 - Hacker News - [Self-hosted instance of Shaarli - it is simple, fast and reliable](https://news.ycombinator.com/item?id=22780219) -- 2016-10-10 - Framasoft - [MyFrama : vos favoris partout, avec vous, rien qu’à vous !](https://framablog.org/2016/10/10/myframa-vos-favoris-et-framasofteries-partout-avec-vous-rien-qua-vous/) -- 2016-09-22 - Hacker News - [Shaarli – Personal, minimalist, database-free, bookmarking service (github.com)](https://news.ycombinator.com/item?id=12552176) -- 2015-08-15 - Reddit - [Question about migrating from WordPress to Shaarli.](https://www.reddit.com/r/selfhosted/comments/3h3zwh/question_about_migrating_from_wordpress_to_shaarli/) -- 2015-06-22 - Hacker News - [Shaarli: Self-hosted del.icio.us alternative (sebsauvage.net)](https://news.ycombinator.com/item?id=9755366) -- 2015-05-12 - Reddit - [shaarli - Self hosted Bookmarking / Delicious (PHP, MySQL)](https://www.reddit.com/r/selfhosted/comments/35pkkc/shaarli_self_hosted_bookmarking_delicious_php/) -- 2014-10-15 - OpenSource.com - [Five open source alternatives to popular web apps](https://opensource.com/life/14/10/five-open-source-alternatives-popular-web-apps) - -It also appears in the following recommendation lists: -- [AlternativeTo](https://alternativeto.net/software/shaarli/) -- [FramaLibre](https://framalibre.org/content/shaarli) -- [Awesome-Selfhosted - Bookmarks and Link Sharing](https://awesome-selfhosted.net/tags/bookmarks-and-link-sharing.html) diff --git a/doc/md/Docker.md b/doc/md/Docker.md deleted file mode 100644 index 69c62897..00000000 --- a/doc/md/Docker.md +++ /dev/null @@ -1,227 +0,0 @@ - -# Docker - -[Docker](https://docs.docker.com/get-started/overview/) is an open platform for developing, shipping, and running applications - -## Install Docker - -Install [Docker](https://docs.docker.com/engine/install/), by following the instructions relevant to your OS / distribution, and start the service. For example on [Debian](https://docs.docker.com/engine/install/debian/): - -```bash -# update your package lists -sudo apt update -# remove old versions -sudo apt-get remove docker docker-engine docker.io containerd runc -# install requirements -sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -# add docker's GPG signing key -curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - -# add the repository -sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" -# install docker engine -sudo apt-get update -sudo apt-get install docker-ce docker-ce-cli containerd.io -# Start and enable Docker service -sudo systemctl enable docker && sudo systemctl start docker -# verify that Docker is properly configured -sudo docker run hello-world -``` - -In order to run Docker commands as a non-root user, you must add the `docker` group to this user: - -```bash -# Add docker group as secondary group -sudo usermod -aG docker your-user -# Reboot or logout -# Then verify that Docker is properly configured, as "your-user" -docker run hello-world -``` - -## Get and run a Shaarli image - -Shaarli images are available on [GitHub Container Registry](https://github.com/shaarli/Shaarli/pkgs/container/shaarli) `ghcr.io/shaarli/shaarli`: - -- `latest`: master (development) branch -- `vX.Y.Z`: shaarli [releases](https://github.com/shaarli/Shaarli/releases) -- `release`: always points to the last release -- `stable` and `master`: **deprecated**. These tags are no longer maintained and may be removed without notice - -These images are built automatically on Github Actions and rely on: - -- [Alpine Linux](https://www.alpinelinux.org/) -- [PHP7-FPM](https://php-fpm.org/) -- [Nginx](https://nginx.org/) - -Additional Dockerfiles are provided for the `arm32v7` platform, relying on [Linuxserver.io Alpine armhf images](https://hub.docker.com/r/lsiobase/alpine.armhf/). These images must be built using [`docker build`](https://docs.docker.com/engine/reference/commandline/build/) on an `arm32v7` machine or using an emulator such as [qemu](https://blog.balena.io/building-arm-containers-on-any-x86-machine-even-dockerhub/). - -Here is an example of how to run Shaarli latest image using Docker: - -```bash -# download the 'latest' image from GitHub Container Registry -docker pull ghcr.io/shaarli/shaarli - -# create persistent data volumes/directories on the host -docker volume create shaarli-data -docker volume create shaarli-cache - -# create a new container using the Shaarli image -# --detach: run the container in background -# --name: name of the created container/instance -# --publish: map the host's :8000 port to the container's :80 port -# --rm: automatically remove the container when it exits -# --volume: mount persistent volumes in the container ($volume_name:$volume_mountpoint) -docker run --detach \ - --name myshaarli \ - --publish 8000:80 \ - --rm \ - --volume shaarli-data:/var/www/shaarli/data \ - --volume shaarli-cache:/var/www/shaarli/cache \ - ghcr.io/shaarli/shaarli:latest - -# verify that the container is running -docker ps | grep myshaarli - -# to completely remove the container -docker stop myshaarli # stop the running container -docker ps | grep myshaarli # verify the container is no longer running -docker ps -a | grep myshaarli # verify the container is stopped -docker rm myshaarli # destroy the container -docker ps -a | grep myshaarli # verify th container has been destroyed - -``` - -After running `docker run` command, your Shaarli instance should be available on the host machine at [localhost:8000](http://localhost:8000). In order to access your instance through a reverse proxy, we recommend using our [Docker Compose](#docker-compose) build. - -## Docker Compose - -A [Compose file](https://docs.docker.com/compose/compose-file/) is a common format for defining and running multi-container Docker applications. - -A `docker-compose.yml` file can be used to run a persistent/autostarted shaarli service using [Docker Compose](https://docs.docker.com/compose/) or in a [Docker stack](https://docs.docker.com/engine/reference/commandline/stack_deploy/). - -Shaarli provides configuration file for Docker Compose, that will setup a Shaarli instance, a [Træfik](https://traefik.io/traefik/) instance (reverse proxy) with [Let's Encrypt](https://letsencrypt.org/) certificates, a Docker network, and volumes for Shaarli data and Træfik TLS configuration and certificates. - -Download docker-compose from the [release page](https://docs.docker.com/compose/install/): - -```bash -$ sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose -$ sudo chmod +x /usr/local/bin/docker-compose -``` - -To run Shaarli container and its reverse proxy, you can execute the following commands: - -```bash -# create a new directory to store the configuration: -$ mkdir shaarli && cd shaarli -# Download the latest version of Shaarli's docker-compose.yml -$ curl -L https://raw.githubusercontent.com/shaarli/Shaarli/latest/docker-compose.yml -o docker-compose.yml -# Create the .env file and fill in your VPS and domain information -# (replace , and with your actual information) -$ echo 'SHAARLI_VIRTUAL_HOST=shaarli.mydomain.org' > .env -$ echo 'SHAARLI_LETSENCRYPT_EMAIL=admin@mydomain.org' >> .env -# Available Docker tags can be found at https://github.com/shaarli/Shaarli/pkgs/container/shaarli/versions?filters%5Bversion_type%5D=tagged -$ echo 'SHAARLI_DOCKER_TAG=latest' >> .env -# Pull the Docker images -$ docker-compose pull -# Run! -$ docker-compose up -d -``` - -After a few seconds, you should be able to access your Shaarli instance at [https://shaarli.mydomain.org](https://shaarli.mydomain.org) (replace your own domain name). - -## Running dockerized Shaarli as a systemd service - -It is possible to start a dockerized Shaarli instance as a systemd service (systemd is the service management tool on several distributions). After installing Docker, use the following steps to run your shaarli container Shaarli to run on system start. - -As root, create `/etc/systemd/system/docker.shaarli.service`: - -```ini -[Unit] -Description=Shaarli Bookmark Manager Container -After=docker.service -Requires=docker.service - - -[Service] -Restart=always - -# Put any environment you want in an included file, like $host- or $domainname in this example -EnvironmentFile=/etc/sysconfig/box-environment - -# It's just an example.. -ExecStart=/usr/bin/docker run \ - -p 28010:80 \ - --name ${hostname}-shaarli \ - --hostname shaarli.${domainname} \ - -v /srv/docker-volumes-local/shaarli-data:/var/www/shaarli/data:rw \ - -v /etc/localtime:/etc/localtime:ro \ - ghcr.io/shaarli/shaarli:latest - -ExecStop=/usr/bin/docker rm -f ${hostname}-shaarli - -[Install] -WantedBy=multi-user.target -``` - -```bash -# reload systemd services definitions -systemctl daemon-reload -# start the servie and enable it a boot time -systemctl enable docker.shaarli.service --now -# verify that the service is running -systemctl status docker.* -# inspect system log if needed -journalctl -f -``` - - - -## Docker cheatsheet - -```bash -# pull/update an image -$ docker pull ghcr.io/shaarli/shaarli:release -# run a container from an image -$ docker run ghcr.io/shaarli/shaarli:latest -# list available images -$ docker images ls -# list running containers -$ docker ps -# list running AND stopped containers -$ docker ps -a -# run a command in a running container -$ docker exec -ti bash -# follow logs of a running container -$ docker logs -f -# delete unused images to free up disk space -$ docker system prune --images -# delete unused volumes to free up disk space (CAUTION all data in unused volumes will be lost) -$ docker system prune --volumes -# delete unused containers -$ docker system prune -``` - - -## References - -- [Docker: using volumes](https://docs.docker.com/storage/volumes/) -- [Dockerfile best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) -- [Dockerfile reference](https://docs.docker.com/engine/reference/builder/) -- [GitHub Container Registry](https://github.com/features/packages) -- [GithHub Packages documentation](https://docs.github.com/en/packages) -- [DockerHub: Teams and organizations](https://docs.docker.com/docker-hub/orgs/), [End of Docker free teams](https://www.docker.com/blog/we-apologize-we-did-a-terrible-job-announcing-the-end-of-docker-free-teams/) -- [Get Docker CE for Debian](https://docs.docker.com/engine/install/debian/) -- [Install Docker Compose](https://docs.docker.com/compose/install/) -- [Service management: Nginx in the foreground](https://nginx.org/en/docs/ngx_core_module.html#daemon) -- [Service management: Run multiple services in a container](https://docs.docker.com/config/containers/multi-service_container/) -- [Volumes](https://docs.docker.com/storage/volumes/) -- [Where are Docker images stored?](https://blog.thoward37.me/articles/where-are-docker-images-stored/) -- [docker create](https://docs.docker.com/engine/reference/commandline/create/) -- [Docker Documentation](https://docs.docker.com/) -- [docker exec](https://docs.docker.com/engine/reference/commandline/exec/) -- [docker images](https://docs.docker.com/engine/reference/commandline/images/) -- [docker logs](https://docs.docker.com/engine/reference/commandline/logs/) -- [Docker Overview](https://docs.docker.com/get-started/overview/) -- [docker ps](https://docs.docker.com/engine/reference/commandline/ps/) -- [docker pull](https://docs.docker.com/engine/reference/commandline/pull/) -- [docker run](https://docs.docker.com/engine/reference/commandline/run/) -- Træfik: [Documentation](https://doc.traefik.io/traefik/), [Docker image](https://hub.docker.com/_/traefik/) diff --git a/doc/md/Installation.md b/doc/md/Installation.md deleted file mode 100644 index 0f795fee..00000000 --- a/doc/md/Installation.md +++ /dev/null @@ -1,83 +0,0 @@ -# Installation - -Once your server is [configured](Server-configuration.md), install Shaarli: - -## From release ZIP - -To install Shaarli, simply place the files from the latest [release .zip archive](https://github.com/shaarli/Shaarli/releases) under your webserver's document root (directly at the document root, or in a subdirectory). Download the **shaarli-vX.X.X-full** archive to include dependencies. - -```bash -wget https://github.com/shaarli/Shaarli/releases/download/v0.11.1/shaarli-v0.11.1-full.zip -unzip shaarli-v0.11.1-full.zip -sudo rsync -avP Shaarli/ /var/www/shaarli.mydomain.org/ -``` - -## From sources - -These components are required to build Shaarli: - -- [Composer](dev/Development.md#install-composer) to manage third-party [PHP dependencies](dev/Development#third-party-libraries). -- [yarn](https://classic.yarnpkg.com/en/docs/install/) to build frontend dependencies. -- [python3-virtualenv](https://pypi.org/project/virtualenv/) to build local HTML documentation. - -```bash -# example from a Debian-based build machine -sudo apt install composer yarnpkg python3-virtualenv -``` - -Clone the repository, either pointing to: - -- any [tagged release](https://github.com/shaarli/Shaarli/releases) -- `latest`: the latest tagged release -- `master`: development branch - -```bash -# clone the branch/tag of your choice -$ git clone -b latest https://github.com/shaarli/Shaarli.git /home/me/Shaarli -# OR download/extract the tar.gz/zip: wget https://github.com/shaarli/Shaarli/archive/latest.tar.gz... - -# enter the directory -$ cd /home/me/Shaarli -# install 3rd-party PHP dependencies -$ composer install --no-dev --prefer-dist -# build frontend static assets -$ make build_frontend -# build translations -$ make translate -# build HTML documentation -$ make htmldoc -# copy the resulting shaarli directory under your webserver's document root -$ rsync -avP /home/me/Shaarli/ /var/www/shaarli.mydomain.org/ -``` - -## Set file permissions - -Regardless of the installation method, appropriate [file permissions](dev/Development.md#directory-structure) must be set: - -```bash -sudo chown -R root:www-data /var/www/shaarli.mydomain.org -sudo chmod -R g+rX /var/www/shaarli.mydomain.org -sudo chmod -R g+rwX /var/www/shaarli.mydomain.org/{cache/,data/,pagecache/,tmp/} -``` - -## Using Docker - -[See the documentation](Docker.md) - - -## Finish Installation - -Once Shaarli is downloaded and files have been placed at the correct location, open this location your web browser. - -Enter basic settings for your Shaarli installation, and it's ready to use! - -![](images/07-installation.jpg) - -Congratulations! Your Shaarli is now available at `https://shaarli.mydomain.org`. - -You can further [configure Shaarli](Shaarli-configuration.md), setup [Plugins](Plugins.md) or [additional software](Community-and-related-software.md). - - -## Upgrading Shaarli - -See [Upgrade and Migration](Upgrade-and-migration) diff --git a/doc/md/Plugins.md b/doc/md/Plugins.md deleted file mode 100644 index d0e91fee..00000000 --- a/doc/md/Plugins.md +++ /dev/null @@ -1,62 +0,0 @@ -# Plugins - -## Installation - -For plugins shipped with Shaarli, no installation is required. - -If you want to install a third party plugin, download it to the `plugins` directory in Shaarli's installation folder: - -```bash -# example directory structure -| index.php -| plugins/ -|---| custom_plugin/ -| |---| custom_plugin.php -| |---| ... - -``` - -Make sure your webserver can read and write the files in your plugin folder. - - -## Configuration - -From Shaarli's administration page (`Tools` link), go to `Plugin administration`. Here you can enable and disable all plugins available, and configure them. - -![administration screenshot](https://camo.githubusercontent.com/5da68e191969007492ca0fbeb25f3b2357b748cc/687474703a2f2f692e696d6775722e636f6d2f766837544643712e706e67) - - -## Order - -In the plugin administration page, you can move enabled plugins to the top or bottom of the list. The first plugins in the list will be processed first. - -This is important in case plugins depend on each other. Read plugins READMEs for more information. - -**Use case**: The (non existent) plugin `shaares_footer` adds a footer to every shaare in Markdown syntax. It needs to be processed *before* (higher in the list) the Markdown plugin. Otherwise its syntax won't be translated in HTML. - - -## Configuration file - -Enabled plugins are stored in your [Configuration file](Shaarli-configuration.md). - -## Usage - -### Official plugins - -Usage of each plugin is documented in it's README file: - - * `addlink-toolbar`: Adds the addlink input on the Shaares list page - * `archiveorg`: For each Shaare, add a link to the archived page on Archive.org - * `default_colors`: Override default theme colors. - * `isso`: Let visitor comment your shaares on permalinks with Isso. - * `piwik`: A plugin that adds Piwik tracking code to Shaarli pages. - * [`playvideos`](https://github.com/shaarli/Shaarli/blob/master/plugins/playvideos/README.md): Add a button in the toolbar allowing to watch all videos. - * `pubsubhubbub`: Enable PubSubHubbub feed publishing - * `qrcode`: For each Shaare, add a QRCode icon. - * `readitlater`: Mark bookmarks to read them later, with bookmark list highlight and filter. - * [`wallabag`](https://github.com/shaarli/Shaarli/blob/master/plugins/wallabag/README.md): For each Shaare, add a Wallabag icon to save it in your instance. - - -### Third party plugins - -See [Community & related software](Community-and-related-software.md) diff --git a/doc/md/REST-API.md b/doc/md/REST-API.md deleted file mode 100644 index f5a579d3..00000000 --- a/doc/md/REST-API.md +++ /dev/null @@ -1,150 +0,0 @@ -# REST API - -## Server requirements - -See the **[REST API documentation](https://shaarli.github.io/api-documentation/)** for a list of available endpoints and parameters. - -Please ensure that your server meets the requirements and is properly [configured](Server-configuration.md): - -- URL rewriting is enabled (see specific Apache and Nginx sections) -- the server's timezone is properly defined -- the server's clock is synchronized with [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) - -The host where the API client is invoked should also be synchronized with NTP, see _payload/token expiration_ - - -## Clients and examples - -- **[python-shaarli-client](https://github.com/shaarli/python-shaarli-client)** - the reference API client ([Documentation](https://python-shaarli-client.readthedocs.io/en/latest/)) -- [shaarli-client](https://www.npmjs.com/package/shaarli-client) - NodeJs client ([source code](https://github.com/laBecasse/shaarli-client)) by [laBecasse](https://github.com/laBecasse) -- [Android client example with Kotlin](https://gitlab.com/-/snippets/1665808) by [Braincoke](https://github.com/Braincoke) - - -This example uses the [PHP cURL](https://www.php.net/manual/en/book.curl.php) library. - -```php -`. -- JWT tokens are composed by three parts, separated by a dot `.` and encoded in base64: - -``` -[header].[payload].[signature] -``` - -##### Header - -Shaarli only allow one hash algorithm, so the header will always be the same: - -```json -{ - "typ": "JWT", - "alg": "HS512" -} -``` - -Encoded in base64, it gives: - -``` -ewogICAgICAgICJ0eXAiOiAiSldUIiwKICAgICAgICAiYWxnIjogIkhTNTEyIgogICAgfQ== -``` - -##### Payload - -Token expiration: To avoid infinite token validity, JWT tokens must include their creation date in UNIX timestamp format (timezone independent - UTC) under the key `iat` (issued at) field ([1](https://datatracker.ietf.org/doc/html/rfc7519)). This token will be valid during **9 minutes**. - -```json -{ - "iat": 1468663519 -} -``` - -##### Signature - -The signature authenticates the token validity. It contains the base64 of the header and the body, separated by a dot `.`, hashed in SHA512 with the API secret available in Shaarli administration page. - -Example signature with PHP: - -```php -$content = base64_encode($header) . '.' . base64_encode($payload); -$signature = hash_hmac('sha512', $content, $secret); -``` - - - -## Troubleshooting - -### Debug mode - -> This should never be used in a production environment. - -For security reasons, authentication issues will always return an `HTTP 401` error code without any detail. - -It is possible to enable the debug mode in `config.json.php` -to get the actual error message in the HTTP response body with: - -```json -{ - "dev": { - "debug": true - } -} -``` - -## References - -- [jwt.io](https://jwt.io) (including a list of client per language). -- [RFC - JSON Web Token (JWT)](https://datatracker.ietf.org/doc/html/rfc7519) -- [JSON Web Tokens (JWT) vs Sessions](https://float-middle.com/json-web-tokens-jwt-vs-sessions/), [HackerNews thread](https://news.ycombinator.com/item?id=11929267) - - - - diff --git a/doc/md/Reverse-proxy.md b/doc/md/Reverse-proxy.md deleted file mode 100644 index 1cd3ee2a..00000000 --- a/doc/md/Reverse-proxy.md +++ /dev/null @@ -1,142 +0,0 @@ -# Reverse proxy - -If Shaarli is hosted on a server behind a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) (i.e. there is a proxy server between clients and the web server hosting Shaarli), configure it accordingly. See [Reverse proxy](Reverse-proxy.md) configuration. In this example: - -- The Shaarli application server exposes port `10080` to the proxy (for example docker container started with `--publish 127.0.0.1:10080:80`). -- The Shaarli application server runs at `127.0.0.1` (container). Replace with the server's IP address if running on a different machine. -- Shaarli's Fully Qualified Domain Name (FQDN) is `shaarli.mydomain.org`. -- No HTTPS is setup on the application server, SSL termination is done at the reverse proxy. - -In your [Shaarli configuration](Shaarli-configuration.md) `data/config.json.php`, add the public IP of your proxy under `security.trusted_proxies`. - -See also [proxy-related](https://github.com/shaarli/Shaarli/issues?utf8=%E2%9C%93&q=label%3Aproxy+) issues. - - -## Apache - -```apache - - ServerName shaarli.mydomain.org - - # For SSL/TLS certificates acquired with certbot or self-signed certificates - # Redirect HTTP requests to HTTPS, except Let's Encrypt ACME challenge requests - RewriteEngine on - RewriteRule ^.well-known/acme-challenge/ - [L] - RewriteCond %{HTTP_HOST} =shaarli.mydomain.org - RewriteRule ^ https://shaarli.mydomain.org%{REQUEST_URI} [END,NE,R=permanent] - - -# SSL/TLS configuration for Let's Encrypt certificates managed with mod_md -#MDomain shaarli.mydomain.org -#MDCertificateAgreement accepted -#MDContactEmail admin@shaarli.mydomain.org -#MDPrivateKeys RSA 4096 - - - ServerName shaarli.mydomain.org - - # SSL/TLS configuration for Let's Encrypt certificates acquired with certbot standalone - SSLEngine on - SSLCertificateFile /etc/letsencrypt/live/shaarli.mydomain.org/fullchain.pem - SSLCertificateKeyFile /etc/letsencrypt/live/shaarli.mydomain.org/privkey.pem - # Let's Encrypt settings from https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/_internal/tls_configs/current-options-ssl-apache.conf - SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 - SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 - SSLHonorCipherOrder off - SSLSessionTickets off - SSLOptions +StrictRequire - - # SSL/TLS configuration for self-signed certificates - #SSLEngine on - #SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem - #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key - - # let the proxied shaarli server/container know HTTPS URLs should be served - RequestHeader set X-Forwarded-Proto "https" - - # send the original SERVER_NAME to the proxied host - ProxyPreserveHost On - - # pass requests to the proxied host - # sets X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Server headers - ProxyPass / http://127.0.0.1:10080/ - ProxyPassReverse / http://127.0.0.1:10080/ - -``` - - -## HAProxy - - -``` -global - [...] - -defaults - [...] - -frontend http-in - bind :80 - redirect scheme https code 301 if !{ ssl_fc } - bind :443 ssl crt /path/to/cert.pem - default_backend shaarli - -backend shaarli - mode http - option http-server-close - option forwardfor - reqadd X-Forwarded-Proto: https - server shaarli1 127.0.0.1:10080 -``` - -- [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/) - -## Nginx - - -```nginx -http { - [...] - - index index.html index.php; - - root /home/john/web; - access_log /var/log/nginx/access.log combined; - error_log /var/log/nginx/error.log; - - server { - listen 80; - server_name shaarli.mydomain.org; - # redirect HTTP to HTTPS - return 301 https://shaarli.mydomain.org$request_uri; - } - - server { - listen 443 ssl http2; - server_name shaarli.mydomain.org; - - ssl_certificate /path/to/certificate - ssl_certificate_key /path/to/private/key - - # if shaarli is installed in a subdirectory of the main domain, edit the location accordingly - location / { - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $host; - - # pass requests to the proxied host - proxy_pass http://localhost:10080/; - proxy_set_header Host $host; - proxy_connect_timeout 30s; - proxy_read_timeout 120s; - } - } -} -``` - -## References - -- [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) -- [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) -- [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) diff --git a/doc/md/Server-configuration.md b/doc/md/Server-configuration.md deleted file mode 100644 index 16763f3c..00000000 --- a/doc/md/Server-configuration.md +++ /dev/null @@ -1,445 +0,0 @@ -# Server configuration - -## Requirements - -### Operating system and web server - -Shaarli can be hosted on dedicated/virtual servers, or shared hosting. - -You need write access to the Shaarli installation directory - you should have received instructions from your hosting provider on how to connect to the server using SSH (or FTP for shared hosts). - -Examples in this documentation are given for [Debian](https://www.debian.org/), a GNU/Linux distribution widely used in server environments. Please adapt them to your specific Linux distribution. - -A $5/month VPS (1 CPU, 1 GiB RAM and 25 GiB SSD) will run any Shaarli installation without problems. Some hosting providers: [DigitalOcean](https://www.digitalocean.com/) ([1](https://docs.digitalocean.com/products/droplets/), [2](https://www.digitalocean.com/pricing/), [3](https://docs.digitalocean.com/products/droplets/how-to/create/), [4](https://docs.digitalocean.com/products/droplets/how-to/add-ssh-keys/), [5](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-debian-8), [6](https://www.digitalocean.com/community/tutorials/an-introduction-to-securing-your-linux-vps)), [Gandi](https://www.gandi.net/en), [OVH](https://www.ovhcloud.com/en-gb/), [RackSpace](https://www.rackspace.com/), etc. - - -### Network and domain name - -Try to host the server in a region that is geographically close to your users. - -A **domain name** ([DNS record](https://opensource.com/article/17/4/introduction-domain-name-system-dns)) pointing to the server's public IP address is required to obtain a SSL/TLS certificate and setup HTTPS to secure client traffic to your Shaarli instance. - -You can obtain a domain name from a [registrar](https://en.wikipedia.org/wiki/Domain_name_registrar) ([1](https://www.ovhcloud.com/en-gb/domains), [2](https://www.gandi.net/en/domain)), or from free subdomain providers ([1](https://freedns.afraid.org/)). If you don't have a domain name, please set up a private domain name ([FQDN](ttps://en.wikipedia.org/wiki/Fully_qualified_domain_name)) in your clients' [hosts files](https://en.wikipedia.org/wiki/Hosts_(file)) to access the server (direct access by IP address can result in unexpected behavior). - -Setup a **firewall** (using `iptables`, [ufw](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-debian-10), [firewalld](https://firewalld.org/) or any frontend of your choice) to deny all incoming traffic except `tcp/80` and `tcp/443`, which are needed to access the web server (and any other posrts you might need, like SSH). If the server is in a private network behind a NAT, ensure these **ports are forwarded** to the server. - -Shaarli makes outbound HTTP/HTTPS connections to websites you bookmark to fetch page information (title, thumbnails), the server must then have access to the Internet as well, and a working DNS resolver. - --------------------------------------------------------------------------------- - -### PHP - -Supported PHP versions: - -Version | Status | Shaarli compatibility -:---:|:---:|:---: -8.2 | Supported | Yes -8.1 | Supported | Yes -8.0 | EOL: 2023-11-26| Yes -7.4 | EOL: 2022-11-28 | Yes -7.3 | EOL: 2021-12-06 | Yes (up to Shaarli 0.12.2) -7.2 | EOL: 2020-11-30 | Yes (up to Shaarli 0.12.2) -7.1 | EOL: 2019-12-01 | Yes (up to Shaarli 0.12.2) -7.0 | EOL: 2018-12-03 | Yes (up to Shaarli 0.10.x) -5.6 | EOL: 2018-12-31 | Yes (up to Shaarli 0.10.x) -5.5 | EOL: 2016-07-10 | Yes -5.4 | EOL: 2015-09-14 | Yes (up to Shaarli 0.8.x) -5.3 | EOL: 2014-08-14 | Yes (up to Shaarli 0.8.x) - -Required PHP extensions: - -Extension | Required? | Usage ----|:---:|--- -[`openssl`](https://www.php.net/manual/en/book.openssl.php) | required | OpenSSL, HTTPS -[`php-json`](https://www.php.net/manual/en/book.json.php) | required | configuration parsing -[`php-simplexml`](https://www.php.net/manual/en/book.simplexml.php) | required | REST API (Slim framework) -[`php-mbstring`](https://www.php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support -[`php-ctype`](https://www.php.net/manual/en/book.ctype.php) | required (bundled with most PHP installation) | Type checking -[`php-iconv`](https://www.php.net/manual/en/book.iconv.php) | required (bundled with most PHP installation) | Character encoding used in translations -[`php-session`](https://www.php.net/manual/en/book.session.php) | required (bundled with most PHP installation) | User session -[`php-zlib`](https://www.php.net/manual/en/book.zlib.php) | required (bundled with most PHP installation) | Datastore I/O compression -[`php-gd`](https://www.php.net/manual/en/book.image.php) | optional | required to use thumbnails -[`php-intl`](https://www.php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`) -[`php-curl`](https://www.php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way -[`php-gettext`](https://www.php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster) -[`php-ldap`](https://www.php.net/manual/en/book.ldap.php) | optional | LDAP login support - -Some [plugins](Plugins.md) may require additional configuration. - -- [PHP: Supported versions](https://www.php.net/supported-versions.php) -- [PHP: Unsupported versions (EOL/End-of-life)](https://www.php.net/eol.php) -- [PHP 7 Changelog](https://www.php.net/ChangeLog-7.php) -- [PHP 5 Changelog](https://www.php.net/ChangeLog-5.php) -- [PHP: Bugs](https://bugs.php.net/) - - -## SSL/TLS (HTTPS) - -We recommend setting up [HTTPS](https://en.wikipedia.org/wiki/HTTPS) (SSL/[TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security)) on your webserver for secure communication between clients and the server. - -### Let's Encrypt - -For public-facing web servers this can be done using free SSL/TLS certificates from [Let's Encrypt](https://en.wikipedia.org/wiki/Let's_Encrypt), a non-profit certificate authority provididing free certificates. - - - [How to secure Apache with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-debian-10) - - [How to secure Nginx with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-debian-10) - - [How To Use Certbot Standalone Mode to Retrieve Let's Encrypt SSL Certificates](https://www.digitalocean.com/community/tutorials/how-to-use-certbot-standalone-mode-to-retrieve-let-s-encrypt-ssl-certificates-on-debian-10). - -In short: - -```bash -# install certbot -sudo apt install certbot - -# stop your webserver if you already have one running -# certbot in standalone mode needs to bind to port 80 (only needed on initial generation) -sudo systemctl stop apache2 -sudo systemctl stop nginx - -# generate initial certificates -# Let's Encrypt ACME servers must be able to access your server! port forwarding and firewall must be properly configured -sudo certbot certonly --standalone --noninteractive --agree-tos --email "admin@shaarli.mydomain.org" -d shaarli.mydomain.org -# this will generate a private key and certificate at /etc/letsencrypt/live/shaarli.mydomain.org/{privkey,fullchain}.pem - -# restart the web server -sudo systemctl start apache2 -sudo systemctl start nginx -``` - -On apache `2.4.43+`, you can also delegate LE certificate management to [mod_md](https://httpd.apache.org/docs/2.4/mod/mod_md.html) [[1](https://www.cyberciti.biz/faq/how-to-secure-apache-with-mod_md-lets-encrypt-on-ubuntu-20-04-lts/)] in which case you don't need certbot and manual SSL configuration in virtualhosts. - -### Self-signed - -If you don't want to rely on a certificate authority, or the server can only be accessed from your own network, you can also generate self-signed certificates. Not that this will generate security warnings in web browsers/clients trying to access Shaarli: - -- [How To Create a Self-Signed SSL Certificate for Apache](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-debian-10) -- [How To Create a Self-Signed SSL Certificate for Nginx](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-on-debian-10) -- [How do I create my own Certificate Authority?](https://workaround.org/certificate-authority) - --------------------------------------------------------------------------------- - -## Examples - -The following examples assume a Debian-based operating system is installed. On other distributions you may have to adapt details such as package installation procedures, configuration file locations, and webserver username/group (`www-data` or `httpd` are common values). In these examples we assume that the web server and the `php-fpm` PHP interpreter are running as the same user, and the document root for your web server/virtualhost is at `/var/www/shaarli.mydomain.org/`,: - -```bash -# create the document root (replace with your own domain name) -sudo mkdir -p /var/www/shaarli.mydomain.org/ -``` - -You can install Shaarli at the root of your virtualhost, or in a subdirectory as well. See [Directory structure](dev/Development.md#directory-structure) - - -### Apache - -```bash -# Install apache + php-fpm -sudo apt update -sudo apt install apache2 libapache2-mod-md libapache2-mod-fcgid php8.2-fpm php8.2-mbstring php8.2-gd php8.2-intl php8.2-curl php8.2-gettext php8.2-ldap - -# Enable required modules -sudo a2enmod ssl # SSL/TLS certificates https://httpd.apache.org/docs/current/mod/mod_ssl.html -sudo a2enmod rewrite # REST API support https://httpd.apache.org/docs/current/mod/mod_rewrite.html -sudo a2enmod headers # custom HTTP headers - -# Edit the virtualhost configuration file with your favorite editor (replace the example domain name) -sudo nano /etc/apache2/sites-available/shaarli.mydomain.org.conf -``` - -```apache - - ServerName shaarli.mydomain.org - DocumentRoot /var/www/shaarli.mydomain.org/ - - # If using certbot or self-signed certificates: - # Redirect HTTP requests to HTTPS, except Let's Encrypt ACME challenge requests - RewriteEngine on - RewriteRule ^.well-known/acme-challenge/ - [L] - RewriteCond %{HTTP_HOST} =shaarli.mydomain.org - RewriteRule ^ https://shaarli.mydomain.org%{REQUEST_URI} [END,NE,R=permanent] - - -# If using mod_md: -MDomain shaarli.mydomain.org -MDCertificateAgreement accepted -MDContactEmail admin@shaarli.mydomain.org -MDPrivateKeys RSA 4096 - - - ServerName shaarli.mydomain.org - DocumentRoot /var/www/shaarli.mydomain.org/ - SSLEngine on - - # If using certbot: - SSLCertificateFile /etc/letsencrypt/live/shaarli.mydomain.org/fullchain.pem - SSLCertificateKeyFile /etc/letsencrypt/live/shaarli.mydomain.org/privkey.pem - - # If using self-signed certificates: - SSLEngine on - SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem - SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key - - # Optional, log PHP errors, useful for debugging - #php_flag log_errors on - #php_flag display_errors on - #php_value error_reporting 2147483647 - #php_value error_log /var/log/apache2/shaarli-php-error.log - - - SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost" - - - - # Required for .htaccess support - AllowOverride All - Require all granted - - - - DirectoryIndex index.html - - Require all granted - - - - - Require all denied - - - DirectoryIndex index.php - - - Require all granted - - - - # allow client-side caching of static files - Header set Cache-Control "max-age=2628000, public, must-revalidate, proxy-revalidate" - - - - Require all granted - - - # serve the Shaarli favicon from its custom location - Alias favicon.ico /var/www/shaarli.mydomain.org/images/favicon.ico - -``` - -```bash -# Enable the virtualhost -sudo a2ensite shaarli.mydomain.org - -# Restart the apache service -sudo systemctl restart apache2 -``` - -- [How to install the Apache web server](https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-debian-10) -- [Apache/PHP - error log per VirtualHost - StackOverflow](https://stackoverflow.com/questions/176/error-log-per-virtual-host) -- [Apache - PHP: php_value vs php_admin_value and the use of php_flag explained](https://ma.ttias.be/php-php_value-vs-php_admin_value-and-the-use-of-php_flag-explained/) -- [Server-side TLS (Apache) - Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS) -- [Apache 2.4 documentation](https://httpd.apache.org/docs/2.4/) -- [Apache mod_proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html) -- [Apache Reverse Proxy Request Headers](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#x-headers) - - -### Nginx - -```bash -# Install nginx and php-fpm -sudo apt install nginx php-fpm - -# Edit the virtualhost configuration file with your favorite editor -sudo nano /etc/nginx/sites-available/shaarli.mydomain.org -``` - -```nginx -server { - listen 80; - server_name shaarli.mydomain.org; - - # redirect all plain HTTP requests to HTTPS - return 301 https://shaarli.mydomain.org$request_uri; -} - -server { - # ipv4 listening port/protocol - listen 443 ssl http2; - # ipv6 listening port/protocol - listen [::]:443 ssl http2; - server_name shaarli.mydomain.org; - root /var/www/shaarli.mydomain.org; - - # log file locations - # combined log format prepends the virtualhost/domain name to log entries - access_log /var/log/nginx/access.log combined; - error_log /var/log/nginx/error.log; - - # paths to private key and certificates for SSL/TLS - ssl_certificate /etc/ssl/shaarli.mydomain.org.crt; - ssl_certificate_key /etc/ssl/private/shaarli.mydomain.org.key; - - # Let's Encrypt SSL settings from https://github.com/certbot/certbot/blob/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf - ssl_session_cache shared:le_nginx_SSL:10m; - ssl_session_timeout 1440m; - ssl_session_tickets off; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # increase the maximum file upload size if needed: by default nginx limits file upload to 1MB (413 Entity Too Large error) - client_max_body_size 100m; - - # relative path to shaarli from the root of the webserver - # if shaarli is installed in a subdirectory of the main domain, edit the location accordingly - location / { - # default index file when no file URI is requested - index index.php; - try_files _ /index.php$is_args$args; - } - - location ~ (index)\.php$ { - try_files $uri =404; - # slim API - split URL path into (script_filename, path_info) - fastcgi_split_path_info ^(.+\.php)(/.+)$; - # pass PHP requests to PHP-FPM - fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; - fastcgi_index index.php; - include fastcgi.conf; - } - - location ~ /doc/html/ { - default_type "text/html"; - try_files $uri $uri/ $uri.html =404; - } - - location = /favicon.ico { - # serve the Shaarli favicon from its custom location - alias /var/www/shaarli/images/favicon.ico; - } - - # allow client-side caching of static files - location ~* \.(?:ico|css|js|gif|jpe?g|png|ttf|oet|woff2?)$ { - expires max; - add_header Cache-Control "public, must-revalidate, proxy-revalidate"; - # HTTP 1.0 compatibility - add_header Pragma public; - } -} -``` - -```bash -# enable the configuration/virtualhost -sudo ln -s /etc/nginx/sites-available/shaarli.mydomain.org /etc/nginx/sites-enabled/shaarli.mydomain.org -# reload nginx configuration -sudo systemctl reload nginx -``` - -- [How to install the Nginx web server](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-debian-10) -- [Nginx Beginner's guide](https://nginx.org/en/docs/beginners_guide.html) -- [Nginx documentation](https://nginx.org/en/docs/) -- [Nginx ngx_http_fastcgi_module](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) -- [Nginx Pitfalls](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/) -- [Server-side TLS (Nginx) - Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS) - - -## Reverse proxies - -If Shaarli is hosted on a server behind a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) (i.e. there is a proxy server between clients and the web server hosting Shaarli), configure it accordingly. See [Reverse proxy](Reverse-proxy.md) configuration. - - -## Using Shaarli without URL rewriting - -By default, Shaarli uses Slim framework's URL, which requires URL rewriting. - -If you can't use URL rewriting for any reason (not supported by your web server, shared hosting, etc.), you *can* use Shaarli without URL rewriting. - -You just need to prefix your URL by `/index.php/`. Example: instead of accessing `https://shaarli.mydomain.org/`, use `https://shaarli.mydomain.org/index.php/`. - -**Recommended:** -* after installation, in the configuration page, set your header link to `/index.php/`. -* in your configuration file `config.json.php` set `general.root_url` to `https://shaarli.mydomain.org/index.php/`. - - -## Allow import of large browser bookmarks export - -Web browser bookmark exports can be large due to the presence of base64-encoded images and favicons/long subfolder names. Edit the PHP configuration file. - -- Apache: `/etc/php//apache2/php.ini` -- Nginx + PHP-FPM: `/etc/php//fpm/php.ini` (in addition to `client_max_body_size` in the [Nginx configuration](#nginx)) - -```ini -[...] -# (optional) increase the maximum file upload size: -post_max_size = 100M -[...] -# (optional) increase the maximum file upload size: -upload_max_filesize = 100M -``` - -To verify PHP settings currently set on the server, create a `phpinfo.php` in your webserver's document root - -```bash -# example -echo '' | sudo tee /var/www/shaarli.mydomain.org/phpinfo.php -#give read-only access to this file to the webserver user -sudo chown www-data:root /var/www/shaarli.mydomain.org/phpinfo.php -sudo chmod 0400 /var/www/shaarli.mydomain.org/phpinfo.php -``` - -Access the file from a web browser (eg. and look at the _Loaded Configuration File_ and _Scan this dir for additional .ini files_ entries - -It is recommended to remove the `phpinfo.php` when no longer needed as it publicly discloses details about your webserver configuration. - - -## Robots and crawlers - -To opt-out of indexing your Shaarli instance by search engines, create a `robots.txt` file at the root of your virtualhost: - -``` -User-agent: * -Disallow: / -``` - -By default Shaarli already disallows indexing of your local copy of the documentation by default, using `` HTML tags. Your Shaarli instance may still be indexed by various robots on the public Internet, that do not respect this header or the robots standard. - -- [Robots exclusion standard](https://en.wikipedia.org/wiki/Robots_exclusion_standard) -- [Introduction to robots.txt](https://developers.google.com/search/docs/crawling-indexing/robots/intro?hl=en) -- [Robots meta tag, data-nosnippet, and X-Robots-Tag specifications](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag) -- [About robots.txt](https://www.robotstxt.org) -- [About the robots META tag](https://www.robotstxt.org/meta.html) - - -## Fail2ban - -[fail2ban](https://github.com/fail2ban/fail2ban) is an intrusion prevention framework that reads server (Apache, SSH, etc.) and uses `iptables` profiles to block brute-force attempts. You need to create a filter to detect shaarli login failures in logs, and a jail configuation to configure the behavior when failed login attempts are detected: - -```ini -# /etc/fail2ban/filter.d/shaarli-auth.conf -[INCLUDES] -before = common.conf -[Definition] -failregex = \s-\s\s-\sLogin failed for user.*$ -ignoreregex = -``` - -```ini -# /etc/fail2ban/jail.local -[shaarli-auth] -enabled = true -port = https,http -filter = shaarli-auth -logpath = /var/www/shaarli.mydomain.org/data/log.txt -# allow 3 login attempts per IP address -# (over a period specified by findtime = in /etc/fail2ban/jail.conf) -maxretry = 3 -# permanently ban the IP address after reaching the limit -bantime = -1 -``` - -Then restart the service: `sudo systemctl restart fail2ban` - - -## What next? - -[Shaarli installation](Installation.md) diff --git a/doc/md/Shaarli-configuration.md b/doc/md/Shaarli-configuration.md deleted file mode 100644 index a7cfb218..00000000 --- a/doc/md/Shaarli-configuration.md +++ /dev/null @@ -1,235 +0,0 @@ -# Shaarli configuration - -Once your Shaarli instance is installed, the file `data/config.json.php` is generated: - -- it contains all settings in JSON format, and can be edited to customize values -- it defines which [plugins](Plugins.md) are enabled -- its values override those defined in `index.php` -- it is wrapped in a PHP comment so that its contents are never served by the web server, regardless of configuration - -**Do not edit configuration options in index.php! Your changes would be lost.** - -## Tools menu - -Some settings can be configured directly from a web browser by accesing the `Tools` menu. Values are read/written to/from the configuration file. - -![](https://i.imgur.com/boaaibC.png) - -### LDAP - -- **host**: LDAP host used for user authentication -- **dn**: user DN template (`sprintf` format, `%s` being replaced by user login) - -## Configuration file example - -``` -", - "hash": "", - "salt": "" - }, - "security": { - "ban_after": 4, - "session_protection_disabled": false, - "ban_duration": 1800, - "trusted_proxies": [ - "1.2.3.4", - "5.6.7.8" - ], - "allowed_protocols": [ - "ftp", - "ftps", - "magnet" - ] - }, - "resources": { - "data_dir": "data", - "config": "data\/config.php", - "datastore": "data\/datastore.php", - "ban_file": "data\/ipbans.php", - "updates": "data\/updates.txt", - "log": "data\/log.txt", - "update_check": "data\/lastupdatecheck.txt", - "raintpl_tmp": "tmp\/", - "raintpl_tpl": "tpl\/", - "thumbnails_cache": "cache", - "page_cache": "pagecache" - }, - "general": { - "check_updates": true, - "rss_permalinks": true, - "links_per_page": 20, - "default_private_links": true, - "check_updates_branch": "stable", - "check_updates_interval": 86400, - "download_max_size": 4194304, - "download_timeout": 30, - "enabled_plugins": [ - "markdown", - "wallabag", - "archiveorg" - ], - "timezone": "Europe\/Paris", - "title": "My Shaarli", - "header_link": "?" - "tags_separator": " " - }, - "dev": { - "debug": false, - } - "extras": { - "show_atom": false, - "hide_public_links": false, - "hide_timestamps": false, - "open_shaarli": false, - }, - "formatter": "markdown", - "updates": { - "check_updates": true, - "check_updates_branch": "stable", - "check_updates_interval": 86400 - }, - "feed": { - "rss_permalinks": true, - "show_atom": false - }, - "privacy": { - "default_private_links": true, - "hide_public_links": false, - "force_login": false, - "hide_timestamps": false, - "remember_user_default": true - }, - "thumbnails": { - "width": 125, - "height": 90, - "mode": "common" - }, - "plugins": { - "WALLABAG_URL": "https://demo.wallabag.org", - "WALLABAG_VERSION": "1" - }, - "translation": { - "language": "fr", - "mode": "php", - "extensions": { - "demo": "plugins/demo_plugin/languages/" - } - }, - "ldap": { - "host": "ldap://localhost", - "dn": "uid=%s,ou=people,dc=example,dc=org" - } -} ?> -``` - -## Settings - -### Credentials - -_These settings should not be edited_ - -- **login**: Login username. -- **hash**: Generated password hash. -- **salt**: Password salt. - -### General - -- **title**: Shaarli's instance title. -- **header_link**: Link to the homepage. -- **links_per_page**: Number of Shaares displayed per page. -- **timezone**: See [the list of supported timezones](https://www.php.net/manual/en/timezones.php). -- **enabled_plugins**: List of enabled plugins. -- **default_note_title**: Default title of a new note. -- **download_max_size:**: Maximum number of bytes to download when retrieveing page content/metadata. -- **download_timeout:**: Network timeout (in seconds) when retrieveing page content/metadata. -- **enable_async_metadata** (boolean): Retrieve external bookmark metadata asynchronously to prevent bookmark creation slowdown. -- **retrieve_description** (boolean): If set to true, for every new Shaare Shaarli will try to retrieve the description and keywords from the HTML meta tags. -- **root_url**: Overrides automatic discovery of Shaarli instance's URL (e.g.) `https://sub.domain.tld/shaarli-folder/`. -- **tags_separator**: Defines your tags separator (default: whitespace). - -### Security - -- **session_protection_disabled**: Disable session cookie hijacking protection (not recommended). - It might be useful if your IP adress often changes. -- **ban_after**: Failed login attempts before being IP banned. -- **ban_duration**: IP ban duration in seconds. -- **open_shaarli**: Anyone can add a new Shaare while logged out if enabled. -- **trusted_proxies**: List of trusted IP which won't be banned after failed login attemps. Useful if Shaarli is behind a reverse proxy. -- **allowed_protocols**: List of allowed protocols in shaare URLs or markdown-rendered descriptions. Useful if you want to store `javascript:` links (bookmarklets) or `file:///` URIs in Shaarli (default: `["ftp", "ftps", "magnet"]`). - -### Formatter - -Single string value. Default available: - - - `default`: supports line breaks, URL and hashtag auto-links. - - `markdown`: supports [Markdown](https://daringfireball.net/projects/markdown/syntax). - - `markdownExtra`: adds [extra](https://michelf.ca/projects/php-markdown/extra/) flavor to Markdown. - -### Formatter Settings - -Additional settings applied to formatters. - -#### default - - - **autolink**: boolean to enable or disable automatic linkification of URL and hashtags. - -### Resources - -- **data_dir**: Data directory. -- **datastore**: Shaarli's Shaares database file path. -- **history**: Shaarli's operation history file path. -- **updates**: File path for the ran updates file. -- **log**: Log file path. -- **update_check**: Last update check file path. -- **raintpl_tpl**: Templates directory. -- **raintpl_tmp**: Template engine cache directory. -- **thumbnails_cache**: Thumbnails cache directory. -- **page_cache**: Shaarli's internal cache directory. -- **ban_file**: Banned IP file path. - -### Translation - -- **language**: translation language (also see [Translations](dev/Development.md#translations)) - - **auto** (default): The translation language is chosen from the browser locale. - It means that the language can be different for 2 different visitors depending on their locale. - - **en**: Use the English translation. - - **fr**: Use the French translation. -- **mode**: - - **auto** or **php** (default): Use the PHP implementation of gettext (slower) - - **gettext**: Use PHP builtin gettext extension - (faster, but requires `php-gettext` to be installed and to reload the web server on update) -- **extension**: Translation extensions for custom themes or plugins. -Must be an associative array: `translation domain => translation path`. - -### Updates - -- **check_updates**: Enable or disable update check to the git repository. -- **check_updates_branch**: Git branch used to check updates (e.g. `stable` or `master`). -- **check_updates_interval**: Look for new version every N seconds (default: every day). - -### Privacy - -- **default_private_links**: Check the private checkbox by default for every new Shaare. -- **hide_public_links**: All Shaares are hidden while logged out. -- **force_login**: if **hide_public_links** and this are set to `true`, all anonymous users are redirected to the login page. -- **hide_timestamps**: Timestamps are hidden. -- **remember_user_default**: Default state of the login page's *remember me* checkbox - - `true`: checked by default, `false`: unchecked by default - -### Feed - -- **rss_permalinks**: Enable this to redirect RSS links to Shaarli's permalinks instead of shaared URL. -- **show_atom**: Display ATOM feed button. - -### Thumbnails - -- **width:** width of generated thumbnails, in pixels -- **height:** height of generated thumbnails, in pixels -- **mode:** enable thumbnails for `all` shaares, or `common` media hosts, or `none`. - -## Plugins configuration - -See [Plugins](Plugins.md) diff --git a/doc/md/Troubleshooting.md b/doc/md/Troubleshooting.md deleted file mode 100644 index 67540fae..00000000 --- a/doc/md/Troubleshooting.md +++ /dev/null @@ -1,220 +0,0 @@ -# Troubleshooting - -First of all, ensure that both the [web server](Server-configuration.md) and [Shaarli](Shaarli-configuration.md) are correctly configured. - - -## Login - -### I forgot my password! - -Delete the file `data/config.json.php` and display the page again. You will be asked for a new login/password. - -### I'm locked out - Login bruteforce protection - -Login form is protected against brute force attacks: 4 failed logins will ban the IP address from login for 30 minutes. Banned IPs can still browse Shaares. - -- To remove the current IP bans, delete the file `data/ipbans.php` -- To list all login attempts, see `data/log.txt` (succesful/failed logins, bans/lifted bans) - --------------------------------------- - -## Browser issues - -### Redirection issues (HTTP Referer) - -Shaarli relies on `HTTP_REFERER` for some functions (like redirects and clicking on tags). If you have disabled or altered/spoofed [HTTP referers](https://en.wikipedia.org/wiki/HTTP_referer) in your browser, some features of Shaarli may not work as expected (depending on configuration and installed plugins), notably redirections between pages. - -Firefox Referer settings are available by browsing `about:config` and are documented [here](https://wiki.mozilla.org/Security/Referrer). `network.http.referer.spoofSource = true` in particular is known to break some functionality in Shaarli. - - -### Firefox, localhost and redirections - -`localhost` is not a proper Fully Qualified Domain Name (FQDN); if Firefox has been set up to spoof referers, or only accept requests from the same base domain/host, -Shaarli redirections will not work properly. To solve this, assign a local domain to your host, e.g. `localhost.lan` in your [hosts file](https://en.wikipedia.org/wiki/Hosts_(file)) and browse Shaarli at http://localhost.lan/. - ------------------------------------------ - -## Hosting problems - -### Old PHP versions - -- On hosts (such as **free.fr**) which only support PHP 5.6, Shaarli [v0.10.4](https://github.com/shaarli/Shaarli/releases/tag/v0.10.4) is the maximum supported version. At the root of your webspace create a `sessions` directory and a `.htaccess` file containing: - -```apacheconf - -php56 1 - - -Order allow,deny -Deny from all -Satisfy all - -Options -Indexes -``` - -- If you have an error such as: `Parse error: syntax error, unexpected '=', expecting '(' in /links/index.php on line xxx`, it means that your host is using PHP 4, not PHP 5. Shaarli requires PHP 5.1. Try changing the file extension to `.php5` -- On **1and1** : If you add the link from the page (and not from the bookmarklet), Shaarli will no be able to get the title of the page. You will have to enter it manually. (Because they have disabled the ability to download a file through HTTP). -- If you have the error `Warning: file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration in /…/index.php on line xxx`, it means that your host has disabled the ability to fetch a file by HTTP in the php config (Typically in 1and1 hosting). Bad host. Change host. Or comment the following lines: - -```php -//list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive. -// FIXME: Decode charset according to charset specified in either 1) HTTP response headers or 2) in html -//if (strpos($status,'200 OK')) $title=html_extract_title($data); -``` - -- On hosts (such as **free.fr**) which forbid outgoing HTTP requests, some thumbnails will not work. -- On hosts (such as **free.fr**) which limit the number of FTP connections, setup your FTP client accordingly (else some files may be missing after upload). -- On **lost-oasis**, RSS doesn't work correctly, because of this message at the begining of the RSS/ATOM feed : ``. To fix this, remove this message from `php-include/prepend.php` - - -### Dates are not properly formatted - -Shaarli tries to sniff the language of the browser (using `HTTP_ACCEPT_LANGUAGE` headers) -and choose a date format accordingly. But Shaarli can only use the date formats -(and more generally speaking, the locales) provided by the webserver. -So even if you have a browser in French, you may end up with dates in US format -(it's the case on sebsauvage.net :-( ) - -### My session expires! I can't stay logged in - -This can be caused by several things: - -- Your php installation may not have a proper directory setup for session files. (eg. on Free.fr you need to create a `session` directory on the root of your website.) You may need to create the session directory of set it up. -- Most hosts regularly clean the temporary and session directories. Your host may be cleaning those directories too aggressively (eg.OVH hosts), forcing an expire of the session. You may want to set the session directory in your web root. (eg. Create the `sessions` subdirectory and add `ini_set('session.save_path', $_SERVER['DOCUMENT_ROOT'].'/../sessions');`. Make sure this directory is not browsable !) -- If your IP address changes during surfing, Shaarli will force expire your session for security reasons (to prevent session cookie hijacking). This can happen when surfing from WiFi or 3G (you may have switched WiFi/3G access point), or in some corporate/university proxies which use load balancing (and may have proxies with several external IP addresses). -- Some browser addons may interfer with HTTP headers (ipfuck/ipflood/GreaseMonkey…). Try disabling those. -- You may be using OperaTurbo or OperaMini, which use their own proxies which may change from time to time. -- If you have another application on the same webserver where Shaarli is installed, these application may forcefully expire php sessions. - - -### Old apache versions, Internal Server Error - -If you hosting provider only provides apache 2.2 and no support for `mod_version`, `.htaccess` files may cause 500 errors (Internal Server Error). See [this workaround](https://github.com/shaarli/Shaarli/issues/1196#issuecomment-412271085). - - -### Sessions do not seem to work correctly on your server - -Follow the instructions in the error message. Make sure you are accessing shaarli via a direct IP address or a proper hostname. If you have **no dots** in the hostname (e.g. `localhost` or `http://my-webserver/shaarli/`), some browsers will not store cookies at all (this respects the [HTTP cookie specification](https://curl.se/rfc/cookie_spec.html)). - - -### Error 406 "Not acceptable" - -If attempting to save a link results in a `Not acceptable` error (HTTP status code of `406`), it is likely due to strict settings for `mod_security` (a module used with Apache). This cannot be mitigated by reconfiguring Shaarli itself, and must be dealt with at the level of the underlying web server instead. - -On some shared hosting services (such as **Bluehost**), `mod_security` is enabled by default, so the recommended course of action is to get in touch with the helpdesk and ask them to disable `mod_security` for your domain, sub-domain, or the subdirectory where Shaarli is installed. Ideally, you want to narrow it down to a very specific location, so as to continue reaping the benefits of `mod_security` elsewhere on your domain. If asked for specific, you can refer support staff to this [issue](https://github.com/shaarli/Shaarli/issues/1736), where more technical details are available. - - -### Timeout during long-lasting operations - -You may need to adjust timeouts to larger values in your [reverse proxy configuration](Reverse-proxy.md) if you're getting `504 Gateway Timeout` errors during long-lasting operations (like importing many bookmarks from HTML, or batch deleting tags) on slow hardware. The PHP setting `max_execution_time` may also need to be adjusted for your specific setup. See issues [#1854](https://github.com/shaarli/Shaarli/issues/1854) and [#1910](https://github.com/shaarli/Shaarli/issues/1910). - - -### Automatic title retrieval fails - -When bookmarking a page using the `+ Shaare > Add Link` dialog, Shaarli cannot retrieve the page `` HTML attribute if it is set by javascript at page load (e.g. Youtube videos). You can work around this limitation by using a [Browser extension](Community-and-related-software.md) or the [Bookmarklet](#Usage). - - ----------------------------------------------------------- - -## Upgrades - -### You must specify an integer as a key - -In `v0.8.1` we changed how Shaare keys are handled (from timestamps to incremental integers). Take a look at `data/updates.txt` content. - - -### `updates.txt` contains `updateMethodDatastoreIds` - -Try to delete it and refresh your page while being logged in. - -### `updates.txt` doesn't exist or doesn't contain `updateMethodDatastoreIds` - -1. Create `data/updates.txt` if it doesn't exist -2. Paste this string in the update file `;updateMethodRenameDashTags;` -3. Login to Shaarli -4. Delete the update file -5. Refresh - - - --------------------------------------------------------- - -## Import/export - -### Importing shaarli data to Firefox - -- In Firefox, open the bookmark manager (`Bookmarks menu > Show all bookmarks` or `Ctrl+Shift+B`), select `Import and Backup > Import bookmarks in HTML format` -- Make sure the `Prepend note permalinks with this Shaarli instance's URL` box is checked when exporting, so that text-only/notes Shaares still point to the Shaarli instance you exported them from. -- Depending on the number of bookmarks, the import can take some time. - -You may be interested in these Firefox addons to manage bookmarks imported from Shaarli - -- [Bookmark Dupes](https://addons.mozilla.org/en-US/firefox/addon/bookmark-dupes/) - provides an easy way to deduplicate your bookmarks - -### Diigo - -If you export your bookmark from Diigo, make sure you use the Delicious export, not the Netscape export. (Their Netscape export is broken, and they don't seem to be interested in fixing it.) - -### Mister Wong - -See [this issue](https://github.com/sebsauvage/Shaarli/issues/146) for import tweaks. - -### SemanticScuttle - -To correctly import the tags from a [SemanticScuttle](https://semanticscuttle.sourceforge.net/) HTML export, edit the HTML file before importing and replace all occurences of `tags=` (lowercase) to `TAGS=` (uppercase). - -### Scuttle - -Shaarli cannot import data directly from [Scuttle](https://github.com/scronide/scuttle). - -However, you can use the third-party [scuttle-to-shaarli](https://github.com/q2apro/scuttle-to-shaarli) -tool to export the Scuttle database to the Netscape HTML format compatible with the Shaarli importer. - -### Refind.com - -You can use the third-party tool [Derefind](https://github.com/ShawnPConroy/Derefind) to convert refind.com bookmark exports to a format that can be imported into Shaarli. - - -------------------------------------------------------- - -## Other - -### The bookmarklet doesn't work - -Some websites may disallow usage of bookmarklets through [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). Unfortunately, there is nothing Shaarli can do about it ([1](https://github.com/shaarli/Shaarli/issues/196), [2](https://bugzilla.mozilla.org/show_bug.cgi?id=866522), [3](https://bugs.chromium.org/p/chromium/issues/detail?id=233903). - -Under Opera, you can't drag'n drop the button: You have to right-click on it and add a bookmark to your personal toolbar. - - -### Changing the timestamp for a shaare - -- Look for `<input type="hidden" name="lf_linkdate" value="{$link.linkdate}">` in `tpl/editlink.tpl` (line 14) -- Replace `type="hidden"` with `type="text"` from this line -- A new date/time field becomes available in the edit/new Shaare dialog. -- You can set the timestamp manually by entering it in the format `YYYMMDD_HHMMS`. - -### Clearing Shaarli caches - -For debugging purposes: - -```bash -# clear raintpl cache and temporary files -find /var/www/links/cache/ /var/www/links/pagecache/ /var/www/links/tmp/ -type f -exec rm -v '{}' \; -# if you have a php accelerator such as php-apcu, restart the webserver -sudo systemctl restart apache2 -``` - -------------------------------------------------------- - -## Support - -If the solutions above did not help, please: - -- Come and ask question on the [Gitter chat](https://app.gitter.im/#/room/#shaarli_Shaarli:gitter.im) -- Search for [issues](https://github.com/shaarli/Shaarli/issues) and [Pull Requests](https://github.com/shaarli/Shaarli/pulls) - - if you find one that is related to the issue, feel free to comment and provide additional details (host/Shaarli setup...) - - check issues labeled [`feature`](https://github.com/shaarli/Shaarli/labels/feature), [`enhancement`](https://github.com/shaarli/Shaarli/labels/enhancement), and [`plugin`](https://github.com/shaarli/Shaarli/labels/plugin) if you would like a feature added to Shaarli. - - else, [open a new issue](https://github.com/shaarli/Shaarli/issues/new), and provide information about the problem: - - _what happens?_ - display glitches, invalid data, security flaws... - - _what is your configuration?_ - OS, server version, activated extensions, web browser... - - _is it reproducible?_ diff --git a/doc/md/Upgrade-and-migration.md b/doc/md/Upgrade-and-migration.md deleted file mode 100644 index 2f14baf9..00000000 --- a/doc/md/Upgrade-and-migration.md +++ /dev/null @@ -1,203 +0,0 @@ -# Upgrade and migration - -## Note your current version - -If anything goes wrong, it's important for us to know which version you're upgrading from. -The current version is present in the `shaarli_version.php` file. - - -## Backup your data - -Shaarli stores all user data and [configuration](Shaarli-configuration.md) under the `data` directory. [Backup](Backup-and-restore.md) this repository _before_ upgrading Shaarli. You will need to restore it after the following upgrade steps. - -```bash -sudo cp -r /var/www/shaarli.mydomain.org/data ~/shaarli-data-backup -``` - -## Upgrading from ZIP archives - -If you installed Shaarli from a [release ZIP archive](Installation.md#from-release-zip): - -```bash -# Download the archive to the server, and extract it -cd ~ -wget https://github.com/shaarli/Shaarli/releases/download/v0.X.Y/shaarli-v0.X.Y-full.zip -unzip shaarli-v0.X.Y-full.zip - -# overwrite your Shaarli installation with the new release **All data will be lost, see _Backup your data_ above.** -sudo rsync -avP --delete Shaarli/ /var/www/shaarli.mydomain.org/ - -# restore file permissions as described on the installation page -sudo chown -R root:www-data /var/www/shaarli.mydomain.org -sudo chmod -R g+rX /var/www/shaarli.mydomain.org -sudo chmod -R g+rwX /var/www/shaarli.mydomain.org/{cache/,data/,pagecache/,tmp/} - -# restore backups of the data directory -sudo cp -r ~/shaarli-data-backup/* /var/www/shaarli.mydomain.org/data/ - -# If you use gettext mode for translations (not the default), reload your web server. -sudo systemctl restart apache2 -sudo systemctl restart nginx -``` - -If you don't have shell access (eg. on shared hosting), backup the shaarli data directory, download the ZIP archive locally, extract it, upload it to the server using file transfer, and restore the data directory backup. - -Access your fresh Shaarli installation from a web browser; the configuration and data store will then be automatically updated, and new settings added to `data/config.json.php` (see [Shaarli configuration](Shaarli-configuration.md) for more details). - - -## Upgrading from Git - -If you have installed Shaarli [from sources](Installation.md#from-sources): - -```bash -# pull new changes from your local clone -cd /var/www/shaarli.mydomain.org/ -sudo git pull - -# update PHP dependencies (Shaarli >= v0.8) -sudo composer install --no-dev - -# update translations (Shaarli >= v0.9.2) -sudo make translate - -# If you use translations in gettext mode (not the default), reload your web server. -sudo systemctl reload apache -sudo systemctl reload nginx - -# update front-end dependencies (Shaarli >= v0.10.0) -sudo make build_frontend - -# restore file permissions as described on the installation page -sudo chown -R root:www-data /var/www/shaarli.mydomain.org -sudo chmod -R g+rX /var/www/shaarli.mydomain.org -sudo chmod -R g+rwX /var/www/shaarli.mydomain.org/{cache/,data/,pagecache/,tmp/} -``` - -Access your fresh Shaarli installation from a web browser; the configuration and data store will then be automatically updated, and new settings added to `data/config.json.php` (see [Shaarli configuration](Shaarli-configuration.md) for more details). - ---------------------------------------------------------------- - -## Migrating and upgrading from Sebsauvage's repository - -If you have installed Shaarli from [Sebsauvage's original Git repository](https://github.com/sebsauvage/Shaarli), you can use [Git remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) to update your working copy. - -The following guide assumes that: - -- you have a basic knowledge of Git [branching](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) and [remote repositories](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) -- the default remote is named `origin` and points to Sebsauvage's repository -- the current branch is `master` - - if you have personal branches containing customizations, you will need to [rebase them](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) after the upgrade; beware though, a lot of changes have been made since the community fork has been created, so things are very likely to break! -- the working copy is clean: - - no versioned file has been locally modified - - no untracked files are present - -### Step 0: show repository information - -```bash -$ cd /path/to/shaarli - -$ git remote -v -origin https://github.com/sebsauvage/Shaarli (fetch) -origin https://github.com/sebsauvage/Shaarli (push) - -$ git branch -vv -* master 029f75f [origin/master] Update README.md - -$ git status -On branch master -Your branch is up-to-date with 'origin/master'. -nothing to commit, working directory clean -``` - -### Step 1: update Git remotes - -``` -$ git remote rename origin sebsauvage -$ git remote -v -sebsauvage https://github.com/sebsauvage/Shaarli (fetch) -sebsauvage https://github.com/sebsauvage/Shaarli (push) - -$ git remote add origin https://github.com/shaarli/Shaarli -$ git fetch origin - -remote: Counting objects: 3015, done. -remote: Compressing objects: 100% (19/19), done. -remote: Total 3015 (delta 446), reused 457 (delta 446), pack-reused 2550 -Receiving objects: 100% (3015/3015), 2.59 MiB | 918.00 KiB/s, done. -Resolving deltas: 100% (1899/1899), completed with 48 local objects. -From https://github.com/shaarli/Shaarli - * [new branch] master -> origin/master - * [new branch] stable -> origin/stable -[...] - * [new tag] v0.6.4 -> v0.6.4 - * [new tag] v0.7.0 -> v0.7.0 -``` - -### Step 2: use the stable community branch - -```bash -$ git checkout origin/stable -b stable -Branch stable set up to track remote branch stable from origin. -Switched to a new branch 'stable' - -$ git branch -vv - master 029f75f [sebsauvage/master] Update README.md -* stable 890afc3 [origin/stable] Merge pull request #509 from ArthurHoaro/v0.6.5 -``` - -Shaarli >= `v0.8.x`: install/update third-party PHP dependencies using [Composer](https://getcomposer.org/): - -```bash -$ composer install --no-dev - -Loading composer repositories with package information -Updating dependencies - - Installing shaarli/netscape-bookmark-parser (v1.0.1) - Downloading: 100% -``` - -Shaarli >= `v0.9.2` supports translations: - -```bash -$ make translate -``` - -If you use translations in gettext mode, reload your web server. - -Shaarli >= `v0.10.0` manages its front-end dependencies with nodejs. You need to install [yarn](https://classic.yarnpkg.com/en/docs/install/): - -```bash -$ make build_frontend -``` - -Optionally, you can delete information related to the legacy version: - -```bash -$ git branch -D master -Deleted branch master (was 029f75f). - -$ git remote remove sebsauvage - -$ git remote -v -origin https://github.com/shaarli/Shaarli (fetch) -origin https://github.com/shaarli/Shaarli (push) - -$ git gc -Counting objects: 3317, done. -Delta compression using up to 8 threads. -Compressing objects: 100% (1237/1237), done. -Writing objects: 100% (3317/3317), done. -Total 3317 (delta 2050), reused 3301 (delta 2034)to -``` - -### Step 3: configuration - -After migrating, access your fresh Shaarli installation from a web browser; the -configuration will then be automatically updated, and new settings added to -`data/config.json.php` (see [Shaarli configuration](Shaarli-configuration.md) for more -details). - -## Troubleshooting - -If the solutions provided here don't work, see [Troubleshooting](Troubleshooting.md) and/or open an issue specifying which version you're upgrading from and to. - diff --git a/doc/md/Usage.md b/doc/md/Usage.md deleted file mode 100644 index d6344039..00000000 --- a/doc/md/Usage.md +++ /dev/null @@ -1,116 +0,0 @@ -# Usage - -## Features - -For any item posted to Shaarli (called a _Shaare_), you can customize the following aspects: - -- URL to link to -- Title -- Free-text description -- Tags -- Public/private status - - -### Adding/editing Shaares - -While logged in to your Shaarli, you can add, edit or delete Shaares: - -- Using the **+Shaare** button: enter the URL you want to share, click `Add link`, fill in the details of your Shaare, and `Save` -- Using the [Bookmarklet](https://en.wikipedia.org/wiki/Bookmarklet): drag the `✚Shaare link` button from the `Tools` page to your browser's bookmarks bar, click it to share the current page. -- Using [apps and browser addons](Community-and-related-software.md#mobile-apps) -- Using the [REST API](https://shaarli.github.io/api-documentation/) -- Any Shaare can edited by clicking its ![](images/edit_icon.png) `Edit` button. - -The `Shaare a new link` dialog also allows you to create multiple bookmarks at once (unfold the `bulk creation` section and add one URL per line). - -### Tags - -Tags can be be used to organize and categorize your Shaares: - -- You can rename, merge and delete tags from the _Tools_ menu or the [tag cloud/list](#tag-cloud) -- Tags are auto-completed (from the list of existing tags) in all dialogs -- Tags can be combined with text in [search](#search) queries - - -### Public/private Shaares - -Additional filter buttons can be found at the top left of the Shaare list **only when logged in**: - -- **Only show private Shaares:** Private shares can be searched by clicking the `only show private links` toggle button top left of the Shaares list (only when logged in) - - -### Permalinks - -Permalinks are fixed, short links attached to each Shaare. Editing a Shaare will not change it's permalink, each permalink always points to the latest revision of a Shaare. - - -### Text-only (note) Shaares - -Shaarli can be used as a minimal blog, notepad, pastebin...: While adding or editing a Shaare, leave the URL field blank to create a text-only ("note") post. This allows you to post any kind of text content, such as blog articles, private or public notes, snippets... There is no character limit! You can access your post from its permalink. - - -### Search - -- **Plain text search:** Use `Search text` to search in all fields of all Shaares (Title, URL, Description...). Use double-quotes (example `"exact search"`) to search for the exact expression. -- **Tags search:** `Filter by tags` allow only displaying Shaares tagged with one or multiple tags (use space to separate tags). A plus sign `+` is optional and will restrict suggested tags to only those starting with the string (example: `pr` will hint `apron` and `printer` but `+pr` will only hint printer). -- **Hidden tags:** tags starting with a dot `.` (example `.secret`) are private. They can only be seen and searched when logged in. -- **Exclude text/tags:** Use the `-` operator before a word or tag to exclude Shaares matching this word from search results (`NOT` operator). -- **Optional tags:** Use the `~` operator before multiple tags to search for any one of them (`OR` operator). Note that the OR operator only works if there are multiple tags with a tilde. A search for `webdesign ~ai ~youtube` search would match `webdesign AND (ai OR youtube)`. A search for `webdesign ~youtube` is equivalent to `+webdesign +youtube`. -- **Wildcard tag search:** An asterisk (`*`) can be used as a wildcard and will match any number of characters. Wildcards can appear in the middle of a search term or at the end (example: pro\*in\* will match programming and protein). -- **Untagged links:** Shaares without tags can be searched by clicking the `untagged` toggle button top left of the Shaares list (only when logged in). - -Both exclude patterns and exact searches can be combined with normal searches (example `"exact search" term otherterm -notthis "very exact" stuff -notagain`). Only AND (and NOT) text search is currently supported. - -Active search terms are displayed on top of the link list. To remove terms/tags from the current search, click the `x` next to any of them, or simply clear text/tag search fields. - - -### Tag cloud - -The `Tag cloud` page displays a "cloud" or list view of all tags in your Shaarli (most frequently used tags are displayed with a bigger font size) - - -- **Tags list:** click on `Most used` or `Alphabetical` to display tags as a list. You can also edit/delete tags for this page. -- Click on any tag to search all Shaares matching this tag. -- **Filtering the tag cloud/list:** Click on the counter next to a tag to show other tags of Shaares with this tag. Repeat this any number of times to further filter the tag cloud. Click `List all links with those tags` to display Shaares matching your current tag filter set. - - - -### RSS feeds - -RSS/ATOM feeds feeds are available (in ATOM with `/feed/atom` and RSS with `/feed/rss`) - -- **Filtering RSS feeds:** RSS feeds and picture wall can also be restricted to only return items matching a text/tag search. For example, search for `photography` (text or tags) in Shaarli, then click the `RSS Feed` button. A feed with only matching results is displayed. -- Add the `&nb` parameter in feed URLs to specify the number of Shaares you want in a feed (default if not specified: `50`). The keyword `all` is available if you want everything. -- Add the `&permalinks` parameter in feed URLs to point permalinks to the corresponding Shaarli entry/link instead of the direct, Shaare URL attribute - -![](images/rss-filter-1.png) ![](images/rss-filter-2.png) - -```bash -# examples -https://shaarli.mydomain.org/feed/atom?permalinks -https://shaarli.mydomain.org/feed/atom?permalinks&nb=42 -https://shaarli.mydomain.org/feed/atom?permalinks&nb=all -https://shaarli.mydomain.org/feed/rss?searchtags=nature -https://shaarli.mydomain.org/links/picture-wall?searchterm=poney -``` - - -### Picture wall - -- The picture wall can be filtered by text or tags search in the same way as [RSS feeds](#rss-feeds) - - -### Import/export - -To **export Shaares as a HTML file**, under _Tools > Export_, choose: - -- `Export all` to export both public and private Shaares -- `Export public` to export public Shaares only -- `Export private` to export private Shaares only - -Restore by using the `Import` feature. - -- These exports contain the full data (URL, title, tags, date, description, public/private status of your Shaares) -- They can also be imported to your web browser bookmarks. - -To **import a HTML bookmarks file** exported from your browser, just use the `Import` feature. For each "folder" in the bookmarks you imported, a new tag will be created (for example a bookmark in `Movies > Sci-fi` folder will be tagged `Movies` `Sci-fi`). diff --git a/doc/md/dev/Development.md b/doc/md/dev/Development.md deleted file mode 100644 index 33bdbfbd..00000000 --- a/doc/md/dev/Development.md +++ /dev/null @@ -1,1449 +0,0 @@ - -# Development - -Please read [Contributing to Shaarli](https://github.com/shaarli/Shaarli/blob/master/CONTRIBUTING.md) - - -## Third-party libraries - -CSS: - -- Yahoo UI [CSS Reset](https://clarle.github.io/yui3/yui/docs/cssreset/) - standardize cross-browser rendering - -Javascript: - -- [Awesomeplete](https://projects.verou.me/awesomplete/) ([GitHub](https://github.com/LeaVerou/awesomplete)) - autocompletion in input forms -- [bLazy](https://dinbror.dk/blazy/) ([GitHub](https://github.com/dinbror/blazy)) - lazy loading for thumbnails -- [qr.js](https://github.com/neocotic/qrious) - QR code generation - -PHP (managed through [`composer.json`](https://github.com/shaarli/Shaarli/blob/master/composer.json)): - -- [RainTPL](https://github.com/feulf/raintpl) - HTML templating for PHP -- [`shaarli/netscape-bookmark-parser`](https://packagist.org/packages/shaarli/netscape-bookmark-parser) - Import bookmarks from Netscape files -- [`erusev/parsedown`](https://packagist.org/packages/erusev/parsedown) - Parse MarkDown syntax for the MarkDown plugin -- [`slim/slim`](https://packagist.org/packages/slim/slim) - Handle routes and middleware for the REST API -- [`ArthurHoaro/web-thumbnailer`](https://github.com/ArthurHoaro/web-thumbnailer) - PHP library which will retrieve a thumbnail for any given URL -- [`pubsubhubbub/publisher`](https://github.com/pubsubhubbub/php-publisher) - A PubSubHubbub publisher module for PHP. -- [`gettext/gettext`](https://github.com/php-gettext/Gettext) - PHP library to collect and manipulate gettext (.po, .mo, .php, .json, etc) - - -## Security - -- The password is salted, hashed and stored in the data subdirectory, in a PHP file, and protected by htaccess. Even if the webserver does not support htaccess, the hash is not readable by URL. Even if the .php file is stolen, the password cannot deduced from the hash. The salt prevents rainbow-tables attacks. -- Directories are protected using `.htaccess` files -- Forms are protected against [XSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery): - - Forms which act on data (save,delete…) contain a token generated by the server. - - Any posted form which does not contain a valid token is rejected. - - Any token can only be used once. - - Tokens are attached to the session and cannot be reused in another session. -- Sessions automatically expire after 60 minutes. -- Sessions are protected against hijacking: the session ID cannot be used from a different IP address. -- Links are stored as an associative array which is serialized, compressed (with deflate), base64-encoded and saved as a comment in a `.php` file - even if the server does not support `.htaccess` files, the data file will still not be readable by URL. -- Bruteforce protection: Successful and failed login attempts are logged - IP bans are enforced after a configurable amount of failures. Logs can also be used consumed by [fail2ban](../Server-configuration.md#fail2ban) -- A pop-up notification is shown when a new release is available. - -## Link structure - -Every link available through the `LinkDB` object is represented as an array -containing the following fields: - - * `id` (integer): Unique identifier. - * `title` (string): Title of the link. - * `url` (string): URL of the link. Used for displayable links (without redirector, url encoding, etc.). - Can be absolute or relative for Notes. - * `real_url` (string): Real destination URL, can be redirected, encoded, etc. - * `shorturl` (string): Permalink small hash. - * `description` (string): Link text description. - * `private` (boolean): whether the link is private or not. - * `tags` (string): all link tags separated by a single space - * `thumbnail` (string|boolean): relative path of the thumbnail cache file, or false if there isn't any. - * `created` (DateTime): link creation date time. - * `updated` (DateTime): last modification date time. - -Small hashes are used to make a link to an entry in Shaarli. They are unique: the date of the item (eg. `20110923_150523`) is hashed with CRC32, then converted to base64 and some characters are replaced. They are always 6 characters longs and use only `A-Z a-z 0-9 - _` and `@`. - - -## Directory structure - -Here is the directory structure of Shaarli and the purpose of the different files: - -```bash - index.php # Main program - application/ # Shaarli classes - ├── LinkDB.php - - ... - - └── Utils.php - tests/ # Shaarli unitary & functional tests - ├── LinkDBTest.php - - ... - - ├── utils # utilities to ease testing - │ └── ReferenceLinkDB.php - └── UtilsTest.php - assets/ - ├── common/ # Assets shared by multiple themes - ├── ... - ├── default/ # Assets for the default template, before compilation - ├── fonts/ # Font files - ├── img/ # Images used by the default theme - ├── js/ # JavaScript files in ES6 syntax - ├── scss/ # SASS files - └── vintage/ # Assets for the vintage template, before compilation - └── ... - COPYING # Shaarli license - inc/ # static assets and 3rd party libraries - └── rain.tpl.class.php # RainTPL templating library - images/ # Images and icons used in Shaarli - data/ # data storage: bookmark database, configuration, logs, banlist... - ├── config.json.php # Shaarli configuration (login, password, timezone, title...) - ├── datastore.php # Your link database (compressed). - ├── ipban.php # IP address ban system data - ├── lastupdatecheck.txt # Update check timestamp file - └── log.txt # login/IPban log. - tpl/ # RainTPL templates for Shaarli. They are used to build the pages. - ├── default/ # Default Shaarli theme - ├── fonts/ # Font files - ├── img/ # Images - ├── js/ # JavaScript files compiled by Babel and compatible with all browsers - ├── css/ # CSS files compiled with SASS - └── vintage/ # Legacy Shaarli theme - └── ... - cache/ # thumbnails cache - # This directory is automatically created. You can erase it anytime you want. - tmp/ # Temporary directory for compiled RainTPL templates. - # This directory is automatically created. You can erase it anytime you want. - vendor/ # Third-party dependencies. This directory is created by Composer -``` - -Shaarli needs read access to: - -- the root index.php file -- the `application/`, `plugins/` and `inc/` directories (recursively) - -Shaarli needs read/write access to the `cache/`, `data/`, `pagecache/`, and `tmp/` directories - - -## Automation - -A [`Makefile`](https://github.com/shaarli/Shaarli/blob/master/Makefile) is available to perform project-related operations: - -- [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 - -[Github Actions](https://github.com/shaarli/Shaarli/actions) is a Continuous Integration build server, that runs a build: - -- each time a commit is pushed to any branch -- each time a Pull Request is submitted or updated - -After all jobs have finished, Github Actions returns the results to GitHub: - -- a status icon represents the result for the `master` branch: [![Build Status](https://github.com/shaarli/Shaarli/actions/workflows/ci.yml/badge.svg)](https://github.com/shaarli/Shaarli/actions) -- Pull Requests are updated with the Github Actions build result. - -Github Actions is also used to build and push [Docker](../Docker.md) images to <https://github.com/shaarli/Shaarli/pkgs/container/shaarli> for the `master` branch and on every git `tag`/[release](https://github.com/shaarli/Shaarli/releases). - -See [`.github/workflows/`](https://github.com/shaarli/Shaarli/tree/master/.github/workflows). - - -## 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`. - - -## Static analysis - -Patches should try to stick to the [PHP Standard Recommendations](https://www.php-fig.org/psr/) (PSR), and must follow: - -- [PSR-1](https://www.php-fig.org/psr/psr-1/) - Basic Coding Standard -- [PSR-2](https://www.php-fig.org/psr/psr-2/) - Coding Style Guide -- [PSR-12](https://www.php-fig.org/psr/psr-12/) - Extended Coding Style Guide - -These are enforced on pull requests using our Continuous Integration tools with [PHP Code Sniffer](https://github.com/squizlabs/PHP_CodeSniffer). - -Static analysis tools are installed with Composer dependencies, and used through Shaarli's [Makefile](https://github.com/shaarli/Shaarli/blob/master/Makefile) with `make code_sniffer`. - -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](https://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/6.5/en/appendixes.annotations.html) 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/<distribution>/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/alpine316/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://wiki.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](https://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://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 key server) - -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](https://www.cryptnet.net/fdp/crypto/keysigning_party/en/keysigning_party.html), - - -### Generate a GPG key - -- [Generating a GPG key for Git tagging](https://stackoverflow.com/questions/12061645/generating-a-gpg-key-for-git-tagging/16725717#16725717) (StackOverflow) -- [Generating a GPG key](https://docs.github.com/en/authentication/managing-commit-signature-verification) (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 <marvin@h2g2.net>" - -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 <marvin@h2g2.net> -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 https://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 doc/conf.py README.md -$ git add shaarli_version doc/conf.py README.md -$ git commit -s -m "Bump Shaarli version to v0.x.0" -$ git push upstream v0.x -``` - -### Create and push a signed tag - -Git [tags](https://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project) 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 <virtualtam@flibidi.net>" [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 <plugin_name>.meta file and a <plugin_name>.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 <plugin_name>.php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter. - - <plugin_name>_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 <plugin_name>.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_<plugin_name>_<hook_name>($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 `<plugin_name>.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.<PARAMETER_NAME>`: 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 <plugin_name>_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/<plugin name>/`. - - `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 <shaarli_url>/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`** is an array containing [Special data](#special-data) -- Template placeholders: items can be displayed in templates by adding an entry in `$data['<placeholder>']` array. List of placeholders: - - `buttons_toolbar`: after the list of buttons in the header. - - `fields_toolbar`: after search fields in the header. Note: This will only be called in linklist. - -![buttons_toolbar_example](https://i.imgur.com/ssJUOrt.png) -![fields_toolbar_example](https://i.imgur.com/3GMifI2.png) - - -#### render_includes - -Triggered on every page - allows plugins to include their own CSS files. - -- **`$data`** is an array containing [Special data](#special-data) -- Template placeholders: items can be displayed in templates by adding an entry in `$data['<placeholder>']` 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 - allows plugins to add content in page footer and include their own JS files. - -- **`$data`** is an array containing [Special data](#special-data) -- Template placeholders: items can be displayed in templates by adding an entry in `$data['<placeholder>']` array. List of placeholders: - - `text`: called after the end of the footer text. - - `endofpage`: called at the end of the page. - - `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`. - -![text_example](https://i.imgur.com/L5S2YEH.png) - - -#### render_linklist - -Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.) - allows to add content at the begining and end of the page, after every link displayed and to alter link 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['<placeholder>']` array. List of placeholders: - - `action_plugin`: next to the button "private only" at the top and bottom of the page. - - `link_plugin`: for every link, between permalink and link URL. - - `plugin_start_zone`: before displaying the template content. - - `plugin_end_zone`: after displaying the template content. - -![action_plugin_example](https://i.imgur.com/Q12PWg0.png) -![link_plugin_example](https://i.imgur.com/3oDPhWx.png) -![plugin_start_zone_example](https://i.imgur.com/OVBkGy3.png) -![plugin_end_zone_example](https://i.imgur.com/6IoRuop.png) - - -#### render_editlink - -Triggered when the link edition form is displayed - allows to add fields in the form, or display elements. - -- **`$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['<placeholder>']` array. List of placeholders: - - `edit_link_plugin`: after tags field. - -![edit_link_plugin_example](https://i.imgur.com/5u17Ens.png) - - -#### render_tools - -Triggered when the "tools" page is displayed - allows to add content at the end of the page. - -- **`$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['<placeholder>']` array. List of placeholders: - - `tools_plugin`: at the end of the page. - -![tools_plugin_example](https://i.imgur.com/Bqhu9oQ.png) - - -#### render_picwall - -Triggered when picwall is displayed - allows to add content at the top and bottom of the page. - -- **`$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['<placeholder>']` 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](https://i.imgur.com/tVTQFER.png) - - -#### render_tagcloud - -Triggered when tagcloud is displayed - allows to add content at the top and bottom of the page. - -- **`$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['<placeholder>']` 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](https://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`** 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['<placeholder>']` 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 - allows to add content at the top and bottom of the page, the bottom of each link and to alter 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['<placeholder>']` array. List of placeholders: - - `link_plugin`: used at bottom of each link. - - `plugin_start_zone`: before displaying the template content. - - `plugin_end_zone`: after displaying the template content. - -![link_plugin_example](https://i.imgur.com/hzhMfSZ.png) - - -#### render_feed - -Triggered when the ATOM or RSS feed is displayed - allows to add tags in the feed, either in the header or for each items. Items (links) can also be altered before being rendered. - -- **`$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['<placeholder>']` array. List of placeholders: - - `feed_plugins_header`: used as a header tag in the feed. -- For each link, the following placeholder can be used: - - `feed_plugins`: additional tag for every link entry. - - -#### save_link - -Triggered when a link is save (new link or edit) - allows to alter the link being saved in the datastore. - -- **`$data`** is an array containing: - - the link being saved (id, title, url, shorturl, description, private, tags, created, updated) - - [Special data](#special-data). - - -#### delete_link - -Triggered when a link is deleted - allows to execute any action before the link is actually removed from the datastore - -- **`$data`** is an array containing: - - the link being deleted (id, title, url, shorturl, description, private, tags, created, updated) - - [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`** 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. - - [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. - -- Parameters: - - `Shaarli\Bookmark\Bookmark` object: entry to evaluate - - `$context` array: additional information provided depending on what search is currently used, the user request, etc. -- 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. - - -## 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: - -<input type="hidden" name="order_{$key}" value="{$counter}"> - - -### 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"} - <ul class="errors"> - {loop="plugin_errors"} - <li>{$value}</li> - {/loop} - </ul> - {/if} - -**includes.html** - -At the end of the file: - -```html -{loop="$plugins_includes.css_files"} -<link type="text/css" rel="stylesheet" href="{$value}#"/> -{/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"} - <script src="{$value}#"></script> -{/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"} - <span>{$value}</span> -{/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 -<div id="plugin_zone_start_picwall" class="plugin_zone"> - {loop="$plugin_start_zone"} - {$value} - {/loop} -</div> -``` - -Bottom: - -```html -<div id="plugin_zone_end_picwall" class="plugin_zone"> - {loop="$plugin_end_zone"} - {$value} - {/loop} -</div> -``` - -**tagcloud.html** - -Top: - -```html - <div id="plugin_zone_start_tagcloud" class="plugin_zone"> - {loop="$plugin_start_zone"} - {$value} - {/loop} - </div> -``` - -Bottom: - -```html - <div id="plugin_zone_end_tagcloud" class="plugin_zone"> - {loop="$plugin_end_zone"} - {$value} - {/loop} - </div> -``` - -**daily.html** - -Top: - -```html -<div id="plugin_zone_start_picwall" class="plugin_zone"> - {loop="$plugin_start_zone"} - {$value} - {/loop} -</div> -``` - -After every link: - -```html -<div class="dailyEntryFooter"> - {loop="$link.link_plugin"} - {$value} - {/loop} -</div> -``` - -Bottom: - -```html -<div id="plugin_zone_end_picwall" class="plugin_zone"> - {loop="$plugin_end_zone"} - {$value} - {/loop} -</div> -``` - -**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/<a_sweet_theme>` -- 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://<replace_domain>/ -http://<replace_domain>/login -http://<replace_domain>/daily -http://<replace_domain>/tags/cloud -http://<replace_domain>/tags/list -http://<replace_domain>/picture-wall -http://<replace_domain>/?nonope -http://<replace_domain>/admin/add-shaare -http://<replace_domain>/admin/password -http://<replace_domain>/admin/tags -http://<replace_domain>/admin/configure -http://<replace_domain>/admin/tools -http://<replace_domain>/admin/shaare -http://<replace_domain>/admin/export -http://<replace_domain>/admin/import -http://<replace_domain>/admin/plugins -``` - - -### Improve existing translations - -- In Poedit, click on "Edit a Translation -- Open `inc/languages/<lang>/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/<lang>/LC_MESSAGES/shaarli.po` under Shaarli's directory -- Select the language you want to create. -- Click on `File > Save as...`, save your file in `<shaarli directory>/inc/language/<new language>/LC_MESSAGES/shaarli.po` (`<new language>` 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/<theme name>/language/<lang>/LC_MESSAGES/<theme name>.po -tpl/<theme name>/language/<lang>/LC_MESSAGES/<theme name>.mo -``` - -Where `<lang>` 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: - -``` -<your_module>/languages/<ISO 3166-1 alpha-2 language code>/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.<domain>: <translation files path>`. - -Example: - -```php -if (! $conf->exists('translation.extensions.my_theme')) { - $conf->set('translation.extensions.my_theme', '<your_module>/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 `<your_module>/languages/<language code>/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 points to 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 <fix commit hash> -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/images/poedit-1.jpg b/doc/md/dev/images/poedit-1.jpg deleted file mode 100644 index 673ae6d6..00000000 Binary files a/doc/md/dev/images/poedit-1.jpg and /dev/null differ diff --git a/doc/md/images/07-installation.jpg b/doc/md/images/07-installation.jpg deleted file mode 100644 index 42cc9f10..00000000 Binary files a/doc/md/images/07-installation.jpg and /dev/null differ diff --git a/doc/md/images/doc-logo.png b/doc/md/images/doc-logo.png deleted file mode 100644 index 3da7ba57..00000000 Binary files a/doc/md/images/doc-logo.png and /dev/null differ diff --git a/doc/md/images/doc-logo.svg b/doc/md/images/doc-logo.svg deleted file mode 100644 index 37fc6658..00000000 --- a/doc/md/images/doc-logo.svg +++ /dev/null @@ -1,522 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - width="600" - height="240" - id="svg2" - version="1.1"> - <title - id="title6384">Shaarli Logo - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Shaarli Logo - - - http://blog.idleman.fr/ - - - 2012-08-29 22:36:01+02:00 - - - http://sebsauvage.net/ - - - - - Shaarli - Logo - - - - - http://thatguynamedandy.com/, -http://mro.name/me - - - - http://sebsauvage.net/files/shaarli_logo.zip - http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion#comment_09a1e91bc0abc7db6d186a6abf429877 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/md/images/edit_icon.png b/doc/md/images/edit_icon.png deleted file mode 100644 index 16c440c8..00000000 Binary files a/doc/md/images/edit_icon.png and /dev/null differ diff --git a/doc/md/images/icon.png b/doc/md/images/icon.png deleted file mode 100644 index 530d7469..00000000 Binary files a/doc/md/images/icon.png and /dev/null differ diff --git a/doc/md/images/logo.png b/doc/md/images/logo.png deleted file mode 100644 index f8b0c94f..00000000 Binary files a/doc/md/images/logo.png and /dev/null differ diff --git a/doc/md/images/rss-filter-1.png b/doc/md/images/rss-filter-1.png deleted file mode 100644 index 0cf1591c..00000000 Binary files a/doc/md/images/rss-filter-1.png and /dev/null differ diff --git a/doc/md/images/rss-filter-2.png b/doc/md/images/rss-filter-2.png deleted file mode 100644 index 5a40755a..00000000 Binary files a/doc/md/images/rss-filter-2.png and /dev/null differ diff --git a/doc/md/index.md b/doc/md/index.md deleted file mode 100644 index 6ef9a194..00000000 --- a/doc/md/index.md +++ /dev/null @@ -1,122 +0,0 @@ -# Shaarli - -_The personal, minimalist, super fast, database-free, bookmarking service._ - -Do you want to share the links you discover? Shaarli is a minimalist bookmark manager and link sharing service that you can install on your own server. It is designed to be personal (single-user), fast and handy. - -Visit the pages in the sidebar to find information on how to setup, use, configure, tweak and troubleshoot Shaarli. - -* [GitHub project page](https://github.com/shaarli/Shaarli) -* [Documentation](https://shaarli.readthedocs.io/) -* [Changelog](https://github.com/shaarli/Shaarli/blob/master/CHANGELOG.md) - - -[![](https://i.imgur.com/8wEBRSG.png)](https://i.imgur.com/WWPfSj0.png) [![](https://i.imgur.com/93PpLLs.png)](https://i.imgur.com/V09kAQt.png) [![](https://i.imgur.com/rrsjWYy.png)](https://i.imgur.com/TZzGHMs.png) [![](https://i.imgur.com/8iRzHfe.png)](https://i.imgur.com/sfJJ6NT.png) [![](https://i.imgur.com/GjZGvIh.png)](https://i.imgur.com/QsedIuJ.png) [![](https://i.imgur.com/TFZ9PEq.png)](https://i.imgur.com/KdtF8Ll.png) [![](https://i.imgur.com/tVvD3gH.png)](https://i.imgur.com/zGF4d6L.jpg) - -```{toctree} -:maxdepth: 1 -:hidden: - -Server-configuration.md -Installation.md -Reverse-proxy.md -Docker.md -Shaarli-configuration.md -Usage.md -Backup-and-restore.md -Upgrade-and-migration.md -Community-and-related-software.md -Plugins.md -REST-API.md -Troubleshooting.md -dev/Development.md -``` - -## Demo - -You can use this [public demo instance of Shaarli](https://demo.shaarli.org). -It runs the latest development version of Shaarli and is updated/reset daily. - -Login: `demo`; Password: `demo` - - -## Getting started - -- [Configure your server](Server-configuration.md) -- [Install Shaarli](Installation.md) -- Or install Shaarli using [Docker](Docker.md) - - -## Features - -Shaarli can be used: - -- to share, comment and save interesting links -- to bookmark useful/frequent links and share them between computers -- as a minimal blog/microblog/writing platform -- as a read-it-later/todo list -- as a notepad to draft and save articles/posts/ideas -- as a knowledge base to keep notes, documentation and code snippets -- as a shared clipboard/notepad/pastebin between computers -- as playlist manager for online media -- to feed other blogs, aggregators, social networks... - -### Edit, view and search your links - -- Editable URL, title, description, tags, private/public status for all your [Shaares](Usage.md) -- [Tags](Usage.md#tags) to organize your Shaares -- [Search](Usage.md#search) in all fields -- Unique [permalinks](Usage.md#permalinks) for easy reference -- Paginated Shaares list view (with image and video thumbnails) -- [Tag cloud/list](Usage.md#tag-cloud) views -- [Picture wall](Usage.md#picture-wall)/thumbnails view (with lazy loading) -- [ATOM and RSS feeds](Usage.md#rss-feeds) (can also be filtered using tags or text search) -- [Daily](Usage.md#daily): newspaper-like daily digest (and daily RSS feed) -- URL cleanup: automatic removal of `?utm_source=...`, `fb=...` tracking parameters -- Extensible through [plugins](Plugins.md) -- Easily extensible by any client using the [REST API](REST-API.md) exposed by Shaarli -- Bookmarklet and [other tools](Community-and-related-software.md) to share links in one click -- Responsive/support for mobile browsers, degrades gracefully with Javascript disabled -- LDAP (single-user) login support - - -### Easy setup - -- Dead-simple [installation](Installation.md): drop the files on your server, open the page -- Shaares are stored in a file (no database required, easy [backup](Backup-and-restore.md)) -- [Configurable](Shaarli-configuration.md) from dialog and configuration file -- Extensible through third-party [plugins and themes](Community-and-related-software.md) - - -### Fast - -- Fast! Small datastore file, write-once/read-many, served most of the time from OS disk caches (no disk I/O) -- Stays fast with even tens of thousands shaares! - - -### Self-hosted - -- Shaarli is an alternative to commercial services such as StumbleUpon, Delicio.us, Diigo... -- The data is yours, [import and export](Usage.md#import-export) it to HTML bookmarksformat compatible with most web browser, and from a variety of formats -- Shaarli does not send any telemetry/metrics/private information to developers -- Shaarli is Free and Open-Source software, inspect and change how the program works in the [source code](https://github.com/shaarli/Shaarli) -- Built-in [Security](dev/Development.md#security) features to help you protect your Shaarli instance - - -## About - -This [community fork](https://github.com/shaarli/Shaarli) of the original [Shaarli](https://github.com/sebsauvage/Shaarli/) project by [Sébastien Sauvage](https://sebsauvage.net/) (now [unmaintained](https://github.com/sebsauvage/Shaarli/issues/191)) has carried on the work to provide [many patches](https://github.com/sebsauvage/Shaarli/compare/master...shaarli:Shaarli:master) for [bug fixes and enhancements](https://github.com/shaarli/Shaarli/issues?q=is%3Aclosed+) in this repository, and will keep maintaining the project for the foreseeable future, while keeping Shaarli simple and efficient. - -The original Shaarli instance is still available [here](https://sebsauvage.net/links/) (+25000 shaares!) - - -### Contributing and getting help - -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](https://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). diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index 5ba9f971..00000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -sphinx==7.1.0 -furo==2023.7.26 -myst-parser -sphinx-design diff --git a/plugins/myShaarli/myShaarli.php b/plugins/myShaarli/myShaarli.php index f51bab73..54280df0 100644 --- a/plugins/myShaarli/myShaarli.php +++ b/plugins/myShaarli/myShaarli.php @@ -149,6 +149,9 @@ function hook_myShaarli_render_footer($data) { if (file_exists('contact.php')) { $data['text'][] = '
Contact'; } + + $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/myShaarli/myShaarli.js'; + return $data; } diff --git a/tpl/myShaarli/css/myShaarli.css b/tpl/myShaarli/css/myShaarli.css index c7152a98..34b75afc 100644 --- a/tpl/myShaarli/css/myShaarli.css +++ b/tpl/myShaarli/css/myShaarli.css @@ -1,1384 +1,385 @@ -/** - * General - */ -body { - background: linear-gradient(#434343,#cdcdcd) no-repeat transparent; +:root { + color-scheme: dark light; + + --primary: #cc2027; + --primary-darken: #8E161B; + --primary-lighten: #D64C52; + --primary-text-contrast: #FFF; + + --secondary: #20ccc5; + --secondary-darken: #168E89; + --secondary-lighten: #4CD6D0; + --secondary-text-contrast: #000; + + --error: #c43933; + --error-darken: #892723; + --error-lighten: #CF605B; + --error-text-contrast: #FFF; + + --info: #206ccc; + --info-darken: #164B8E; + --info-lighten: #4C89D6; + --info-text-contrast: #FFF; + + --success: #7dcc20; + --success-darken: #578E16; + --success-lighten: #97D64C; + --success-text-contrast: #000; + + --warning: #cc5e20; + --warning-darken: #8E4116; + --warning-lighten: #D67E4C; + --warning-text-contrast: #FFF; + + --background-color: light-dark(#fffbfb, #171414); + --background-color-darken: light-dark(#B2AFAF, #100E0E); + --background-color-lighten: light-dark(#FFFBFB, #454343); + + --header-background-color: light-dark(#171414, #fffbfb); + --header-background-color-darken: light-dark(#100E0E, #B2AFAF); + --header-background-color-lighten: light-dark(#454343, #FFFBFB); + + --header-text-color: light-dark(#fffbfb, #171414); + --header-text-color-secondary: #ffffffb3; + --header-text-color-disable: light-dark(#ffffff80, #454343); + + --text-color: light-dark(#171414, #fffbfb); + --text-color-secondary: #ffffffb3; + --text-color-disable: light-dark(#454343, #ffffff80); + + --text-color-inverse: light-dark(#fffbfb, #171414); + --text-color-secondary-inverse: #ffffffb3; + --text-color-disable-inverse: light-dark(#ffffff80, #454343); + + --h1-color: var(--primary); + --h2-color: #c33d35; + --h3-color: #b94f44; + --h4-color: #ae5e52; + --h5-color: #a16a61; + --h6-color: #927671; +} + +[data-theme="dark"] { + --background-color: #171414; + --text-color: #fffbfb; + --text-color-inverse: #171414; + .linklist-pages { + color: var(--text-color); + } +} + +[data-theme="light"] { + --background-color: #fffbfb; + --text-color: #171414; + --text-color-inverse: #fffbfb; +} + +* { box-sizing: border-box; - color: #000; - font-size: .9em; } -.strong { - font-weight: bold; +:root { + --main-color: var(--primary); + --dark-main-color: var(--primary-darken); } -.clear { - clear: both; +body { + background-color: var(--background-color); + color: var(--text-color); } -.center { - text-align: center; - margin: auto; +a { + transition: all .2s linear, border .2s linear; } -.label { - display: inline-block; - padding: .3em; - font-size: 75%; - font-weight: 700; - line-height: 1; - text-align: center; - white-space: nowrap; - vertical-align: baseline; -} - -.linklist-item-infos .label a{ - border-radius: .3rem; - background-color: #ddd; - border: 1px solid #fff; - padding: .3em .6em; -} - -.linklist-item-infos .label a:hover { - color: #1b926c; - background-color: #fff; - border: 1px solid #333; - transition: color .2s linear, border .2s linear; -} - -pre { - max-width: 100%; -} - -@font-face { - font-family: 'Roboto'; - font-weight: 400; - font-style: normal; - src: - local('Roboto'), - local('Roboto-Regular'), - url('../fonts/Roboto-Regular.woff2') format('woff2'), - url('../fonts/Roboto-Regular.woff') format('woff'); -} - -@font-face { - font-family: 'Roboto'; - font-weight: 700; - font-style: normal; - src: - local('Roboto'), - local('Roboto-Bold'), - url('../fonts/Roboto-Bold.woff2') format('woff2'), - url('../fonts/Roboto-Bold.woff') format('woff'); -} - -body, .pure-g [class*="pure-u"] { - font-family: Roboto, Arial, sans-serif; -} - - -*:hover { - transition: color .25s linear; -} - -/** - * Extends Pure grids responsive to hide items. - * Use xx-0 to hide an item on xx screen. - * Display it at any level with xx-visible. - */ -.pure-u-0 { display: none !important; } -@media screen and (min-width: 35.5em) { - .pure-u-sm-0 { display: none !important; } - .pure-u-sm-visible { display: inline-block !important; } -} -@media screen and (min-width: 48em) { - .pure-u-md-0 { display: none !important; } - .pure-u-md-visible { display: inline-block !important; } -} -@media screen and (min-width: 64em) { - .pure-u-lg-0 { display: none !important; } - .pure-u-lg-visible { display: inline-block !important; } -} -@media screen and (min-width: 80em) { - .pure-u-xl-0 { display: none !important; } - .pure-u-xl-visible { display: inline-block !important; } -} - -/** - * Make pure-extras alert closable. - */ -.pure-alert-closable .fa-times { - float: right; -} -.pure-alert-close { - cursor: pointer; -} - -.pure-alert-success { - background-color: #1b926c; - margin-bottom: .4em; -} - -.anchor:target { - padding-top: 40px; -} -/** - * MENU - **/ .shaarli-menu { - width: 100%; - background: linear-gradient(#333333,#111111); - background-color: #333333; - box-shadow: 0 1px 2px rgba(0,0,0,0.5); - -webkit-font-smoothing: antialiased; - /* Hack to transition with auto height: http://stackoverflow.com/a/8331169/1484919 */ - max-height: 45px; - transition: max-height 0.5s; - overflow: hidden; - z-index: 999; + background-color: var(--primary); } -/* Chrome bugfix: with 100% height, it only displays the first element. */ -.pure-menu-item { - height: 45px; -} - -.shaarli-menu.open { - max-height: 500px; - transition: max-height 0.75s; -} - -.head-logo { - float: left; - margin: 0px 5px 0 0; -} - -.pure-menu-link, -.pure-menu-link:visited, -.pure-menu-selected .pure-menu-link, -.pure-menu-selected .pure-menu-link:visited { - padding: 0.8em 1em; - color: #f5f5f5; -} - -.pure-menu-link:hover, .pure-menu-link:focus, -.pure-menu-selected .pure-menu-link:hover, -.pure-menu-selected .pure-menu-link:focus { - color: #fff; - background: transparent; -} - -.pure-menu-item:hover::after { - margin: -4px auto 0 auto; - display: block; - content:""; - background: #1b926c; - height: 4px; - width: 100%; -} - -.menu-toggle { - width: 34px; - height: 45px; - position: absolute; - top: 5px; - right: 0; - display: none; -} - -.menu-toggle .bar { - background-color: #b0ddce; - display: block; - width: 20px; - height: 2px; - border-radius: 100px; - position: absolute; - top: 18px; - right: 7px; - transition: all 0.5s; -} - -.menu-toggle .bar:first-child { - transform: translateY(-6px); -} - -.menu-toggle.x .bar { - transform: rotate(45deg); -} - -.menu-toggle.x .bar:first-child { - transform: rotate(-45deg); -} - -@media screen and (max-width: 64em) { - .menu-toggle { - display: block; - } -} - -.header-buttons { - text-align: right; -} - -.linkcount { - color: #A2DD42; - font-size: 0.8em; -} - -@media screen and (min-width: 64em) { - .linkcount { - position: absolute; - right: 5px; - } -} - -#search, #search-linklist, #search-tagcloud { - text-align: center; - width: 100%; -} - -.contain-searchform { - display: flex; -} - -#search input[type="text"], #search-linklist input[type="text"] { - padding: 0 5px; - height: 30px; - width: 100%; - background: #f5f5f5; - border: medium none currentColor; - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.078), 0 1px 1px rgba(0, 0, 0, 0.298) inset; - border-radius: .2em; - color: #252525; - margin: .1em .2em; -} -@media screen and (max-width: 64em) { - .searchform { - max-width: 260px; - margin: 0 auto; - } -} - -/* because chrome */ -#search input[type="text"]::-webkit-input-placeholder, -#search-linklist input[type="text"]::-webkit-input-placeholder { - color: #777777; -} - -#search button, -#search-tagcloud button, -#search-linklist button { - background: transparent; - border: none; - border-radius: 2px; -} - -#search button { - color: #f5f5f5; -} - -#search-linklist button { - color: #252525; -} - -#search button:hover, -#search-linklist button:hover { - color: #fff; -} -#search-tagcloud button:hover { - color: #d0d0d0; -} - -#search, -#search-linklist { - padding: 5px 0; -} - -@media screen and (min-width: 64em) { - #search .searchform, - #search-linklist .searchform { - display: flex; - text-align: left; - width: 60%; - margin: 0 auto; - } - - #search .tagfilter, - #search-linklist .tagfilter { - text-align: left; - display: flex; - width: 50%; - } -} -@media screen and (max-width: 64em) { - #search, #search * { - visibility: hidden; - } -} - -.subheader-form a.button { - color: #f5f5f5; - font-weight: bold; - text-decoration: none; - border: 2px solid #f5f5f5; +.tag-sort a.button { + border: 2px solid var(--text-color); border-radius: 5px; padding: 3px 10px; -} - -.linklist-item-editbuttons .delete-checkbox { - display: none; -} - -#header-login-form input[type="text"], #header-login-form input[type="password"] { - width: 200px; -} - -/* because chrome */ -#header-login-form input[type="text"]::-webkit-input-placeholder, -#header-login-form input[type="password"]::-webkit-input-placeholder { - color: #777777; + text-decoration: none; + color: var(--text-color); + font-weight: bold; + background-color: transparent; } .subheader-form { - visibility: hidden; - position: fixed; - width: 100%; - text-align: center; - background: #111; - display: block; - z-index: 999; - height: 30px; - padding: 5px 0; + background-color: var(--background-color-lighten); + padding: 1.1em 0; } -@media screen and (min-width: 64em) { - .subheader-form.open, .subheader-form.open * { - visibility: visible; - } +.subheader-form { + height: auto; } -.subheader-form input[type="text"], .subheader-form input[type="password"], .subheader-form .remember-me { - margin: 0 0 5px 0; - padding: 5px 5px 3px 15px; - height: 20px; - width: 20%; - background: #f5f5f5; - border: medium none currentColor; - border-radius: 2px; - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.078), 0 1px 4px rgba(0, 0, 0, 0.298) inset; - color: #252525; +.subheader-form a.button, +.tag-sort a.button { + border-color: var(--text-color); + color: var(--text-color); } -/* because chrome */ -.subheader-form input[type="text"]::-webkit-input-placeholder, -.subheader-form input[type="password"]::-webkit-input-placeholder -{ - color: #252525; +.subheader-form a.button:hover, +.tag-sort a.button:hover { + border-color: var(--text-color-inverse); + color: var(--text-color-inverse); } -.subheader-form .remember-me { - display: inline-block; - width: auto; - padding: 5px 20px 3px 20px; - cursor: pointer; +.linklist-pages a, +.daily-entry .daily-entry-title a { + color: var(--primary); } -.subheader-form .remember-me label, .subheader-form .remember-me input { - cursor: pointer; +.linkcount { + color: var(--text-color); } -.subheader-form input[type="submit"] { - display: inline-block; - margin: 0 0 5px 0; - padding: 4px 0 4px 0; - height: 28px; - width: 100px; - background: #1b926c; - border: 1px solid #f5f5f5; - color: #f5f5f5; - border-radius: 2px; +#link-count-content { + background-color: var(--background-color-lighten); } -.subheader-form input[type="submit"]:hover { - background: #f5f5f5; - color: #1b926c; -} - -.new-version-message { - text-align: center; -} - -.new-version-message a { - color: rgb(151, 96, 13); - font-weight: bold; -} - -/** - * CONTENT - GENERAL - */ -#content { - position: relative; - z-index: 2; -} - -/** - * Plugins additional forms - */ -.toolbar-plugin { - margin: 5px 0; - text-align: center; -} - -.toolbar-plugin input[type="text"] { - padding: 0 5px; - height: 30px; - width: 300px; - background: #f5f5f5; - border: medium none currentColor; - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.078), 0 1px 1px rgba(0, 0, 0, 0.298) inset; - border-radius: 2px; - color: #252525; -} - -/* because chrome */ -.toolbar-plugin input[type="text"]::-webkit-input-placeholder { - color: #777777; -} - -.toolbar-plugin input[type="submit"] { - padding: 0 10px; - height: 30px; - background: #f5f5f5; - border: medium none currentColor; - border-radius: 2px; - color: #252525; -} - -.toolbar-plugin input[type="submit"]:hover { - background: #fff; -} - -@media screen and (max-width: 64em) { - .toolbar-plugin input[type="text"] { - width: 70%; - - } -} - -/** - * CONTENT - LINKLIST PAGING - * 64em -> lg - */ .linklist-filters { - margin: 0; - color: #252525; - font-size: 0.9em; - align-self:center; + color: var(--text-color); + padding-left: .3em; } .linklist-filters a:hover { - color: #b0ddce; - background: #1b926c; -} - -.linklist-filters a { - padding: 5px 8px; - text-decoration: none; -} - -.linklist-filters .filter-off { - color: #252525; - background: #f5f5f5; -} - -.linklist-filters .filter-on { - color: #b0ddce; - background: #1b926c; -} - -.linklist-pages { - margin: 0; - color: #252525; - text-align: center; - align-self:center; -} - -.linklist-pages a { - color: #252525; - text-decoration: none; -} - -.linklist-pages a:hover { - color: #fff; + color: var(--text-color); + background: var(--primary); } .linksperpage { - margin: 0; - text-align: right; - color: #252525; - font-size: 0.9em; - align-self:center; + color: var(--text-color) } .linksperpage a { - padding: 5px 5px; - text-decoration: none; - color: #252525; - background: #f5f5f5; + width: auto; } .linksperpage a:hover { - color: #b0ddce; - background: #1b926c; -} - -.linksperpage a, .linksperpage input[type="text"] { - display: inline-block; - width: 20px; - text-align: center; -} - -.linksperpage form { - display: inline; + color: var(--text-color); + background: var(--primary); } .linksperpage input[type="text"] { - height: 20px; margin: 0; - padding: 4px 5px 3px 8px; - background: #f5f5f5; - border: medium none currentColor; - color: #252525; - font-size: 0.8em; + padding: .348em; + height: auto; + font-size: 1em; + width: 4em; } -.paging { - background-color: #777; - margin: 0 0 5px 0; - border-radius: .3em; - padding: .2em; -} - -/** - * CONTENT - LINKLIST ITEMS - */ -.linklist-item { - background: #f5f5f5; - box-shadow: 2px 2px 0.5em #797979; - border-radius: .2em; - margin: 0 0 15px 0; - border-radius: .3em; -} - -.linklist-item-title, .linklist-item-title h2 { - margin: 0; - word-wrap: break-word; - border-radius: .2em .2em 0 0; +.linklist-item.private::before { + background: var(--warning); } .linklist-item-title { - position: relative; - background: #f5f5f5; -} - -.linklist-item-title h2 { - padding: 3px 10px 0 10px; - line-height: 30px; -} - -.linklist-item-title a { - font-size: 0.7em; - color: #252525; - text-decoration: none; - vertical-align: middle; -} - -.linklist-item-title .linklist-link { - font-size: 1.1em; - color: #1b926c; -} - -.linklist-item-title a:visited .linklist-link { - color: #555555; -} - -.linklist-item-title a:hover, .linklist-item-title .linklist-link:hover{ - color: #252525; -} - - -.linklist-item-title .label-private { - border: solid 1px #F89406; - font-family: Arial, sans-serif; - font-size: 0.65em; - color: #F89406; -} - -.linklist-item-title .fold-button { - display: none; -} - -.linklist-item-editbuttons { - float: right; - padding: 8px 5px; -} - -.linklist-item-editbuttons * { - display: block; - float: left; - margin: 0 1px; -} - -.linklist-item-editbuttons a { - font-size: 1em; -} - -.edit-link { - font-size: 1.2em; - color: #0b5ea6; -} - -.delete-link { - font-size: 1.3em; - color: #ac2925 !important; + background: var(--header-background-color); } .linklist-item-description { - position: relative; - padding: 10px; - word-wrap: break-word; - color: #252525; - line-height: 1.3em; + color: var(--text-color-inverse); } - { - position: absolute; - left: 3px; - top: 0; - display: block; - content:""; - background: #F89406; - height: 95%; - width: 2px; - z-index: 1; +.linklist-item-description a:hover, +.daily-entry-title a:hover, +.page-form a:hover { + color: var(--primary-darken); } -.linklist-item-description a { - text-decoration: none; - color: #1b926c; +.linklist-item-title .linklist-link:hover { + color: var(--primary-darken); } -.linklist-item-description a:hover { - color: #252525; +.edit-link { + color: var(--secondary-darken); } -.linklist-item-description a:visited { - color: #14553f; -} - -.origin { - margin: .3em .3em .3em 0; -} - -.linklist-item-thumbnail { - position: relative; - padding: .6em; - float: left; - z-index: 50; -} - -.linklist-item.private .linklist-item-title::before, -.linklist-item.private .linklist-item-description::before, -.linklist-item.private .linklist-item-thumbnail::before { - position: absolute; - left: 3px; - top: 0; - display: block; - content:""; - background: #F89406; - height: 95%; - width: 2px; - z-index: 1; -} - -.favicon { - height: 16px; - margin-right: .1em; - vertical-align: unset; - width: 16px; -} - -.linklist-item.private .linklist-item-title::before { - margin-top: 3px; +.edit-link:hover { + color: var(--secondary); } .linklist-item-infos { padding: 8px 8px 5px 8px; - background: #ddd; - color: #252525; - border-radius: 0 0 .2em .2em; } -.linklist-item-infos a { - color: #252525; - text-decoration: none; +.linklist-item-title .label-private { + border: solid 1px var(--warning); + color: var(--warning); } -.linklist-item-infos a:hover { - color: #000; +.linklist-item-infos .label a { + border-radius: .3rem; + background-color: var(--header-background-color-darken); + border: 1px solid var(--header-background-color-darken); + padding: .3em .6em; +} + +.linklist-item-infos .label a:hover { + color: var(--primary); + background-color: var(--header-background-color-lighten); + border: 1px solid var(--header-background-color-darken); } .linklist-item-infos .linklist-item-tags { - font-size: 0.8em; margin-bottom: .6em; } -.linklist-item-infos .label-tag { - font-size: 1em; -} - -.linklist-item-infos-dateblock { - font-size: 0.9em; -} - -.linklist-plugin-icon { - width: 13px; - height: 13px; -} - -.linklist-item-infos-url { - text-align: right; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: 0.8em; -} - -.linklist-item-infos .mobile-buttons { - text-align: right; -} - -.linklist-item-infos .linklist-plugin-icon { - display: inline-block; - margin: 0 2px; - width: 16px; - height: 16px; -} - -/** 64em -> lg **/ -@media screen and (max-width: 64em) { - .linklist-item-infos-url { - text-align: left; - } -} - -/** - * Footer - */ -#footer { - margin: 20px 0; - padding: 5px; - text-align: center; - color: #252525; -} - -#footer:before { - display: block; - content:""; - background: linear-gradient(to right, #949393, #252525, #949393); - height: 1px; - width: 80%; - margin: 10px auto; -} - -#footer a { - color: #252525; -} - -/** - * PAGE FORM - */ -.page-form { - margin: 20px 0 0 0; - background: #f5f5f5; - box-shadow: 1px 1px 2px #797979; - color: #252525; - overflow: hidden; -} - -.page-form .window-title { - margin: 0 0 10px 0; - padding: 10px 0; - width: 100%; - color: #1b926c; - background: #f5f5f5; - text-align: center; -} - -.page-form .window-subtitle { - text-align: center; -} - -.page-form a { - color: #1b926c; - font-weight: bold; - text-decoration: none; -} - -.page-form p { - padding: 5px 10px; +.footer-container::before { + display: none; margin: 0; + background: inherit; } -.page-form input[type="text"], -.page-form input[type="password"], -.page-form textarea { - box-sizing: border-box; - margin: 10px 0; - padding: 5px 5px 3px 15px; - height: 35px; - width: 90%; - background: #eeeeee; - border: solid 1px #d8d8d8; - border-radius: 2px; - color: #252525; -} - -.page-form textarea { - min-height: 240px; - padding: 15px 5px 3px 15px; - resize: vertical; - overflow-y: auto; - word-wrap:break-word -} - -/* because chrome */ -.page-form input[type="text"]::-webkit-input-placeholder, -.page-form input[type="password"]::-webkit-input-placeholder { - color: #777777; -} - -.page-form input[type="submit"], .page-form a.button { - margin: 15px 5px; - height: 35px; - line-height: 35px; - width: 150px; - background: #1b926c; - color: #f5f5f5; - border: none; - box-shadow: 1px 1px 1px #ddd, -1px -1px 6px #ddd, -1px 1px 2px #ddd, 1px -1px 2px #ddd; - font-size: 1.2em; - text-decoration: none; - vertical-align: center; - font-weight: normal; - display: inline-block; -} - - -.page-form .button.button-red { - background: #ac2925; -} - -.page-form .submit-buttons { - margin-bottom: 10px; -} - -@media screen and (min-width: 64em) { - .page-form .submit-buttons { - position: relative; - } - - .page-form .submit-buttons .button.button-red { - position: absolute; - right: 5%; - } -} - -@media screen and (max-width: 64em) { - .page-form .submit-buttons .button { - display: block; - margin: auto; - } -} - -.page-form select { - color: #252525; -} - -/** - * PAGE FORM - LIGHT - */ -.page-form-light div, .page-form-light p { - text-align: center; -} - -/** - * PAGE FORM - COMPLETE - */ -.page-form-complete { - background: #f5f5f5; -} - -.page-form-complete div, .page-form-complete p { - color: #252525; -} - -.page-form-complete .form-label, .page-form-complete .form-input { - position: relative; - height: 60px; -} - -.page-form-complete .form-label label, -.page-form-complete .form-input input, -.page-form-complete .form-input select.align, -.page-form-complete .timezone { - position: absolute; - top: 50%; - transform: translateY(-50%); -} - -.page-form-complete .form-label label { - text-align: right; - right: 0; - padding: 0 20px; -} - -.page-form-complete .label-name { - font-weight: bold; -} - -.page-form-complete .label-desc { - font-size: 0.8em; -} - -.page-form-complete input[type="text"], -.page-form-complete input[type="password"], -.page-form-complete textarea { +.footer-container { margin: 0; + color: var(--text-color); } -.page-form section { - margin: 10px 0 25px 0; +.footer-container a { + color: var(--primary); } -.page-form table { - margin: auto; - width: 90%; +.footer-container a:hover { + color: var(--primary-darken); } -.page-form table .order { - text-decoration: none; - color: #252525; +.linklist-item-title { + grid-area: header; } -.page-form table, .page-form th, .page-form td { - border-width: 1px 0; - border-style: solid; - border-color: #aaaaaa; +.linklist-item-thumbnail { + grid-area: thumb; } -.page-form th, .page-form td { - padding: 5px; - +.linklist-item-description { + grid-area: main; } -/* Awesomeplete fix */ -div.awesomplete { - width: inherit; - margin: 0 10px 0 0; - width: 100%; +.linklist-item-infos { + grid-area: footer; } -div.awesomplete > input { - display: inherit; -} +.grid-container, +.linklist-item { + display: grid; + grid-template-columns: auto 1fr; + grid-template-areas: + 'thumb header header' + 'thumb main main' + 'footer footer footer'; + gap: 10px; -div.awesomplete > ul { - z-index: 9999; -} - -.page-form .awesomplete { - width: 90%; -} - -.page-form .awesomplete input { - width: 100%; -} - -.page-form div.awesomplete > ul { - color: black; -} - -form[name="linkform"].page-form { - overflow: visible; -} - -@media screen and (max-width: 64em) { - .page-form-complete .form-label { - height: inherit; - } - - .page-form-complete .form-label label, - .page-form-complete .form-input input, - .page-form-complete .timezone { - position: inherit; - top: inherit; - transform: translateY(0); - } - - .page-form-complete .form-input input[type="checkbox"] { - position: absolute; - top: 50%; - right: 50%; - transform: translateY(-50%); - } - - .page-form-complete .form-input { - text-align: center; - } - - .page-form-complete .form-label label { - display: block; - text-align: left; - margin: 10px 0 0 0; - } - - .timezone-continent:after { - content:"\a\a"; - white-space: pre; - } - - .page-form-complete .radio-buttons { - text-align: left; - padding: 5px 15px; - } -} - -/** - * Page visitor (page form extended) - */ -.page-visitor { - color: #252525; -} - -#page404 { - color: #3f3f3f; -} - -/** - * EDIT LINK - */ -#editlinkform .created-date { - color: #767676; - margin-bottom: 10px; -} - -/** - * LOGIN - */ -#login-form .remember-me { - margin: 5px 0; -} - -/** - * Search results - */ -.search-result a { - color: white; - text-decoration: none; -} - -.search-result .label-tag { - border-color: white; -} - -.search-result .label-tag .remove { - border-left: white 1px solid; - padding: 0 0 0 5px; - margin: 0 0 0 5px; -} - -.search-result .label-private { - border: 1px solid white; -} - -/** - * TOOLS - */ -.tools-item { - margin: 10px 0; -} - -.tools-item .pure-button:hover { - background-image: none; - background-color: #1b926c; - color: #f5f5f5; -} - -/** - * PLUGIN ADMIN - */ -#pluginform .mobile-row { - font-size: 0.9em; -} - -#pluginform .more { - margin-top: 10px; -} - -@media screen and (max-width: 64em) { - #pluginform .main-row, #pluginform .main-row td { - border-bottom-style: none; - } - - #pluginform .mobile-row, #pluginform .mobile-row td { - border-top-style: none; - } -} - -/** - * IMPORT - */ -#import-field { - margin: 15px 0; -} - -/** - * TAG CLOUD - */ -#cloudtag { padding: 10px; - text-align: center; } -#cloudtag a { - color: #252525; - text-decoration: none; +.linklist-item-title h2 { + line-height: auto; } -#cloudtag a { - color: #1b926c; - text-decoration: none; +.page-form select, +input[type="text"], +input[type="checkbox"] { + color: var(--text-color); + background-color: var(--primary-lighten) !important; } -#cloudtag a:hover { - color: #252525; - text-decoration: none; +.page-form code, +.pure-alert code, +.markdown :not(pre) code { + color: var(--text-color); + background-color: var(--background-color-lighten); } -#cloudtag .count { - color: #7f7f7f; +.cloudtag-container a { + color: var(--primary); } -/** - * TAG LIST - */ -#taglist { - padding: 0 10px; +.cloudtag-container a:hover { + color: var(--primary-darken); } -#taglist a { - color: #252525; - text-decoration: none; +button { + color: var(--text-color); + background-color: var(--primary); + border: 0; + border-radius: 2px; + background-color: var(--main-color); + padding: 5.5px 7.2px; } -#taglist .count { - display: inline-block; - width: 35px; - text-align: right; - color: #7f7f7f; +button:hover { + color: var(--text-color-inverse); } -#taglist .rename-tag-form { - display: none; +.page-form textarea, +.page-form input[type="password"], +.page-form input[type="text"] { + border: medium none currentColor; + border-radius: 2px; + box-shadow: 0 1px 0 rgba(255, 255, 255, .078), 0 1px 1px rgba(0, 0, 0, .298) inset; + padding: 0 5px; + height: 30px; } -#taglist .delete-tag { - color: #ac2925; - display: none; +.searchform-block input[type="text"] { + border: medium none currentColor; + border-radius: 2px; + box-shadow: 0 1px 0 rgba(255, 255, 255, .078), 0 1px 1px rgba(0, 0, 0, .298) inset; + padding: 0 5px; + height: 30px; } -#taglist .rename-tag { - color: #0b5ea6; -} - -#taglist .validate-rename-tag { - color: #1b926c; -} - -/** - * Picture wall CSS - */ -.myShaarli_picwall { - background-color: #000; -} - -.myShaarli_picwall .pure-u-lg-4-5 { - margin:auto; - background-color: #000; - box-shadow: none; -} - -#picwall-container { - margin: 0 10px 10px 10px; - color: #252525; - background-color: #000; - clear: both; - text-align: center; -} - -.picwall-pictureframe { - margin: 2px; - background-color: #000; - z-index: 5; - position: relative; - display: inline-flex; - overflow: hidden; - text-align: center; - width: auto; - height: auto; - float: none; -} - -.b-lazy { - -webkit-transition: opacity 500ms ease-in-out; - -moz-transition: opacity 500ms ease-in-out; - -o-transition: opacity 500ms ease-in-out; - transition: opacity 500ms ease-in-out; - opacity: 0; -} -.b-lazy.b-loaded { - opacity: 1; -} - -.picwall-pictureframe img { - max-width: 100%; - height: auto; - color: transparent; - border-radius:.3em; -} /* Adapt the width of the image */ - -.picwall-pictureframe a { - text-decoration: none; -} - -/* CSS to show title when hovering an image - no javascript required. */ -.picwall-pictureframe span.info { - display: none; - font-family: Arial, sans-serif; +.picwall-container { + display: flex; + flex-wrap: wrap; + gap: .1rem; + justify-content: center; } .picwall-pictureframe:hover span.info { - display: block; - position: absolute; - top: 0; - left: 0; + background-color: rgba(0, 0, 0, .6); + color: var(--text-color); width: 100%; height: 100%; + padding: .1em; +} + +.awesomplete>ul { + color: var(--text-color-inverse); + background: var(--primary-lighten); +} + +.awesomplete mark { + background-color: var(--success); font-weight: bold; - font-size: 9pt; - color: #f5f5f5; - text-align: left; - background-color: rgba(0, 0, 0, 0.8); - overflow-wrap: break-word; } -/** - * DAILY - */ -.daily-desc { - color: #7f7f7f; - font-size: 0.8em; -} - -.daily-about a { - color: #343434; - text-decoration: none; -} - -.daily-about a:hover { - color: #7f7f7f; -} - -.daily-about h3:before, .daily-about h3:after { - display: block; - content:""; - background: linear-gradient(to right, #d5d4d4, #252525, #d5d4d4); - height: 1px; - width: 90%; - margin: 10px auto; -} - -.daily-entry { - padding: 0 10px; - clear: both; -} - -.daily-entry .daily-entry-title:after { - display: block; - content:""; - background: linear-gradient(to right, #fff, #515151, #fff); - height: 1px; - width: 70%; - margin: 5px auto; -} - -.daily-entry .daily-entry-title { - margin: 10px 0 0 0; -} - -.daily-entry .daily-entry-title a { - color: #000; - text-decoration: none; -} - -.daily-entry .daily-entry-description { - padding: 5px 5px 0 5px; - font-size: 0.9em; - text-align: justify; - word-wrap: break-word; -} - -.daily-entry .daily-entry-tags { - padding: 0 5px 5px 5px; - font-size: 0.8em; -} - -.daily-entry-thumbnail { - float: left; - margin: 15px 5px 5px 15px; -} - -.daily-entry-description a { - text-decoration: none; - color: #1b926c; -} - -.daily-entry-description a:hover { - text-shadow: 1px 1px #ddd; -} - -.daily-entry-description a:visited { - color: #20b988; -} - -/* - * Fix empty bookmarklet name in Firefox - */ -.pure-button { - -moz-user-select: auto; +.awesomplete>ul>li[aria-selected="true"], +.awesomplete>ul>li:hover { + background: var(--primary-darken); + color: var(--primary-text-contrast); } .tag-sort { - margin-top: 30px; - text-align: center; + margin-top: 1em; } -.tag-sort a { - display: inline-block; - margin: 0 15px; - color: white; - text-decoration: none; - font-weight: bold; - background-color: inherit; +.page-form { + margin: 0; } + +.container { + margin-top: 55px; +} + +.header-search, +.search-linklist { + padding: 0 0 10px 0; +} + +.pinned-link { + color: var(--error) !important; + } \ No newline at end of file diff --git a/tpl/myShaarli/daily.html b/tpl/myShaarli/daily.html index f26a053e..9368fe36 100644 --- a/tpl/myShaarli/daily.html +++ b/tpl/myShaarli/daily.html @@ -8,9 +8,9 @@ @@ -129,4 +129,3 @@ - diff --git a/tpl/myShaarli/includes.html b/tpl/myShaarli/includes.html index 6dc58ad7..a99e2071 100644 --- a/tpl/myShaarli/includes.html +++ b/tpl/myShaarli/includes.html @@ -8,16 +8,16 @@ - {if="strpos($formatter, 'markdown') !== false"} - + {/if} {loop="$plugins_includes.css_files"} - + {/loop} {if="is_file('data/user.css')"} - + {/if} + {if="$template === 'linklist' && ! empty($links) && count($links) === 1"} diff --git a/tpl/myShaarli/linklist.html b/tpl/myShaarli/linklist.html index fdb13bfc..1c7ab67f 100644 --- a/tpl/myShaarli/linklist.html +++ b/tpl/myShaarli/linklist.html @@ -136,21 +136,6 @@