Merge pull request #994 from ae-utbm/taiste

UV as package manager and election style fix
This commit is contained in:
thomas girod 2025-01-08 09:12:06 +01:00 committed by GitHub
commit 686d67410a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 2052 additions and 3041 deletions

14
.envrc
View File

@ -1,14 +1,6 @@
if [[ ! -f pyproject.toml ]]; then if [[ ! -d .venv ]]; then
log_error 'No pyproject.toml found. Use `poetry new` or `poetry init` to create one first.' log_error 'No .venv folder found. Use `uv sync` to create one first.'
exit 2 exit 2
fi fi
local VENV=$(poetry env list --full-path | cut -d' ' -f1) . .venv/bin/activate
if [[ -z $VENV || ! -d $VENV/bin ]]; then
log_error 'No poetry virtual environment found. Use `poetry install` to create one first.'
exit 2
fi
export VIRTUAL_ENV=$VENV
export POETRY_ACTIVE=1
PATH_add "$VENV/bin"

View File

@ -1,8 +0,0 @@
name: "Compile messages"
description: "Compile the gettext translation messages"
runs:
using: composite
steps:
- name: Setup project
run: poetry run ./manage.py compilemessages
shell: bash

View File

@ -9,43 +9,38 @@ runs:
packages: gettext packages: gettext
version: 1.0 # increment to reset cache version: 1.0 # increment to reset cache
- name: Set up python - name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.5.14"
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: "Set up Python"
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: "3.12" python-version-file: ".python-version"
- name: Load cached Poetry installation - name: Restore cached virtualenv
id: cached-poetry uses: actions/cache/restore@v4
uses: actions/cache@v3
with: with:
path: ~/.local key: venv-${{ runner.os }}-${{ hashFiles('.python-version') }}-${{ hashFiles('pyproject.toml') }}-${{ env.CACHE_SUFFIX }}
key: poetry-3 # increment to reset cache path: .venv
- name: Install Poetry
if: steps.cached-poetry.outputs.cache-hit != 'true'
shell: bash
run: curl -sSL https://install.python-poetry.org | python3 - --version 1.8.5
- name: Check pyproject.toml syntax
shell: bash
run: poetry check
- name: Load cached dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pypoetry
key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
restore-keys: |
${{ runner.os }}-poetry-
- name: Install dependencies - name: Install dependencies
run: poetry install --with docs,tests run: uv sync
shell: bash shell: bash
- name: Install xapian - name: Install Xapian
run: poetry run ./manage.py install_xapian run: uv run ./manage.py install_xapian
shell: bash shell: bash
- name: Save cached virtualenv
uses: actions/cache/save@v4
with:
key: venv-${{ runner.os }}-${{ hashFiles('.python-version') }}-${{ hashFiles('pyproject.toml') }}-${{ env.CACHE_SUFFIX }}
path: .venv
- name: Compile gettext messages - name: Compile gettext messages
run: poetry run ./manage.py compilemessages run: uv run ./manage.py compilemessages
shell: bash shell: bash

View File

@ -1,10 +0,0 @@
name: "Setup xapian"
description: "Setup the xapian indexes"
runs:
using: composite
steps:
- name: Setup xapian index
run: |
mkdir -p /dev/shm/search_indexes
ln -s /dev/shm/search_indexes sith/search_indexes
shell: bash

View File

@ -14,6 +14,8 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
with:
python-version-file: ".python-version"
- uses: pre-commit/action@v3.0.1 - uses: pre-commit/action@v3.0.1
with: with:
extra_args: --all-files extra_args: --all-files
@ -29,14 +31,15 @@ jobs:
- name: Check out repository - name: Check out repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- uses: ./.github/actions/setup_project - uses: ./.github/actions/setup_project
- uses: ./.github/actions/setup_xapian env:
- uses: ./.github/actions/compile_messages # To avoid race conditions on environment cache
CACHE_SUFFIX: ${{ matrix.pytest-mark }}
- name: Run tests - name: Run tests
run: poetry run coverage run -m pytest -m "${{ matrix.pytest-mark }}" run: uv run coverage run -m pytest -m "${{ matrix.pytest-mark }}"
- name: Generate coverage report - name: Generate coverage report
run: | run: |
poetry run coverage report uv run coverage report
poetry run coverage html uv run coverage html
- name: Archive code coverage results - name: Archive code coverage results
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:

View File

@ -37,12 +37,12 @@ jobs:
git fetch git fetch
git reset --hard origin/master git reset --hard origin/master
poetry install --with prod --without docs,tests uv sync --group prod
npm install npm install
poetry run ./manage.py install_xapian uv run ./manage.py install_xapian
poetry run ./manage.py migrate uv run ./manage.py migrate
poetry run ./manage.py collectstatic --clear --noinput uv run ./manage.py collectstatic --clear --noinput
poetry run ./manage.py compilemessages uv run ./manage.py compilemessages
sudo systemctl restart uwsgi sudo systemctl restart uwsgi

View File

@ -18,4 +18,4 @@ jobs:
path: .cache path: .cache
restore-keys: | restore-keys: |
mkdocs-material- mkdocs-material-
- run: poetry run mkdocs gh-deploy --force - run: uv run mkdocs gh-deploy --force

View File

@ -36,11 +36,11 @@ jobs:
git fetch git fetch
git reset --hard origin/taiste git reset --hard origin/taiste
poetry install --with prod --without docs,tests uv sync --group prod
npm install npm install
poetry run ./manage.py install_xapian uv run ./manage.py install_xapian
poetry run ./manage.py migrate uv run ./manage.py migrate
poetry run ./manage.py collectstatic --clear --noinput uv run ./manage.py collectstatic --clear --noinput
poetry run ./manage.py compilemessages uv run ./manage.py compilemessages
sudo systemctl restart uwsgi sudo systemctl restart uwsgi

2
.gitignore vendored
View File

@ -8,7 +8,7 @@ pyrightconfig.json
dist/ dist/
.vscode/ .vscode/
.idea/ .idea/
env/ .venv/
doc/html doc/html
data/ data/
galaxy/test_galaxy_state.json galaxy/test_galaxy_state.json

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.12

View File

@ -127,7 +127,7 @@ class Command(BaseCommand):
# dumps and sales are linked to the same customers # dumps and sales are linked to the same customers
# and or both ordered with the same key, so zipping them is valid # and or both ordered with the same key, so zipping them is valid
for dump, sale in zip(pending_dumps, sales): for dump, sale in zip(pending_dumps, sales, strict=False):
dump.dump_operation = sale dump.dump_operation = sale
AccountDump.objects.bulk_update(pending_dumps, ["dump_operation"]) AccountDump.objects.bulk_update(pending_dumps, ["dump_operation"])

View File

@ -3,6 +3,7 @@ import { registerComponent } from "#core:utils/web-components";
import type { RecursivePartial, TomSettings } from "tom-select/dist/types/types"; import type { RecursivePartial, TomSettings } from "tom-select/dist/types/types";
const productParsingRegex = /^(\d+x)?(.*)/i; const productParsingRegex = /^(\d+x)?(.*)/i;
const codeParsingRegex = / \((\w+)\)$/;
function parseProduct(query: string): [number, string] { function parseProduct(query: string): [number, string] {
const parsed = productParsingRegex.exec(query); const parsed = productParsingRegex.exec(query);
@ -21,6 +22,18 @@ export class CounterProductSelect extends AutoCompleteSelectBase {
protected attachBehaviors(): void { protected attachBehaviors(): void {
this.allowMultipleProducts(); this.allowMultipleProducts();
this.parseCodes();
}
private parseCodes(): void {
// We guess the code from the product name so we can prioritize search on it
// If no code is found, we just ignore it and everything still is fine
for (const option of Object.values(this.widget.options)) {
const match = codeParsingRegex.exec(option.text);
if (match !== null) {
option.code = match[1];
}
}
} }
private allowMultipleProducts(): void { private allowMultipleProducts(): void {
@ -60,6 +73,10 @@ export class CounterProductSelect extends AutoCompleteSelectBase {
} }
protected tomSelectSettings(): RecursivePartial<TomSettings> { protected tomSelectSettings(): RecursivePartial<TomSettings> {
/* We disable the dropdown on focus because we're going to always autofocus the widget */ /* We disable the dropdown on focus because we're going to always autofocus the widget */
return { ...super.tomSelectSettings(), openOnFocus: false }; return {
...super.tomSelectSettings(),
openOnFocus: false,
searchField: ["code", "text"],
};
} }
} }

View File

@ -726,7 +726,7 @@ class TestCounterStats(TestCase):
"nickname": user.nick_name, "nickname": user.nick_name,
"perm_sum": perm_time, "perm_sum": perm_time,
} }
for user, perm_time in zip(users, perm_times) for user, perm_time in zip(users, perm_times, strict=False)
] ]
def test_top_customer(self): def test_top_customer(self):
@ -741,7 +741,7 @@ class TestCounterStats(TestCase):
"nickname": user.nick_name, "nickname": user.nick_name,
"selling_sum": sale_amount, "selling_sum": sale_amount,
} }
for user, sale_amount in zip(users, sale_amounts) for user, sale_amount in zip(users, sale_amounts, strict=False)
] ]

View File

@ -462,6 +462,6 @@ def test_update_balance():
# put everything at zero to be sure the amounts were wrong beforehand # put everything at zero to be sure the amounts were wrong beforehand
customers_qs.update(amount=0) customers_qs.update(amount=0)
customers_qs.update_amount() customers_qs.update_amount()
for customer, amount in zip(customers, [40, 10, 20, 40, 0]): for customer, amount in zip(customers, [40, 10, 20, 40, 0], strict=False):
customer.refresh_from_db() customer.refresh_from_db()
assert customer.amount == amount assert customer.amount == amount

View File

@ -311,16 +311,16 @@ pour savoir tout ce qui ne fonctionne pas,
et surtout pour récolter toutes les informations et surtout pour récolter toutes les informations
nécessaires à la réparation des bugs. nécessaires à la réparation des bugs.
### Poetry ### UV
[Utiliser Poetry](https://python-poetry.org/docs/basic-usage/) [UV](https://docs.astral.sh/uv/)
Poetry est un utilitaire qui permet de créer et gérer UV est un utilitaire qui permet de créer et gérer
des environnements Python de manière simple et intuitive. des environnements Python de manière simple et intuitive.
Il permet également de gérer et mettre à jour Il permet également de gérer et mettre à jour
le fichier de dépendances. le fichier de dépendances.
L'avantage d'utiliser poetry L'avantage d'utiliser uv
(et les environnements virtuels en général) (et les environnements virtuels en général)
est de pouvoir gérer plusieurs projets différents est de pouvoir gérer plusieurs projets différents
en parallèle puisqu'il permet d'avoir sur sa en parallèle puisqu'il permet d'avoir sur sa
@ -329,7 +329,7 @@ donc plusieurs versions d'une même dépendance
dans plusieurs projets différents sans impacter dans plusieurs projets différents sans impacter
le système sur lequel le tout est installé. le système sur lequel le tout est installé.
Poetry possède également l'avantage par rapport à un simple venv UV possède également l'avantage par rapport à un simple venv
que les versions exactes de toutes les dépendances, que les versions exactes de toutes les dépendances,
y compris celles utilisées par d'autres dépendances, y compris celles utilisées par d'autres dépendances,
sont consignées dans un fichier `.lock`. sont consignées dans un fichier `.lock`.
@ -338,10 +338,15 @@ configurés avec le même fichier lock utiliseront
exactement les mêmes versions des mêmes dépendances, exactement les mêmes versions des mêmes dépendances,
y compris si celles-ci ne sont pas indiquées explicitement. y compris si celles-ci ne sont pas indiquées explicitement.
Les dépendances utilisées par poetry sont déclarées UV se charge même de télécharger la bonne version de Python
automatiquement !
Les dépendances utilisées par uv sont déclarées
dans le fichier `pyproject.toml`, dans le fichier `pyproject.toml`,
situé à la racine du projet. situé à la racine du projet.
Aussi, uv est rapide, genre TRÈS TRÈS rapide ⚡️
### Ruff ### Ruff
[Site officiel](https://astral.sh/ruff) [Site officiel](https://astral.sh/ruff)

View File

@ -41,6 +41,7 @@ l'éditer et enfin le compiler au format binaire pour qu'il soit lu par le serve
./manage.py makemessages \ ./manage.py makemessages \
--locale=fr \ --locale=fr \
-e py,jinja \ -e py,jinja \
--ignore=.venv \
--ignore=node_modules \ --ignore=node_modules \
--add-location=file --add-location=file
@ -49,6 +50,7 @@ l'éditer et enfin le compiler au format binaire pour qu'il soit lu par le serve
--locale=fr \ --locale=fr \
-d djangojs \ -d djangojs \
-e js,ts \ -e js,ts \
--ignore=.venv \
--ignore=node_modules \ --ignore=node_modules \
--ignore=staticfiles/generated \ --ignore=staticfiles/generated \
--add-location=file --add-location=file

View File

@ -52,11 +52,11 @@ Pour gérer ça plus simplement,
nous utilisons le logiciel python [pre-commit](https://pre-commit.com/) nous utilisons le logiciel python [pre-commit](https://pre-commit.com/)
qui permet de contrôller leur installation via un fichier yaml. qui permet de contrôller leur installation via un fichier yaml.
Le logiciel est installé par défaut par poetry. Le logiciel est installé par défaut par uv.
Il suffit ensuite de lancer : Il suffit ensuite de lancer :
```bash ```bash
pre-commit install uv run pre-commit install
``` ```
Une fois que vous avez fait cette commande, pre-commit Une fois que vous avez fait cette commande, pre-commit
tournera automatiquement chaque fois que vous ferez tournera automatiquement chaque fois que vous ferez
@ -65,7 +65,7 @@ un nouveau commit.
Il est également possible d'appeler soi-même les pre-commits : Il est également possible d'appeler soi-même les pre-commits :
```bash ```bash
pre-commit run --all-files uv run pre-commit run --all-files
``` ```
@ -80,8 +80,8 @@ pre-commit run --all-files
Pour utiliser Ruff, placez-vous à la racine du projet et lancez la commande suivante : Pour utiliser Ruff, placez-vous à la racine du projet et lancez la commande suivante :
```bash ```bash
ruff format # pour formatter le code uv run ruff format # pour formatter le code
ruff check # pour linter le code uv run ruff check # pour linter le code
``` ```
Ruff va alors faire son travail sur l'ensemble du projet puis vous dire Ruff va alors faire son travail sur l'ensemble du projet puis vous dire

View File

@ -64,10 +64,10 @@ Commencez par installer les dépendances système :
source ~/.zshrc source ~/.zshrc
``` ```
Puis, installez les dépendances poetry nécessaires en prod : Puis, installez les dépendances nécessaires en prod :
```bash ```bash
poetry install --with prod uv sync --group prod
``` ```
!!! info !!! info
@ -158,7 +158,7 @@ DATABASES = {
Enfin, créez vos données : Enfin, créez vos données :
```bash ```bash
poetry run ./manage.py populate uv run ./manage.py populate
``` ```
!!! note !!! note
@ -253,7 +253,7 @@ Enfin, démarrez le serveur Django :
```bash ```bash
cd /repertoire/du/projet cd /repertoire/du/projet
poetry run ./manage.py runserver 8001 uv run ./manage.py runserver 8001
``` ```
Et c'est bon, votre reverse-proxy est prêt à tourner devant votre serveur. Et c'est bon, votre reverse-proxy est prêt à tourner devant votre serveur.

View File

@ -2,11 +2,10 @@
Certaines dépendances sont nécessaires niveau système : Certaines dépendances sont nécessaires niveau système :
- poetry - uv
- libssl - libssl
- libjpeg - libjpeg
- zlib1g-dev - zlib1g-dev
- python
- gettext - gettext
### Installer WSL ### Installer WSL
@ -62,26 +61,13 @@ cd /mnt/<la_lettre_du_disque>/vos/fichiers/comme/dhab
sudo apt upgrade sudo apt upgrade
``` ```
Puis, si ce n'est pas déjà fait, installez Python : Installez les dépendances :
```bash
sudo apt install python3
# on sait jamais
sudo apt install python-is-python3
```
Si vous utilisez Ubuntu 22.04 ou Ubuntu 24.04,
votre version de Python devrait être compatible
par défaut avec celle du projet.
Si ce n'est pas le cas, nous vous conseillons
d'utiliser [pyenv](https://github.com/pyenv/pyenv)
Puis installez les autres dépendances :
```bash ```bash
sudo apt install build-essential libssl-dev libjpeg-dev zlib1g-dev python-dev npm \ sudo apt install curl build-essential libssl-dev \
libffi-dev python-dev-is-python3 pkg-config \ libjpeg-dev zlib1g-dev npm libffi-dev pkg-config \
gettext git pipx gettext git
curl -LsSf https://astral.sh/uv/install.sh | sh
pipx install poetry==1.8.5
``` ```
=== "Arch Linux" === "Arch Linux"
@ -89,9 +75,7 @@ cd /mnt/<la_lettre_du_disque>/vos/fichiers/comme/dhab
```bash ```bash
sudo pacman -Syu # on s'assure que les dépôts et le système sont à jour sudo pacman -Syu # on s'assure que les dépôts et le système sont à jour
sudo pacman -S python sudo pacman -S uv gcc git gettext pkgconf npm
sudo pacman -S gcc git gettext pkgconf python-poetry npm
``` ```
=== "macOS" === "macOS"
@ -100,8 +84,7 @@ cd /mnt/<la_lettre_du_disque>/vos/fichiers/comme/dhab
Il est également nécessaire d'avoir installé xcode Il est également nécessaire d'avoir installé xcode
```bash ```bash
brew install git python pipx npm brew install git uv npm
pipx install poetry==1.8.5
# Pour bien configurer gettext # Pour bien configurer gettext
brew link gettext # (suivez bien les instructions supplémentaires affichées) brew link gettext # (suivez bien les instructions supplémentaires affichées)
@ -111,6 +94,10 @@ cd /mnt/<la_lettre_du_disque>/vos/fichiers/comme/dhab
Si vous rencontrez des erreurs lors de votre configuration, n'hésitez pas à vérifier l'état de votre installation homebrew avec :code:`brew doctor` Si vous rencontrez des erreurs lors de votre configuration, n'hésitez pas à vérifier l'état de votre installation homebrew avec :code:`brew doctor`
!!!note
Python ne fait pas parti des dépendances puisqu'il est automatiquement
installé par uv.
## Finaliser l'installation ## Finaliser l'installation
@ -122,9 +109,9 @@ git clone https://github.com/ae-utbm/sith.git
cd sith cd sith
# Création de l'environnement et installation des dépendances # Création de l'environnement et installation des dépendances
poetry install # Dépendances backend uv sync
npm install # Dépendances frontend npm install # Dépendances frontend
poetry run ./manage.py install_xapian uv run ./manage.py install_xapian
``` ```
!!!note !!!note
@ -149,19 +136,16 @@ echo 'SITH_URL = "localhost:8000"' >> sith/settings_custom.py
Enfin, nous pouvons lancer les commandes suivantes : Enfin, nous pouvons lancer les commandes suivantes :
```bash ```bash
# Activation de l'environnement virtuel
poetry shell
# Prépare la base de données # Prépare la base de données
python ./manage.py setup uv run ./manage.py setup
# Installe les traductions # Installe les traductions
python ./manage.py compilemessages uv run ./manage.py compilemessages
``` ```
!!!note !!!note
Pour éviter d'avoir à utiliser la commande `poetry shell` Pour éviter d'avoir à utiliser la commande `uv run`
systématiquement, il est possible de consulter [direnv](../howto/direnv.md). systématiquement, il est possible de consulter [direnv](../howto/direnv.md).
## Démarrer le serveur de développement ## Démarrer le serveur de développement
@ -172,7 +156,7 @@ et se placer à la racine du projet.
Il suffit ensuite d'utiliser cette commande : Il suffit ensuite d'utiliser cette commande :
```bash ```bash
python manage.py runserver uv run ./manage.py runserver
``` ```
!!!note !!!note
@ -198,14 +182,8 @@ Cette commande génère la documentation à
chacune de ses modifications, chacune de ses modifications,
inutile de relancer le serveur à chaque fois. inutile de relancer le serveur à chaque fois.
!!!note
Les dépendances pour la documentation sont optionnelles.
Avant de commencer à travailler sur la doc, il faut donc les installer
avec la commande `poetry install --with docs`
```bash ```bash
mkdocs serve uv run mkdocs serve
``` ```
## Lancer les tests ## Lancer les tests
@ -215,13 +193,13 @@ la commande suivante :
```bash ```bash
# Lancer tous les tests # Lancer tous les tests
pytest uv run pytest
# Lancer les tests de l'application core # Lancer les tests de l'application core
pytest core uv run pytest core
# Lancer les tests de la classe UserRegistrationTest de core # Lancer les tests de la classe UserRegistrationTest de core
pytest core/tests/tests_core.py::TestUserRegistration uv run pytest core/tests/tests_core.py::TestUserRegistration
``` ```
!!!note !!!note
@ -231,10 +209,10 @@ pytest core/tests/tests_core.py::TestUserRegistration
vous pouvez exécutez pytest ainsi : vous pouvez exécutez pytest ainsi :
```bash ```bash
pytest -m "not slow" uv run pytest -m "not slow"
# vous pouvez toujours faire comme au-dessus # vous pouvez toujours faire comme au-dessus
pytest core -m "not slow" uv run pytest core -m "not slow"
``` ```
A l'inverse, vous pouvez ne faire tourner que les tests A l'inverse, vous pouvez ne faire tourner que les tests

View File

@ -72,19 +72,20 @@ sith/
├── .gitattributes ├── .gitattributes
├── .gitignore ├── .gitignore
├── .mailmap ├── .mailmap
├── .env.exemple
├── manage.py (26) ├── manage.py (26)
├── mkdocs.yml (27) ├── mkdocs.yml (27)
├── poetry.lock ├── uv.lock
├── pyproject.toml (28) ├── pyproject.toml (28)
├── .venv/ (29)
├── .python-version (30)
└── README.md └── README.md
``` ```
</div> </div>
1. Dossier contenant certaines actions réutilisables 1. Dossier contenant certaines actions réutilisables
dans des workflows Github. Par exemple, l'action dans des workflows Github. Par exemple, l'action
`setup-project` installe poetry puis appelle `setup-project` installe uv puis appelle
la commande `poetry install`. configure l'environnement de développement
2. Dossier contenant les fichiers de configuration 2. Dossier contenant les fichiers de configuration
des workflows Github. des workflows Github.
Par exemple, le workflow `docs.yml` compile Par exemple, le workflow `docs.yml` compile
@ -127,6 +128,8 @@ sith/
avec ses plugins et sa table des matières. avec ses plugins et sa table des matières.
28. Le fichier où sont déclarés les dépendances et la configuration 28. Le fichier où sont déclarés les dépendances et la configuration
de certaines d'entre elles. de certaines d'entre elles.
29. Dossier d'environnement virtuel généré par uv
30. Fichier qui contrôle quel version de python utiliser pour le projet
## L'application principale ## L'application principale

View File

@ -106,7 +106,7 @@ class Basket(models.Model):
products = Product.objects.filter(id__in=ids).order_by("id") products = Product.objects.filter(id__in=ids).order_by("id")
# items and products are sorted in the same order # items and products are sorted in the same order
sales = [] sales = []
for item, product in zip(items, products): for item, product in zip(items, products, strict=False):
sales.append( sales.append(
Selling( Selling(
label=product.name, label=product.name,

View File

@ -15,8 +15,8 @@ $min_col_width: 100px;
flex-direction: row; flex-direction: row;
gap: $gap; gap: $gap;
> input, >input,
> label { >label {
margin: 0; margin: 0;
} }
@ -25,12 +25,12 @@ $min_col_width: 100px;
} }
} }
.election_vote { #page #content {
overflow-x: scroll !important; overflow-x: clip;
} }
.election_table { .election_table {
width: 100%; width: inherit;
>.lists { >.lists {
display: flex; display: flex;
@ -93,16 +93,24 @@ $min_col_width: 100px;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin: 0; margin: 0;
row-gap: 10px;
padding: $padding; padding: $padding;
width: 100%; width: 100%;
>.role_text { >.role_text {
display: flex;
flex-direction: column;
>h4 { >h4 {
margin: 0; margin: 0;
} }
>p { >p {
flex-grow: 1;
margin-top: .5em; margin-top: .5em;
text-wrap: auto;
text-align: left;
} }
} }
@ -112,9 +120,9 @@ $min_col_width: 100px;
align-items: center; align-items: center;
gap: $gap; gap: $gap;
> button, >button,
> button > i, >button>i,
> a { >a {
width: 20px; width: 20px;
height: 20px; height: 20px;
background-color: #e9e9e9; background-color: #e9e9e9;
@ -127,23 +135,23 @@ $min_col_width: 100px;
justify-content: center; justify-content: center;
&:hover, &:hover,
&:hover > i { &:hover>i {
background-color: #fff; background-color: #fff;
} }
} }
> button { >button {
width: 30px; width: 30px;
height: 30px; height: 30px;
} }
> button[disabled] { >button[disabled] {
background-color: #eee; background-color: #eee;
cursor: not-allowed; cursor: not-allowed;
>i, >i,
&:hover, &:hover,
&:hover > i { &:hover>i {
background-color: #eee; background-color: #eee;
} }
} }
@ -178,12 +186,12 @@ $min_col_width: 100px;
width: 100%; width: 100%;
gap: $gap; gap: $gap;
>input[type="radio"]:checked + label, >input[type="radio"]:checked+label,
>input[type="checkbox"]:checked + label { >input[type="checkbox"]:checked+label {
background-color: lightgray; background-color: lightgray;
border-radius: 10px; border-radius: 10px;
>figure>.edit_btns>a:hover{ >figure>.edit_btns>a:hover {
background-color: #fff; background-color: #fff;
} }
} }
@ -215,7 +223,9 @@ $min_col_width: 100px;
margin: 0; margin: 0;
text-align: center; text-align: center;
} }
.candidate_program { .candidate_program {
text-wrap: auto;
margin: 5px 0; margin: 5px 0;
} }
} }
@ -228,7 +238,7 @@ $min_col_width: 100px;
right: $gap; right: $gap;
gap: $gap; gap: $gap;
> a { >a {
width: 20px; width: 20px;
height: 20px; height: 20px;
background-color: #e9e9e9; background-color: #e9e9e9;
@ -253,40 +263,44 @@ $min_col_width: 100px;
} }
} }
.election_details { #content {
margin: .5em 0;
}
.buttons { .election_details {
display: flex; margin: .5em 0;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: $gap;
}
.button {
border: none;
color: black;
text-decoration: none;
background-color: $primary-neutral-light-color;
padding: 0.4em;
margin: 0.1em;
font-size: 1.18em;
border-radius: 5px;
box-shadow: #dfdfdf 0 0 1px;
cursor: pointer;
&:hover {
color: black;
background: #d4d4d4;
} }
&_send { .buttons {
background-color: #59aee2; display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: $gap;
}
.button {
border: none;
color: black;
text-decoration: none;
background-color: $primary-neutral-light-color;
padding: 0.4em;
margin: 0.1em;
font-size: 1.18em;
border-radius: 5px;
box-shadow: #dfdfdf 0 0 1px;
cursor: pointer;
&:hover { &:hover {
background-color: rgb(130, 186, 235); color: black;
background: #d4d4d4;
}
&_send {
background-color: #59aee2;
&:hover {
background-color: rgb(130, 186, 235);
}
} }
} }
} }

View File

@ -4,12 +4,11 @@
{{ object.title }} {{ object.title }}
{% endblock %} {% endblock %}
{% block head %}
{{ super() -}}
<link rel="stylesheet" href="{{ static('election/css/election.scss') }}">
{%- endblock %}
{% block additional_css %} {% block additional_css %}
<link rel="stylesheet" href="{{ static('election/css/election.scss') }}">
{% endblock %}
{% block additional_js %}
<script src="{{ static('bundled/vendored/jquery.shorten.min.js') }}"></script> <script src="{{ static('bundled/vendored/jquery.shorten.min.js') }}"></script>
{% endblock %} {% endblock %}
@ -47,7 +46,6 @@
{% csrf_token %} {% csrf_token %}
<table class="election_table"> <table class="election_table">
{%- set election_lists = election.election_lists.all() -%} {%- set election_lists = election.election_lists.all() -%}
<caption></caption>
<thead class="lists"> <thead class="lists">
<tr> <tr>
<th class="column" style="width: {{ 100 / (election_lists.count() + 1) }}%">{% trans %}Blank vote{% endtrans %}</th> <th class="column" style="width: {{ 100 / (election_lists.count() + 1) }}%">{% trans %}Blank vote{% endtrans %}</th>
@ -204,7 +202,7 @@
$('.role_description').shorten({ $('.role_description').shorten({
moreText: "{% trans %}Show more{% endtrans %}", moreText: "{% trans %}Show more{% endtrans %}",
lessText: "{% trans %}Show less{% endtrans %}", lessText: "{% trans %}Show less{% endtrans %}",
showChars: 50 showChars: 300
}); });
$('.candidate_program').shorten({ $('.candidate_program').shorten({
moreText: "{% trans %}Show more{% endtrans %}", moreText: "{% trans %}Show more{% endtrans %}",

2758
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +1,86 @@
[tool.poetry] [project]
name = "Sith" name = "Sith"
version = "3" version = "3"
description = "Le web Sith de l'AE" description = "Le web Sith de l'AE"
readme = "README.md"
authors = [ authors = [
"Skia <skia@hya.sk>", {name = "Skia", email = "skia@hya.sk"},
"klmp200 <antoine@bartuccio.fr>", {name = "klmp200", email = "antoine@bartuccio.fr"},
"Krophil <pierre.brunet@krophil.fr>", {name = "Krophil", email = "pierre.brunet@krophil.fr"},
"Maréchal <thgirod@hotmail.com>", {name = "Maréchal", email = "thgirod@hotmail.com"},
"Och <francescowitz68@gmail.com>", {name = "Och", email = "francescowitz68@gmail.com"},
"tleb <tleb@openmailbox.org>", {name = "tleb", email = "tleb@openmailbox.org"},
"Soldat <ryan-68@live.fr>", {name = "Soldat", email = "ryan-68@live.fr"},
"Nabos <gnikwo@hotmail.com>", {name = "Nabos", email = "gnikwo@hotmail.com"},
"Terre <jbaptiste.lenglet+git@gmail.com>", {name = "Terre", email = "jbaptiste.lenglet+git@gmail.com"},
"Lo-J <renaudg779@gmail.com>", {name = "Lo-J", email = "renaudg779@gmail.com"},
"Vial <robin.trioux@utbm.fr>" {name = "Vial", email = "robin.trioux@utbm.fr"},
] ]
documentation = "https://sith-ae.readthedocs.io/" license = {text = "GPL-3.0-only"}
requires-python = "<4.0,>=3.12"
dependencies = [
"Django<5.0.0,>=4.2.17",
"django-ninja<2.0.0,>=1.3.0",
"django-ninja-extra<1.0.0,>=0.21.8",
"Pillow<12.0.0,>=11.0.0",
"mistune<4.0.0,>=3.0.2",
"django-jinja<3.0.0,>=2.11.0",
"cryptography<45.0.0,>=44.0.0",
"django-phonenumber-field<9.0.0,>=8.0.0",
"phonenumbers<9.0.0,>=8.13.52",
"reportlab<5.0.0,>=4.2.5",
"django-haystack<4.0.0,>=3.3.0",
"xapian-haystack<4.0.0,>=3.1.0",
"libsass<1.0.0,>=0.23.0",
"django-ordered-model<4.0.0,>=3.7.4",
"django-simple-captcha<1.0.0,>=0.6.0",
"python-dateutil<3.0.0.0,>=2.9.0.post0",
"sentry-sdk<3.0.0,>=2.19.2",
"Jinja2<4.0.0,>=3.1.4",
"django-countries<8.0.0,>=7.6.1",
"dict2xml<2.0.0,>=1.7.6",
"Sphinx<6,>=5",
"tomli<3.0.0,>=2.2.1",
"django-honeypot<2.0.0,>=1.2.1",
"pydantic-extra-types<3.0.0,>=2.10.1",
"ical<9.0.0,>=8.3.0",
]
[project.urls]
homepage = "https://ae.utbm.fr/" homepage = "https://ae.utbm.fr/"
license = "GPL-3.0-only" documentation = "https://sith-ae.readthedocs.io/"
[tool.poetry.dependencies] [dependency-groups]
python = "^3.12" prod = [
Django = "^4.2.17" "psycopg[c]<4.0.0,>=3.2.3",
django-ninja = "^1.3.0" "redis[hiredis]<6.0.0,>=5.2.0",
django-ninja-extra = "^0.21.8" ]
Pillow = "^11.0.0" dev = [
mistune = "^3.0.2" "django-debug-toolbar<5.0.0,>=4.4.6",
django-jinja = "^2.11.0" "ipython<9.0.0,>=8.30.0",
cryptography = "^44.0.0" "pre-commit<5.0.0,>=4.0.1",
django-phonenumber-field = "^8.0.0" "ruff<1.0.0,>=0.8.3",
phonenumbers = "^8.13.52" "djhtml<4.0.0,>=3.0.7",
reportlab = "^4.2.5" "faker<34.0.0,>=33.1.0",
django-haystack = "^3.3.0" "rjsmin<2.0.0,>=1.2.3",
xapian-haystack = "^3.1.0" ]
libsass = "^0.23.0" tests = [
django-ordered-model = "^3.7.4" "freezegun<2.0.0,>=1.5.1",
django-simple-captcha = "^0.6.0" "pytest<9.0.0,>=8.3.4",
python-dateutil = "^2.9.0.post0" "pytest-cov<7.0.0,>=6.0.0",
sentry-sdk = "^2.19.2" "pytest-django<5.0.0,>=4.9.0",
Jinja2 = "^3.1.4" "model-bakery<2.0.0,>=1.20.0",
django-countries = "^7.6.1" ]
dict2xml = "^1.7.6" docs = [
Sphinx = "^5" # Needed for building xapian "mkdocs<2.0.0,>=1.6.1",
tomli = "^2.2.1" "mkdocs-material<10.0.0,>=9.5.47",
django-honeypot = "^1.2.1" "mkdocstrings<1.0.0,>=0.27.0",
pydantic-extra-types = "^2.10.1" "mkdocstrings-python<2.0.0,>=1.12.2",
ical = "^8.3.0" "mkdocs-include-markdown-plugin<8.0.0,>=7.1.2",
]
[tool.poetry.group.prod.dependencies] [tool.uv]
# deps used in prod, but unnecessary for development default-groups = ["dev", "tests", "docs"]
# The C extra triggers compilation against system libs during install.
# Removing it would switch psycopg to a slower full-python implementation
psycopg = {extras = ["c"], version = "^3.2.3"}
redis = {extras = ["hiredis"], version = "^5.2.0"}
[tool.poetry.group.prod]
optional = true
[tool.poetry.group.dev.dependencies]
# deps used for development purposes, but unneeded in prod
django-debug-toolbar = "^4.4.6"
ipython = "^8.30.0"
pre-commit = "^4.0.1"
ruff = "^0.8.3" # Version used in pipeline is controlled by pre-commit hooks in .pre-commit.config.yaml
djhtml = "^3.0.7"
faker = "^33.1.0"
rjsmin = "^1.2.3"
[tool.poetry.group.tests.dependencies]
# deps used for testing purposes
freezegun = "^1.5.1" # used to test time-dependent code
pytest = "^8.3.4"
pytest-cov = "^6.0.0"
pytest-django = "^4.9.0"
model-bakery = "^1.20.0"
[tool.poetry.group.docs.dependencies]
# deps used to work on the documentation
mkdocs = "^1.6.1"
mkdocs-material = "^9.5.47"
mkdocstrings = "^0.27.0"
mkdocstrings-python = "^1.12.2"
mkdocs-include-markdown-plugin = "^7.1.2"
[tool.poetry.group.docs]
optional = true
[tool.xapian] [tool.xapian]
version = "1.4.25" version = "1.4.25"
@ -131,7 +126,3 @@ convention = "google"
DJANGO_SETTINGS_MODULE = "sith.settings" DJANGO_SETTINGS_MODULE = "sith.settings"
python_files = ["tests.py", "test_*.py", "*_tests.py"] python_files = ["tests.py", "test_*.py", "*_tests.py"]
markers = ["slow"] markers = ["slow"]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

1788
uv.lock generated Normal file

File diff suppressed because it is too large Load Diff