From b39b43386dd76fc32fc8416e05083251924937a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20M=C3=A9taireau?= Date: Sun, 17 Dec 2023 17:12:01 +0100 Subject: [PATCH] docs: use mkdocs --- .readthedocs.yaml | 12 ++ README.md | 310 +----------------------------- docs/assets/logo.png | Bin 0 -> 66604 bytes docs/changelog.md | 11 ++ docs/contributing/contributing.md | 62 ++++++ docs/contributing/naming.md | 66 +++++++ docs/contributing/releasing.md | 13 ++ docs/deploy.md | 107 +++++++++++ docs/development/architecture.md | 59 ++++++ docs/index.md | 3 + docs/install.md | 126 ++++++++++++ docs/requirements.txt | 3 + docs/settings.md | 29 +++ la_chariotte/settings.py | 2 +- mkdocs.yml | 47 +++++ pyproject.toml | 12 +- 16 files changed, 553 insertions(+), 309 deletions(-) create mode 100644 .readthedocs.yaml create mode 100644 docs/assets/logo.png create mode 100644 docs/changelog.md create mode 100644 docs/contributing/contributing.md create mode 100644 docs/contributing/naming.md create mode 100644 docs/contributing/releasing.md create mode 100644 docs/deploy.md create mode 100644 docs/development/architecture.md create mode 100644 docs/index.md create mode 100644 docs/install.md create mode 100644 docs/requirements.txt create mode 100644 docs/settings.md create mode 100644 mkdocs.yml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..3a2576b --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,12 @@ +version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +mkdocs: + configuration: mkdocs.yml + +python: + install: + - requirements: docs/requirements.txt diff --git a/README.md b/README.md index 5764df4..9a70a1f 100644 --- a/README.md +++ b/README.md @@ -1,308 +1,12 @@ # La Chariotte - + -La Chariotte est une application de gestion de commandes groupées. +La Chariotte is a web application to handle grouped orders. -Elle est publiée sous licence libre Affero GPL, développée et maintenue par [Hashbang](https://hashbang.fr/). +- [Public server](https://chariotte.fr) +- [Online documentation](https://docs.chariotte.fr) -## Contribuer - -Si vous souhaitez contribuer au projet de la Chariotte, merci beaucoup ! - -La permière étape est de cloner le projet et d'obtenir le statut de développeur. Une fois que c'est fait, vous pouvez : - -- choisir une tâche dans le board que vous voulez réaliser, et vous l'assigner - si vous ne savez pas quelle tâche faire, n'hésitez pas à écrire à laetitia@chariotte.fr -- créer une nouvelle branche **à partir de develop** dont le nom dira ce que vous voulez faire -- réaliser la tâche, sans oublier d'écrire et de lancer les tests (voir plus bas) -- créer une Merge Request, contenant le plus de détails possible sur ce que vous avez fait - -Ensuite, un mainteneur de la Chariotte pourra relire votre code et proposer des améliorations/poser des questions si nécessaire. Seuls les mainteneurs peuvent merger dans develop et main. - -Encore merci, et bon code ! - -## Versions - semantic versionning - -Les fonctionnalités développées dans les différentes versions sont listées dans le fichier [CHANGELOG.md](https://gitlab.com/hashbangfr/la_chariotte/-/blob/main/CHANGELOG.md). - -Étant donné un numéro de version MAJEUR.MINEUR.CORRECTIF, il faut incrémenter : - -le numéro de version MAJEUR quand il y a des changements non rétrocompatibles, -le numéro de version MINEUR quand il y a des ajouts de fonctionnalités rétrocompatibles, -le numéro de version de CORRECTIF quand il y a des corrections d’anomalies rétrocompatibles. - -La version est à mettre à jour dans `la_chariotte.__init__.py` lors des releases. - -## Développement - -Cloner le projet : -```bash -git clone git@gitlab.com:hashbangfr/la_chariotte.git -``` - -### Environnement virtuel. - -Pour éviter que les bibliothèques nécessaires au projet ne rentrent en conflit avec celles de votre système, il peut être utile d'installer un environnement virtuel : - -```bash -python3 -m venv .venv -``` - -Une fois l'environnement virtuel installé, vous pouvez l'activer : - -```bash -source .venv/bin/activate -``` - -### Dépendances - -La Chariotte utilise Weasyprint pour la génération de PDFs, qui nécessite certains paquets sur votre machine. Vous pouvez suivre [les instructions de cette page](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation) pour les installer. - -Ensuite, vous pouvez récupérer les dépendances python : -```bash -pip install -r requirements-dev.txt -``` - -### Base de données - -La Chariotte nécessite une base de données, et est actuellement compatible avec PostgreSQL ([instructions d'installation ici](https://www.digitalocean.com/community/tutorials/how-to-install-postgresql-on-ubuntu-20-04-quickstart)). - -Pour le développement, nous vous conseillons de créer une base de données nommée ```chariotte``` accessible par l'utilisateur et le mot de passe du même nom. - -Dans une invite postgresql, entrez ceci : - -```SQL -CREATE ROLE chariotte WITH - LOGIN - NOSUPERUSER - CREATEDB - NOCREATEROLE - INHERIT - NOREPLICATION - CONNECTION LIMIT -1 - PASSWORD 'xxxxxx'; -``` -```SQL -CREATE DATABASE chariotte - WITH - OWNER = chariotte - ENCODING = 'UTF8' - CONNECTION LIMIT = -1 - IS_TEMPLATE = False; -``` - -### Fichier de configuration - -Créez un fichier de configuration dans lequel vous pourrez spécifier la configuration qui est utile pour vous. Nous allons le nommer ici ```local_settings.py```. - -```python -from la_chariotte.settings import * - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": "chariotte", - "USER": "chariotte", - "PASSWORD": "chariotte", - "HOST": "localhost", - } -} -``` - -### Lancement du serveur - -Tout devrait être maintenant prêt pour pouvoir lancer le serveur : - -```shell -python manage.py migrate --settings=local_settings -python manage.py runserver --settings=local_settings -``` - -Pour créer un superutilisateur, qui aura accès à l'interface admin (/admin) : -```shell -python manage.py createsuperuser --settings=local_settings -``` - -### Travailler sur le frontend - -Nous utilisons bulma comme framework CSS. Vous pouvez l'installer en utilisant la commande suivante : - -```bash -npm install bulma -``` - -Vous aurez aussi besoin de sass : -```bash -npm install -g sass -``` - -Vérifiez que vous utilisez la bonne version de sass : - -```bash -sass --version -# used for developement: 1.59.3 compiled with dart2js 2.19.4 -``` - -Recompiler dès que des changements sont detectés dans les fichiers scss. - -```bash -sass --watch --no-source-map ./la_chariotte/static/sass/style.sass:./la_chariotte/static/css/app.css -``` - -Ou bien préférez compiler vers CSS au coup à coup : -```bash -sass --no-source-map ./la_chariotte/static/sass/style.sass:./la_chariotte/static/css/app.css -``` - -### Lancer les tests - -Lancer les tests avec pytest : -```bash -pytest -``` - -Si il y a des erreurs [isort](https://pycqa.github.io/isort/), on peut lancer isort pour trier les fichiers : - -```bash -isort . -``` - -Si il y a des erreurs [black](https://black.readthedocs.io/en/stable/), on peut lancer black pour linter le code : - -```bash -black . -``` - -### Tests de l'envoi de mails - -Pour tester l'apparence des mails, on peut utiliser [Sendria](https://github.com/msztolcman/sendria) : -```bash -pip install sendria -sendria --db mails.sqlite -$NAVIGATOR http://127.0.0.1:1080 -``` - -Attention : si vous n'activez pas `sendria --db mails.sqlite` quand vous travaillez en local, vous aurez une erreur en commandant : `[Errno 111] Connection refused`. - -## Architecture de l'application - -Les différentes applications Django créées sont : - -- ``order``, pour gérer tout ce qui tourne autour des commandes -- ``accounts``, pour gérer la création de comptes. Pour la connexion, la déconnexion et le changement de mot de passe, on utilise l'application auth intégrée à Django. -- ``mail``, pour l'envoi des mails. - -A l'état actuel, le diagramme de classes est le suivant : - -```mermaid -classDiagram - GroupedOrder "item_set" <-- Item - GroupedOrder "order_set" <-- Order - Order "ordered_items" <-- OrderedItem - Item "orders" <-- OrderedItem - OrderAuthor "author" <-- Order - CustomUser "grouped_orders" <-- GroupedOrder - - class GroupedOrder{ - name - deadline : DateTime - delivery_date : Date - place - description - orga : CustomUser - total_price - } - class Item{ - name - grouped_order : GroupedOrder - ordered_nb - total_price - max_limit - } - class Order{ - grouped_order : GroupedOrder - author : OrderAuthor - price - created_date - note - } - class OrderedItem{ - order : Order - nb - item : Item - } - class OrderAuthor { - first_name - last_name - phone - email - } - class CustomUser{ - first_name - last_name - email - } -``` - -## Conventions de nommage - -### Nommage des branches - -Chaque branche doit être nommée sous la forme `category[/ticket-ref]/description`. -*category* détermine le type de modification que vous comptez effectuer au sein de la branche : - - - `feature` pour ajouter une fonctionnalité au projet - - `fix` pour corriger un bug - - `test` pour effectuer des changements n'étant associé à aucun besoin déjà spécifié - - `doc` pour effectuer des changements relatifs à la documentation (readme notamment) - - `refactor` pour effectuer un changement au sein du code sans conséquence sur l'application - -Vous pouvez ajouter une catégorie si le besoin s'en fait sentir, tout en s'assurant que le sens soit bien compréhensible de l'extérieur. - -Entre la catégorie et la description peut s'insérer la référence du ticket Gitlab relatif à la branche. - -La description de la branche, en anglais et en kebab-case, doit décrire de manière très succinte l'objectif de la branche : dans quel but elle a été créée sans entrer dans le détail. - - Bons exemples : - - - `feature/72/improve-pdf-generation` - - `fix/117/deadline-increments-on-duplicated-commands` - - `doc/explain-conventions` - - `refactor/99/is_ongoing-to-is_open` - - Mauvais exemples : - - - `fix-some-stuff` - - `readme` - - `feature/add-a-cool-ui-element-when-the-cursor-passes-over-the-calendar-where-the-user-can-also-choose-the-associated-hour` - - `fix/edit-order/views/order.py-to-replace-is_ongoing-by-is_open` - -### Noms des commits - -Les noms de commits doivent être constitués de deux parties : un sujet et un corps (optionnel). -Le sujet fait office de titre du commit ; il se suffit souvent à lui-même et doit expliquer brièvement le but du commit. -Si besoin, le message de commit peut être enrichi d'un corps qui permet de détailler plus en détails ce qui a été modifié et pourquoi (mais pas comment !). - -Les noms des commits doivent respecter ces 7 règles d'or pour garantir une homogénéité dans le projet: - -- Sépare le sujet du corps avec une ligne vide -- Limite la ligne de sujet à 50 caractères -- Met une majuscule à la ligne de de sujet -- Ne finis pas la ligne de sujet avec un point -- Utilise le mode impératif dans la ligne de sujet (IMPORTANT) -- Limite la taille de ligne (*wrap*) du corps à 72 caractères -- Utilise le corps pour expliquer le quoi et le pourquoi (et pas le comment) - -Les détails de cette méthode sont détaillés dans ce tuto : https://cbea.ms/git-commit/ - -Bons exemples : - -- `Refactor system X for readability` -- `Remove deprecated method` -- `Release version 1.4.2` - - Mauvais exemples : - -- `Changing behaviour of X` -- `add submit button.` -- `Edit order.py line 72 to improve efficiency by adding recursive algorithm` +This project has been initially developped and published by [Hashbang](https:// +hashbang.fr/) under an [Affero GPLv3](LICENSE) license, and is now maintained +and developed by a team of volunteers. diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ab6ce16df2f06190e8655055760af9587c7ed8b6 GIT binary patch literal 66604 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 H?O*>72%_|i literal 0 HcmV?d00001 diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..42333f1 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,11 @@ +# Changelog + +Given a version number `MAJOR`.`MINOR`.`PATCH`: + +- `MAJOR` is updated when there are **incompatible changes**, +- `MINOR` is updated when there are **backwards-compatible feature additions**, +- `PATCH` is updated when there are **backwards-compatible bug fixes**. + +### 1.0.0 (date) + +- Basic features. diff --git a/docs/contributing/contributing.md b/docs/contributing/contributing.md new file mode 100644 index 0000000..6454e09 --- /dev/null +++ b/docs/contributing/contributing.md @@ -0,0 +1,62 @@ +# Contributing + +You want to contribute to the project ? First, thank you very much! We'll try to do our best to help you getting started. + +The first step is to clone the project, you can find more information about that in the [getting started guide](../install.md). Once that's done, you can: + +- choose a task [on the board]() and assign it to yourself - if you don't know which task to do, feel free to reach to us. +- create a new branch **from develop** naming it to reflect what you want to do +- complete the task, without forgetting to write and run tests (see below) +- create a Merge Request, containing as many details as possible about what you have done + +Then, a maintainer will be able to review your code and suggest improvements/ask questions if necessary. Only maintainers can merge into develop and main. + +Thanks again, and happy coding! + +## Working on the frontend + +To recompile the files as soon as changes are detected in the scss files. + +```bash +sass --watch --no-source-map ./la_chariotte/static/sass/style.sass:./la_chariotte/static/css/app.css +``` + +## Running tests + +Run tests with `pytest`: + +```bash +pytest +``` + +## Formatting your code + +Once you're ready, you'll need to ensure your code is formatted the right way. +We're using [isort](https://pycqa.github.io/isort/) to fix the import order, +and [black](https://black.readthedocs.io/en/stable/) for general linting. + +You can run them with: + +```bash +isort . +black . +``` + +## Working with emails + +To test the appearance of emails, you can use [Sendria](https://github.com/msztolcman/sendria): + +```bash +pip install sendria +sendria --db mails.sqlite +$NAVIGATOR http://127.0.0.1:1080 +``` + +## Docs + +We're using [MkDocs](https://www.mkdocs.org/) for this documentation. If you want to +build it locally, just run: + +```bash +mkdocs serve +``` diff --git a/docs/contributing/naming.md b/docs/contributing/naming.md new file mode 100644 index 0000000..c5f8780 --- /dev/null +++ b/docs/contributing/naming.md @@ -0,0 +1,66 @@ +# Naming Conventions + +We're trying to enforce some naming rules for our work. The goal is to be consistent. + +## Git branches + +Each git branch should be named in the form `category[/ticket-ref]/description`. + +`category` determines the type of change you intend to make within the branch: + +- `feature` to add a feature to the project +- `fix` to correct a bug +- `test` for making changes that are not associated with any specified need +- `doc` for making changes related to documentation (readme in particular) +- `refactor` for making a change within the code without consequence on the application + +You can add a category if needed, making sure the meaning is easily understandable from the outside. + +Between the category and description, the Gitlab ticket reference related to the branch may be inserted. + +The branch description, in English and in kebab-case, must briefly describe the purpose of the branch: the purpose for which it was created without going into detail. + +Good examples: + +- `feature/72/improve-pdf-generation` +- `fix/117/deadline-increments-on-duplicated-commands` +- `doc/explain-conventions` +- `refactor/99/is_ongoing-to-is_open` + +Bad examples: + +- `fix-some-stuff` +- `readme` +- `feature/add-a-cool-ui-element-when-the-cursor-passes-over-the-calendar-where-the-user-can-also-choose-the-associated-hour` +- `fix/edit-order/views/order.py-to-replace-is_ongoing-by-is_open` + +## Git commits + +Commit names should consist of two parts: a subject and a body (optional). + +The subject acts as the title of the commit; it often suffices by itself and should briefly explain the purpose of the commit. +If needed, the commit message can be enriched with a body that allows for more detailed explanations of what was modified and why (but not how!). + +Commit names must follow these 7 golden rules to ensure uniformity in the project: + +- Separate the subject from the body with a blank line +- Limit the subject line to 50 characters +- Capitalize the subject line +- Do not end the subject line with a period +- Use imperative mood in the subject line (IMPORTANT) +- Limit the line size (*wrap*) of the body to 72 characters +- Use the body to explain the what and the why (and not the how) + +Details of this method can be found in this tutorial: https://cbea.ms/git-commit/ + +Good examples: + +- `Refactor system X for readability` +- `Remove deprecated method` +- `Release version 1.4.2` + +Bad examples: + +- `Changing behaviour of X` +- `add submit button.` +- `Edit order.py line 72 to improve efficiency by adding recursive algorithm` diff --git a/docs/contributing/releasing.md b/docs/contributing/releasing.md new file mode 100644 index 0000000..ffa1fd4 --- /dev/null +++ b/docs/contributing/releasing.md @@ -0,0 +1,13 @@ +# Releasing a new version + +## Semantic versioning + +The features developed in the various versions are listed in the [changelog](../changelog.md) file. + +Given a version number MAJOR.MINOR.PATCH, increment: + +- the MAJOR version when there are incompatible changes, +- the MINOR version when there are backwards-compatible feature additions, +- the PATCH version when there are backwards-compatible bug fixes. + +The version should be updated in `la_chariotte.__init__.py` during releases. diff --git a/docs/deploy.md b/docs/deploy.md new file mode 100644 index 0000000..7f1723a --- /dev/null +++ b/docs/deploy.md @@ -0,0 +1,107 @@ +# How to deploy + +!!! info "This is how **we** deploy" + + This page describes how the main instance is deployed, and is mainly meant as a + way to share the knowledge. You can obviously do things differently. + +## Services + +"La chariotte" uses different domains: + +- **docs.chariotte.fr**, the docs you are reading now. It's handled by [readthedocs.org](https://readthedocs.org). +- **chariotte.fr**, the main instance. It's deployed on Alwaysdata +- **blog.chariotte.fr**, our blog. It's [a static website](https://gitlab.com/la-chariotte/la-chariotte.gitlab.io) deployed on Gitlab pages. + +## The main instance + +### Alwaysdata, our hosting provider + +[Alwaysdata](https://www.alwaysdata.com) offers [a free plan for open source +projects](https://www.alwaysdata.com/en/open-source/), which we are using for +the main instance of la chariotte. + +Thanks to them for supporting open source! + +### Getting access + +To get access, you'll need to generate an ssh keypair, and give your public key to a known admin. + +```bash +ssh-keygen +``` + +This will generate a private a public key. You need to share the **public** key. +On unix systems, it's stored under `~/.ssh/id_rsa.pub` by default. + +### Connecting to ssh + +Once your key is generated and you're known to the server, you can connect there. + +```bash +ssh chariotte@ssh-chariotte.alwaysdata.net +``` + +### Configuration file + +The chariotte application is run by [uwsgi](https://uwsgi-docs.readthedocs.io/ +en/latest/), managed by AlwaysData. + +The production settings are stored in `~/ la_chariotte/prod_settings.py`, and +the secrets are defined in the admin console. + +### The different sites + +In the AD console, here are the defined sites: + +- `app.chariotte.fr`, redirecting to `chariotte.fr` +- `chariotte.fr/static`, hosting the static files, it just serves the collected static files stored in `/static/` +- `chariotte.fr`, the main website, defined in the next section + +`chariotte.fr` is configured as a Python WSGI app: + +- application path: `/la_chariotte/la_chariotte/wsgi.py` +- working directory: `/la_chariotte` +- venv location: `/venv` + +Environment variables: + +``` +DJANGO_SETTINGS_MODULE=prod_settings +``` + +### How to deploy + +To deploy a new version, we'll need to: + +- get the new code +- update the database +- collect the static files +- restart the daemon + +Here's how: + +```bash +# Activate the venv +source venv/bin/activate +cd la_chariotte + +# Get the code +git fetch +git checkout tag # if we're using a tag, otherwise, just checkout the main branch + +python manage.py updatedb +python manage.py collectstatic +``` + +Then you'll need to restart the server from AD's interface. + +### What about SSL certificates? + +The SSL certificates are issued directly by AlwaysData (they use [Let's Encrypt] +(https://letsencrypt.org/) behind the scenes) + +## Mails + +Mails are hosted by alwaysdata, as part of their opensource plan. + diff --git a/docs/development/architecture.md b/docs/development/architecture.md new file mode 100644 index 0000000..9268e47 --- /dev/null +++ b/docs/development/architecture.md @@ -0,0 +1,59 @@ +# Application Architecture + +The various Django apps created are: + +- ``order``, to manage everything around the orders +- ``accounts``, to manage account creation. For logging in, logging out, and changing passwords, we use Django’s built-in auth application. +- ``mail``, for sending emails. + +At the moment, the class diagram is as follows: + +```mermaid +classDiagram + GroupedOrder "item_set" <-- Item + GroupedOrder "order_set" <-- Order + Order "ordered_items" <-- OrderedItem + Item "orders" <-- OrderedItem + OrderAuthor "author" <-- Order + CustomUser "grouped_orders" <-- GroupedOrder + + class GroupedOrder{ + name + deadline : DateTime + delivery_date : Date + place + description + orga : CustomUser + total_price + } + class Item{ + name + grouped_order : GroupedOrder + ordered_nb + total_price + max_limit + } + class Order{ + grouped_order : GroupedOrder + author : OrderAuthor + price + created_date + note + } + class OrderedItem{ + order : Order + nb + item : Item + } + class OrderAuthor { + first_name + last_name + phone + email + } + class CustomUser{ + first_name + last_name + email + } +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..38eb6b4 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,3 @@ +# La chariotte - Documentation + +![Logo](assets/logo.png) diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000..0664733 --- /dev/null +++ b/docs/install.md @@ -0,0 +1,126 @@ +First, clone the project + +```bash +git clone git@gitlab.com:la-chariotte/la_chariotte.git +``` + +## Virtual environment + +To prevent the project's necessary libraries from conflicting with those on your system, it may be beneficial to install a virtual environment: + +```bash +python3 -m venv .venv +``` + +Once the virtual environment is installed, you can activate it: + +```bash +source .venv/bin/activate +``` + +## Installing the dependencies + +!!! info "Weasyprint" + + We are using [Weasyprint](https://weasyprint.readthedocs.io/) for `.pdf` generation, which requires certain packages on your machine. You can follow [the instructions on this page](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation) to install them. + +Then, you can retrieve the Python dependencies: + +```bash +pip install -e ".[dev]" +``` + +And the frontend dependencies: + +=== "Yarn" + + ```bash + npm install + ``` + +=== "npm" + ```bash + yarn install + ``` + +## Setting up the database + +We recommend using PostgreSQL for now ([installation instructions here](https://www.digitalocean.com/community/tutorials/how-to-install-postgresql-on-ubuntu-20-04-quickstart)). + +For development, we recommend creating a database named ```chariotte``` accessible by the user and password of the same name. + +In a PostgreSQL prompt, enter this: + +```sql +CREATE ROLE chariotte WITH + LOGIN + NOSUPERUSER + CREATEDB + NOCREATEROLE + INHERIT + NOREPLICATION + CONNECTION LIMIT -1 + PASSWORD 'xxxxxx'; +``` +```sql +CREATE DATABASE chariotte + WITH + OWNER = chariotte + ENCODING = 'UTF8' + CONNECTION LIMIT = -1 + IS_TEMPLATE = False; +``` + +## Create a configuration file + +Create a local configuration file: + +```python title="local_settings.py" +from la_chariotte.settings import * + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": "chariotte", + "USER": "chariotte", + "PASSWORD": "chariotte", + "HOST": "localhost", + } +} +``` + +## Compile the CSS files + +We use bulma as a CSS framework. + +Make sure you are using the correct version of sass: + +```bash +sass --version +# used for development: 1.59.3 compiled with dart2js 2.19.4 +``` + +Recompile as soon as changes are detected in scss files. + +```bash +sass --watch --no-source-map ./la_chariotte/static/sass/style.sass:./la_chariotte/static/css/app.css +``` + +Or prefer to compile to CSS on a per-occurrence basis: +```bash +sass --no-source-map ./la_chariotte/static/sass/style.sass:./la_chariotte/static/css/app.css +``` + +## Start the server + +Everything should now be ready to start the server: + +```shell +python manage.py migrate --settings=local_settings +python manage.py runserver --settings=local_settings +``` + +To create a superuser, who will have access to the admin interface (/admin): +```shell +python manage.py createsuperuser +``` diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..12275a7 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +mkdocs==1.5.3 +pymdown-extensions==10.4 +mkdocs-material==9.4.14 diff --git a/docs/settings.md b/docs/settings.md new file mode 100644 index 0000000..4580658 --- /dev/null +++ b/docs/settings.md @@ -0,0 +1,29 @@ +# Settings + +Here are the useful settings you can define. We're generally extending [Django settings](https://docs.djangoproject.com/en/4.2/ref/settings/), so any setting there could be used here. + +This page documents the additional setting. + +## CONTACT_MAIL + +The contact mail that will be displayed at the bottom of the page. + +```python title="chariotte_settings.py" +CONTACT_MAIL = "name@example.org" +``` + +## GITLAB_LINK + +The URL to the git repository. + +```python title="chariotte_settings.py" +GITLAB_LINK = "https://gitlab.com/your-repository" +``` + +## PROJECT_NAME + +This is the main name of the project. By default it's set to `"La Chariotte"` + +```python title="chariotte_settings.py" +PROJECT_NAME = "Groupement d'achat du CRAC" +``` diff --git a/la_chariotte/settings.py b/la_chariotte/settings.py index 7c85c4d..284f5b9 100644 --- a/la_chariotte/settings.py +++ b/la_chariotte/settings.py @@ -7,7 +7,7 @@ from sentry_sdk.integrations.django import DjangoIntegration BASE_DIR = Path(__file__).resolve().parent.parent BASE_URL = os.getenv("BASE_URL", "http://127.0.0.1:8000") PROJECT_NAME = os.getenv("PROJECT_NAME", "La Chariotte") -GITLAB_LINK = "https://gitlab.com/hashbangfr/la_chariotte" +GITLAB_LINK = "https://gitlab.com/la-chariotte/la_chariotte" CONTACT_MAIL = "laetitia@chariotte.fr" # SECURITY WARNING: keep the secret key used in production secret! diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..2d6ca01 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,47 @@ +site_name: La chariotte +site_description: An application for grouped-orders +repo_name: la-chariotte/la_chariotte +repo_url: https://gitlab.com/la-chariotte/la_chariotte +nav: + - How-tos: + - Getting started: install.md + - Contributing: + - How to: contributing/contributing.md + - Naming conventions: contributing/naming.md + - Releasing: contributing/releasing.md + - Developer: + - Architecture: development/architecture.md + - Configuration: + - Settings: settings.md + - Deployment: deploy.md + - Changelog: changelog.md +theme: + name: material + homepage: https://chariotte.fr + palette: + - scheme: 'default' + media: '(prefers-color-scheme: light)' + primary: 'custom' + toggle: + icon: 'material/lightbulb' + name: 'Switch to dark mode' + - scheme: 'slate' + media: '(prefers-color-scheme: dark)' + primary: 'custom' + toggle: + icon: 'material/lightbulb-outline' + name: 'Switch to light mode' + features: + - navigation.sections + - navigation.footer +markdown_extensions: + - pymdownx.magiclink + - admonition + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + combine_header_slug: true diff --git a/pyproject.toml b/pyproject.toml index e3efe3f..577cfad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,11 +11,12 @@ dependencies = [ "django>=4,<5", "psycopg2-binary>=2,<3", "sentry-sdk<1", - "xhtml2pdf", - "icalendar", - "base36", - "django-weasyprint", - "html2text", + "xhtml2pdf>=0.2.11,<1", + "icalendar>=5.0.7,<6", + "base36>=0.1.1,<1", + "django-weasyprint==1.1.0.post1", # see below + "weasyprint==52.5", # pin weasyprint to not depend on latest libpango + "html2text>=2020.1.16", ] [tool.setuptools] @@ -39,6 +40,7 @@ dev = [ "pytest-django>=4,<5", "pytest-cov>=4,<5", "diff-cover>=4,<5", + "pymdown-extensions==10.4", "pytest-black<1", ]