diff --git a/.gitignore b/.gitignore index d26855f..ae1ea7d 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,5 @@ public/ # Vim recover files *~ + +.pre-commit-config.yaml diff --git a/accounts/forms.py b/accounts/forms.py index 75401dc..fce3b9e 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -1,5 +1,5 @@ -from django.forms import ModelForm, ValidationError from django.contrib.auth.models import User +from django.forms import ModelForm, ValidationError class AccountSettingsForm(ModelForm): diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py index 04be971..2d94174 100644 --- a/accounts/migrations/0001_initial.py +++ b/accounts/migrations/0001_initial.py @@ -8,27 +8,94 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), + ("auth", "0012_alter_user_first_name_max_length"), ] operations = [ migrations.CreateModel( - name='User', + name="User", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('email', models.EmailField(max_length=254, unique=True, verbose_name='adresse email')), - ('public_name', models.CharField(help_text='Ce nom est utilisé pour toutes les interactions publiques sur GestioJeux. Il doit être unique.', max_length=150, unique=True, verbose_name='nom ou pseudo')), - ('is_staff', models.BooleanField(default=False, help_text="Précise si l’utilisateur peut se connecter à ce site d'administration.", verbose_name='statut équipe')), - ('is_active', models.BooleanField(default=True, help_text='Précise si l’utilisateur doit être considéré comme actif. Décochez ceci plutôt que de supprimer le compte.', verbose_name='actif')), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "email", + models.EmailField( + max_length=254, unique=True, verbose_name="adresse email" + ), + ), + ( + "public_name", + models.CharField( + help_text="Ce nom est utilisé pour toutes les interactions publiques sur GestioJeux. Il doit être unique.", + max_length=150, + unique=True, + verbose_name="nom ou pseudo", + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Précise si l’utilisateur peut se connecter à ce site d'administration.", + verbose_name="statut équipe", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Précise si l’utilisateur doit être considéré comme actif. Décochez ceci plutôt que de supprimer le compte.", + verbose_name="actif", + ), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.Group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.Permission", + verbose_name="user permissions", + ), + ), ], options={ - 'verbose_name': 'utilisateur·ice', - 'verbose_name_plural': 'utilisateur·ice·s', + "verbose_name": "utilisateur·ice", + "verbose_name_plural": "utilisateur·ice·s", }, ), ] diff --git a/accounts/migrations/0002_delete_user.py b/accounts/migrations/0002_delete_user.py index c4f13a4..dd96f89 100644 --- a/accounts/migrations/0002_delete_user.py +++ b/accounts/migrations/0002_delete_user.py @@ -6,11 +6,11 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('accounts', '0001_initial'), + ("accounts", "0001_initial"), ] operations = [ migrations.DeleteModel( - name='User', + name="User", ), ] diff --git a/accounts/urls.py b/accounts/urls.py index 8577cf3..38f465e 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,5 +1,6 @@ from django.urls import include, path -from .views import PasswordChangeView, AccountSettingsView + +from .views import AccountSettingsView, PasswordChangeView app_name = "accounts" diff --git a/accounts/views.py b/accounts/views.py index 6bf66f4..9270fac 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,15 +1,10 @@ -from django.views.generic import TemplateView, RedirectView -from django.views.generic.edit import UpdateView -from django.shortcuts import redirect -from django.urls import reverse -from django.dispatch import receiver -from django.contrib.auth import logout as auth_logout +from django.contrib import messages from django.contrib.auth import user_logged_in, user_logged_out, user_login_failed from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.views import PasswordChangeView -from django.contrib import messages - -from urllib.parse import quote as urlquote +from django.dispatch import receiver +from django.urls import reverse +from django.views.generic.edit import UpdateView from .forms import AccountSettingsForm diff --git a/comments/apps.py b/comments/apps.py index ff01b77..5e25df2 100644 --- a/comments/apps.py +++ b/comments/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class CommentsConfig(AppConfig): - name = 'comments' + name = "comments" diff --git a/comments/tests.py b/comments/tests.py index 7ce503c..a39b155 100644 --- a/comments/tests.py +++ b/comments/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/comments/views.py b/comments/views.py index 950e636..2233940 100644 --- a/comments/views.py +++ b/comments/views.py @@ -1,10 +1,10 @@ -from django.views.generic import TemplateView, RedirectView -from django.views.generic.detail import SingleObjectMixin -from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib import messages -from django.http import Http404 +from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied -from django.shortcuts import redirect, get_object_or_404 +from django.http import Http404 +from django.shortcuts import get_object_or_404, redirect +from django.views.generic import RedirectView, TemplateView +from django.views.generic.detail import SingleObjectMixin class AddCommentView(LoginRequiredMixin, SingleObjectMixin, RedirectView): diff --git a/default.nix b/default.nix index 47ddc33..6e75ecd 100644 --- a/default.nix +++ b/default.nix @@ -6,6 +6,31 @@ let nix-pkgs = import sources.nix-pkgs { inherit pkgs; }; + check = (import sources.git-hooks).run { + src = ./.; + + hooks = { + # Python hooks + ruff.enable = true; + black.enable = true; + isort.enable = true; + + # Nix Hooks + statix.enable = true; + deadnix.enable = true; + rfc101 = { + enable = true; + + name = "RFC-101 formatting"; + entry = "${pkgs.lib.getExe pkgs.nixfmt-rfc-style}"; + files = "\\.nix$"; + }; + + # Misc Hooks + commitizen.enable = true; + }; + }; + python3 = pkgs.python3.override { packageOverrides = final: _: { inherit (nix-pkgs) @@ -14,7 +39,7 @@ let markdown-icons python-cas ; - authens = final.callPackage ./nix/authens {}; + authens = final.callPackage ./nix/authens { }; }; }; in @@ -23,7 +48,7 @@ in devShell = pkgs.mkShell { name = "gestiojeux.dev"; - packages = [ + packages = check.enabledPackages ++ [ (python3.withPackages (ps: [ ps.django ps.django-types @@ -53,5 +78,8 @@ in GESTIOJEUX_DEBUG = builtins.toJSON true; }; + shellHook = '' + ${check.shellHook} + ''; }; } diff --git a/gestiojeux/asgi.py b/gestiojeux/asgi.py index 5e97b9c..cb5582b 100644 --- a/gestiojeux/asgi.py +++ b/gestiojeux/asgi.py @@ -11,6 +11,6 @@ import os from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gestiojeux.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gestiojeux.settings") application = get_asgi_application() diff --git a/gestiojeux/urls.py b/gestiojeux/urls.py index d3bfaa8..63758bd 100644 --- a/gestiojeux/urls.py +++ b/gestiojeux/urls.py @@ -13,10 +13,11 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ -from django.contrib import admin -from django.urls import include, path + from django.conf import settings from django.conf.urls.static import static +from django.contrib import admin +from django.urls import include, path urlpatterns = [ path("admin/", admin.site.urls), diff --git a/gestiojeux/wsgi.py b/gestiojeux/wsgi.py index bca2fe9..a799c5c 100644 --- a/gestiojeux/wsgi.py +++ b/gestiojeux/wsgi.py @@ -11,6 +11,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gestiojeux.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gestiojeux.settings") application = get_wsgi_application() diff --git a/inventory/admin.py b/inventory/admin.py index 069d2bf..47c1ce7 100644 --- a/inventory/admin.py +++ b/inventory/admin.py @@ -1,7 +1,9 @@ from django.contrib import admin -from .models import Category, Tag, Game, GameComment + from comments.admin import CommentAdmin +from .models import Category, Game, GameComment, Tag + admin.site.register(Category) admin.site.register(Tag) admin.site.register(Game) diff --git a/inventory/forms.py b/inventory/forms.py index 12be68a..90be389 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -1,5 +1,6 @@ from loans.forms import BorrowForm + class BorrowGameForm(BorrowForm): error_css_class = "errorfield" required_css_class = "requiredfield" diff --git a/inventory/markdown.py b/inventory/markdown.py index ecc3d0b..0f0866a 100644 --- a/inventory/markdown.py +++ b/inventory/markdown.py @@ -1,6 +1,7 @@ import markdown from django.template.loader import get_template -from .models import Category, Tag, Game + +from .models import Category, Game, Tag class InventoryLinkProcessor(markdown.inlinepatterns.InlineProcessor): diff --git a/inventory/migrations/0001_initial.py b/inventory/migrations/0001_initial.py index eaab918..66ad8e6 100644 --- a/inventory/migrations/0001_initial.py +++ b/inventory/migrations/0001_initial.py @@ -1,9 +1,10 @@ # Generated by Django 3.1.2 on 2020-12-29 23:21 import autoslug.fields +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion + import website.validators @@ -17,71 +18,216 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Category', + name="Category", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='nom')), - ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(max_length=256, unique=True, verbose_name="nom"), + ), + ( + "slug", + autoslug.fields.AutoSlugField( + editable=False, populate_from="name", unique=True + ), + ), ], options={ - 'verbose_name': 'catégorie', - 'ordering': ['name'], + "verbose_name": "catégorie", + "ordering": ["name"], }, ), migrations.CreateModel( - name='Game', + name="Game", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=256, unique=True, verbose_name='titre du jeu')), - ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='title', unique=True)), - ('nb_player_min', models.PositiveSmallIntegerField(verbose_name='nombre de joueur·se·s minimum')), - ('nb_player_max', models.PositiveSmallIntegerField(verbose_name='nombre de joueur·se·s maximum')), - ('player_range', models.CharField(blank=True, help_text='Affichage personnalisé pour le nombre de joueur·se·s', max_length=256, verbose_name='nombre de joueur·se·s')), - ('duration', models.CharField(blank=True, max_length=256, verbose_name='durée de partie')), - ('game_designer', models.CharField(blank=True, max_length=256, verbose_name='game designer')), - ('illustrator', models.CharField(blank=True, max_length=256, verbose_name='illustrateur·trice')), - ('editor', models.CharField(blank=True, max_length=256, verbose_name='éditeur')), - ('description', models.TextField(blank=True, verbose_name='description')), - ('image', models.ImageField(blank=True, help_text="L'image doit peser 512 Kio au maximum", upload_to='game_img/', validators=[website.validators.MaxFileSizeValidator(512)], verbose_name='image')), - ('missing_elements', models.TextField(blank=True, verbose_name='pièces manquantes')), - ('category', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='inventory.category', verbose_name='catégorie')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "title", + models.CharField( + max_length=256, unique=True, verbose_name="titre du jeu" + ), + ), + ( + "slug", + autoslug.fields.AutoSlugField( + editable=False, populate_from="title", unique=True + ), + ), + ( + "nb_player_min", + models.PositiveSmallIntegerField( + verbose_name="nombre de joueur·se·s minimum" + ), + ), + ( + "nb_player_max", + models.PositiveSmallIntegerField( + verbose_name="nombre de joueur·se·s maximum" + ), + ), + ( + "player_range", + models.CharField( + blank=True, + help_text="Affichage personnalisé pour le nombre de joueur·se·s", + max_length=256, + verbose_name="nombre de joueur·se·s", + ), + ), + ( + "duration", + models.CharField( + blank=True, max_length=256, verbose_name="durée de partie" + ), + ), + ( + "game_designer", + models.CharField( + blank=True, max_length=256, verbose_name="game designer" + ), + ), + ( + "illustrator", + models.CharField( + blank=True, max_length=256, verbose_name="illustrateur·trice" + ), + ), + ( + "editor", + models.CharField( + blank=True, max_length=256, verbose_name="éditeur" + ), + ), + ( + "description", + models.TextField(blank=True, verbose_name="description"), + ), + ( + "image", + models.ImageField( + blank=True, + help_text="L'image doit peser 512 Kio au maximum", + upload_to="game_img/", + validators=[website.validators.MaxFileSizeValidator(512)], + verbose_name="image", + ), + ), + ( + "missing_elements", + models.TextField(blank=True, verbose_name="pièces manquantes"), + ), + ( + "category", + models.ForeignKey( + on_delete=django.db.models.deletion.RESTRICT, + to="inventory.category", + verbose_name="catégorie", + ), + ), ], options={ - 'verbose_name': 'jeu', - 'verbose_name_plural': 'jeux', - 'ordering': ['title'], + "verbose_name": "jeu", + "verbose_name_plural": "jeux", + "ordering": ["title"], }, ), migrations.CreateModel( - name='Tag', + name="Tag", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=256, unique=True, verbose_name='nom')), - ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(max_length=256, unique=True, verbose_name="nom"), + ), + ( + "slug", + autoslug.fields.AutoSlugField( + editable=False, populate_from="name", unique=True + ), + ), ], options={ - 'ordering': ['name'], + "ordering": ["name"], }, ), migrations.CreateModel( - name='GameComment', + name="GameComment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.TextField(verbose_name='texte')), - ('created_on', models.DateTimeField(auto_now_add=True, verbose_name='date de publication')), - ('modified_on', models.DateTimeField(auto_now=True, verbose_name='date de modification')), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='auteur·ice')), - ('commented_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='inventory.game', verbose_name='jeu')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("text", models.TextField(verbose_name="texte")), + ( + "created_on", + models.DateTimeField( + auto_now_add=True, verbose_name="date de publication" + ), + ), + ( + "modified_on", + models.DateTimeField( + auto_now=True, verbose_name="date de modification" + ), + ), + ( + "author", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="auteur·ice", + ), + ), + ( + "commented_object", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="comments", + to="inventory.game", + verbose_name="jeu", + ), + ), ], options={ - 'verbose_name': 'commentaire sur un jeu', - 'verbose_name_plural': 'commentaires sur des jeux', - 'ordering': ['created_on'], + "verbose_name": "commentaire sur un jeu", + "verbose_name_plural": "commentaires sur des jeux", + "ordering": ["created_on"], }, ), migrations.AddField( - model_name='game', - name='tags', - field=models.ManyToManyField(blank=True, to='inventory.Tag', verbose_name='tags'), + model_name="game", + name="tags", + field=models.ManyToManyField( + blank=True, to="inventory.Tag", verbose_name="tags" + ), ), ] diff --git a/inventory/migrations/0003_gameloan.py b/inventory/migrations/0003_gameloan.py index a0ac384..885e0d3 100644 --- a/inventory/migrations/0003_gameloan.py +++ b/inventory/migrations/0003_gameloan.py @@ -1,32 +1,52 @@ # Generated by Django 4.2.8 on 2024-05-02 09:30 import autoslug.fields -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('inventory', '0002_duration_range'), + ("inventory", "0002_duration_range"), ] operations = [ migrations.CreateModel( - name='GameLoan', + name="GameLoan", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='lent_object', unique=True)), - ('borrow_date', models.DateTimeField(auto_now_add=True)), - ('return_date', models.DateTimeField(null=True)), - ('mail', models.EmailField(max_length=254)), - ('lent_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.game', verbose_name='jeu emprunté')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "slug", + autoslug.fields.AutoSlugField( + editable=False, populate_from="lent_object", unique=True + ), + ), + ("borrow_date", models.DateTimeField(auto_now_add=True)), + ("return_date", models.DateTimeField(null=True)), + ("mail", models.EmailField(max_length=254)), + ( + "lent_object", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="inventory.game", + verbose_name="jeu emprunté", + ), + ), ], options={ - 'verbose_name': 'emprunt', - 'verbose_name_plural': 'emprunts', - 'ordering': ['borrow_date'], - 'abstract': False, + "verbose_name": "emprunt", + "verbose_name_plural": "emprunts", + "ordering": ["borrow_date"], + "abstract": False, }, ), ] diff --git a/inventory/migrations/0004_alter_category_options_alter_gameloan_options_and_more.py b/inventory/migrations/0004_alter_category_options_alter_gameloan_options_and_more.py index 282fb06..4bba337 100644 --- a/inventory/migrations/0004_alter_category_options_alter_gameloan_options_and_more.py +++ b/inventory/migrations/0004_alter_category_options_alter_gameloan_options_and_more.py @@ -6,26 +6,33 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('inventory', '0003_gameloan'), + ("inventory", "0003_gameloan"), ] operations = [ migrations.AlterModelOptions( - name='category', - options={'ordering': ['name'], 'verbose_name': 'étagère'}, + name="category", + options={"ordering": ["name"], "verbose_name": "étagère"}, ), migrations.AlterModelOptions( - name='gameloan', - options={'ordering': ['borrow_date'], 'permissions': [('can_see_loan_details', 'Can see loan details')], 'verbose_name': 'emprunt', 'verbose_name_plural': 'emprunts'}, + name="gameloan", + options={ + "ordering": ["borrow_date"], + "permissions": [("can_see_loan_details", "Can see loan details")], + "verbose_name": "emprunt", + "verbose_name_plural": "emprunts", + }, ), migrations.AlterField( - model_name='gameloan', - name='borrow_date', - field=models.DateTimeField(auto_now_add=True, verbose_name='Date d’emprunt'), + model_name="gameloan", + name="borrow_date", + field=models.DateTimeField( + auto_now_add=True, verbose_name="Date d’emprunt" + ), ), migrations.AlterField( - model_name='gameloan', - name='return_date', - field=models.DateTimeField(null=True, verbose_name='Date de retour'), + model_name="gameloan", + name="return_date", + field=models.DateTimeField(null=True, verbose_name="Date de retour"), ), ] diff --git a/inventory/migrations/0006_alter_game_options_alter_gamecomment_options_and_more.py b/inventory/migrations/0006_alter_game_options_alter_gamecomment_options_and_more.py index 5a9a1f3..611f2ea 100644 --- a/inventory/migrations/0006_alter_game_options_alter_gamecomment_options_and_more.py +++ b/inventory/migrations/0006_alter_game_options_alter_gamecomment_options_and_more.py @@ -1,7 +1,7 @@ # Generated by Django 4.2.11 on 2024-07-02 22:59 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/inventory/models.py b/inventory/models.py index 7a51cd2..aef138a 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -1,13 +1,13 @@ -from django.db import models -from django.urls import reverse -from django.core.exceptions import ValidationError import os import uuid from autoslug import AutoSlugField -from website.validators import MaxFileSizeValidator +from django.db import models +from django.urls import reverse + from comments.models import AbstractComment from loans.models import AbstractLoan +from website.validators import MaxFileSizeValidator class Category(models.Model): @@ -78,7 +78,6 @@ class Game(models.Model): def __str__(self): return self.title - def get_player_range(self): return "" @@ -104,13 +103,12 @@ class GameComment(AbstractComment): "inventory:modify_game_comment", args=(self.commented_object.slug, self.id) ) + class GameLoan(AbstractLoan): lent_object = models.ForeignKey( - Game, on_delete=models.CASCADE, - verbose_name="outil emprunté" + Game, on_delete=models.CASCADE, verbose_name="outil emprunté" ) class Meta(AbstractLoan.Meta): abstract = False permissions = [("can_see_loan_details", "Can see loan details")] - diff --git a/inventory/search_indexes.py b/inventory/search_indexes.py index b19c343..3976dac 100644 --- a/inventory/search_indexes.py +++ b/inventory/search_indexes.py @@ -1,5 +1,6 @@ from haystack import indexes -from .models import Category, Tag, Game + +from .models import Category, Game, Tag class CategoryIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/inventory/tables.py b/inventory/tables.py index 2b12a79..e57b0ae 100644 --- a/inventory/tables.py +++ b/inventory/tables.py @@ -24,7 +24,7 @@ class LoanTable(tables.Table): def render_slug(self, value, record): res = "" - if record.return_date == None: + if record.return_date is None: res = format_html( "Rendre l'outil", reverse("inventory:return_game", args=[value]), diff --git a/inventory/tests.py b/inventory/tests.py index 7ce503c..a39b155 100644 --- a/inventory/tests.py +++ b/inventory/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/inventory/urls.py b/inventory/urls.py index be66a52..0b60d11 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -1,10 +1,23 @@ from django.urls import path -from .views import (AddGameCommentView, BorrowGameView, CategoryListView, - CategoryView, DetailLoanView, GameListView, GameLoanView, - GameView, InventorySearchView, InventoryView, - ModifyGameCommentView, OngoingLoansView, QrCodeView, - ReturnGameView, TagListView, TagView) +from .views import ( + AddGameCommentView, + BorrowGameView, + CategoryListView, + CategoryView, + DetailLoanView, + GameListView, + GameLoanView, + GameView, + InventorySearchView, + InventoryView, + ModifyGameCommentView, + OngoingLoansView, + QrCodeView, + ReturnGameView, + TagListView, + TagView, +) app_name = "inventory" diff --git a/inventory/views.py b/inventory/views.py index a19b403..ac95ca2 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -1,5 +1,4 @@ import qrcode -from comments.views import AddCommentView, ModifyCommentView from django.contrib.auth.mixins import PermissionRequiredMixin from django.http import HttpResponse from django.urls import reverse @@ -8,6 +7,8 @@ from django_tables2.views import SingleTableView from haystack.forms import SearchForm from haystack.generic_views import SearchView from haystack.query import SearchQuerySet + +from comments.views import AddCommentView, ModifyCommentView from loans.views import BorrowView, DetailLoanView, ReturnView from .forms import BorrowGameForm diff --git a/loans/admin.py b/loans/admin.py index d5b22b0..2acaa33 100644 --- a/loans/admin.py +++ b/loans/admin.py @@ -1,5 +1,6 @@ from django.contrib import admin + class LoanAdmin(admin.ModelAdmin): list_display = ("lent_object", "borrow_date", "return_date") ordering = ("-borrow_date",) diff --git a/loans/apps.py b/loans/apps.py index afe898f..a022f7e 100644 --- a/loans/apps.py +++ b/loans/apps.py @@ -2,5 +2,5 @@ from django.apps import AppConfig class LoansConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'loans' + default_auto_field = "django.db.models.BigAutoField" + name = "loans" diff --git a/loans/forms.py b/loans/forms.py index cbfec56..27d8692 100644 --- a/loans/forms.py +++ b/loans/forms.py @@ -1,4 +1,5 @@ from django import forms + class BorrowForm(forms.Form): mail = forms.EmailField(label="Mail") diff --git a/loans/migrations/0001_initial.py b/loans/migrations/0001_initial.py index 29a4716..928bc51 100644 --- a/loans/migrations/0001_initial.py +++ b/loans/migrations/0001_initial.py @@ -1,8 +1,8 @@ # Generated by Django 4.2.8 on 2024-04-23 16:45 import autoslug.fields -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): @@ -10,24 +10,45 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('inventory', '0002_duration_range'), + ("inventory", "0002_duration_range"), ] operations = [ migrations.CreateModel( - name='Loan', + name="Loan", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='game', unique=True)), - ('borrow_date', models.DateTimeField(auto_now_add=True)), - ('return_date', models.DateTimeField(null=True)), - ('mail', models.EmailField(max_length=254)), - ('game', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='loans', to='inventory.game', verbose_name='jeu emprunté')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "slug", + autoslug.fields.AutoSlugField( + editable=False, populate_from="game", unique=True + ), + ), + ("borrow_date", models.DateTimeField(auto_now_add=True)), + ("return_date", models.DateTimeField(null=True)), + ("mail", models.EmailField(max_length=254)), + ( + "game", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="loans", + to="inventory.game", + verbose_name="jeu emprunté", + ), + ), ], options={ - 'verbose_name': 'emprunt', - 'verbose_name_plural': 'emprunts', - 'ordering': ['borrow_date'], + "verbose_name": "emprunt", + "verbose_name_plural": "emprunts", + "ordering": ["borrow_date"], }, ), ] diff --git a/loans/migrations/0002_delete_loan.py b/loans/migrations/0002_delete_loan.py index 2bc49b9..8674341 100644 --- a/loans/migrations/0002_delete_loan.py +++ b/loans/migrations/0002_delete_loan.py @@ -6,11 +6,11 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('loans', '0001_initial'), + ("loans", "0001_initial"), ] operations = [ migrations.DeleteModel( - name='Loan', + name="Loan", ), ] diff --git a/loans/models.py b/loans/models.py index ba8b23f..601c473 100644 --- a/loans/models.py +++ b/loans/models.py @@ -1,12 +1,12 @@ -from django.db import models from autoslug import AutoSlugField +from django.db import models from django.utils.timezone import now + class AbstractLoan(models.Model): - lent_object = None # Fill this with a foreign key in subclasses + lent_object = None # Fill this with a foreign key in subclasses slug = AutoSlugField(unique=True, populate_from="lent_object") - borrow_date = models.DateTimeField( - auto_now_add=True, verbose_name="Date d’emprunt") + borrow_date = models.DateTimeField(auto_now_add=True, verbose_name="Date d’emprunt") return_date = models.DateTimeField(null=True, verbose_name="Date de retour") mail = models.EmailField() @@ -14,7 +14,7 @@ class AbstractLoan(models.Model): class Meta: abstract = True - ordering=["borrow_date"] + ordering = ["borrow_date"] verbose_name = "emprunt" verbose_name_plural = "emprunts" @@ -26,9 +26,9 @@ class AbstractLoan(models.Model): self.save() @classmethod - def ongoing_loans(cls, obj = None): + def ongoing_loans(cls, obj=None): ongoing = cls.objects.filter(return_date=None) - if obj != None: + if obj is not None: return ongoing.filter(lent_object=obj) else: return ongoing diff --git a/loans/tests.py b/loans/tests.py index 7ce503c..a39b155 100644 --- a/loans/tests.py +++ b/loans/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/loans/views.py b/loans/views.py index ab061bf..deec539 100644 --- a/loans/views.py +++ b/loans/views.py @@ -1,25 +1,25 @@ -from django.views.generic import DetailView, FormView, RedirectView -from django.views.generic.detail import SingleObjectMixin from django.contrib import messages from django.shortcuts import redirect -from inventory.models import Game -from .models import AbstractLoan +from django.views.generic import DetailView, FormView, RedirectView +from django.views.generic.detail import SingleObjectMixin + from .forms import BorrowForm class ReturnView(SingleObjectMixin, RedirectView): # Inherited classes should contain: # model = LoanModel - # pattern_name = + # pattern_name = redirect_slug_field = "slug" - + permanent = False def get_redirect_url(self, *args, **kwargs): loan = self.get_object() loan.return_object() - kwargs[self.redirect_slug_field] = getattr(loan.lent_object, - loan.lent_object_slug_field) + kwargs[self.redirect_slug_field] = getattr( + loan.lent_object, loan.lent_object_slug_field + ) messages.success(self.request, "Rendu effectué.") if "next" in self.request.GET: return self.request.GET["next"] @@ -31,7 +31,7 @@ class BorrowView(SingleObjectMixin, FormView): # model = LentObjectModel # loan_model = LoanModel # template_name = "path/to/template.html" - form_class = BorrowForm # Update this for a more complex form + form_class = BorrowForm # Update this for a more complex form def get_initial(self): initial = super().get_initial() @@ -52,21 +52,22 @@ class BorrowView(SingleObjectMixin, FormView): loan.save() self.request.session["loan_mail"] = loan.mail messages.success(self.request, "Votre emprunt est enregistré.") - return redirect(self.success_pattern_name, - getattr(obj, loan.lent_object_slug_field)) + return redirect( + self.success_pattern_name, getattr(obj, loan.lent_object_slug_field) + ) + class DetailLoanView(DetailView): # Inherited classes should contain: # model = LentObjectModel # loan_model = LoanModel # template_name = "path/to/template.html" - + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) loans = self.loan_model.ongoing_loans(self.get_object()) is_borrowed = loans.exists() - context["is_borrowed"] = is_borrowed + context["is_borrowed"] = is_borrowed if is_borrowed: context["loan"] = loans.get() return context - diff --git a/manage.py b/manage.py index c365d27..28627f3 100755 --- a/manage.py +++ b/manage.py @@ -5,7 +5,7 @@ import sys def main(): - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gestiojeux.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gestiojeux.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -17,5 +17,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/npins/default.nix b/npins/default.nix index 4a7c372..43cead3 100644 --- a/npins/default.nix +++ b/npins/default.nix @@ -1,20 +1,34 @@ # Generated by npins. Do not modify; will be overwritten regularly let data = builtins.fromJSON (builtins.readFile ./sources.json); - version = data.version; + inherit (data) version; - mkSource = spec: - assert spec ? type; let + mkSource = + spec: + assert spec ? type; + let path = - if spec.type == "Git" then mkGitSource spec - else if spec.type == "GitRelease" then mkGitSource spec - else if spec.type == "PyPi" then mkPyPiSource spec - else if spec.type == "Channel" then mkChannelSource spec - else builtins.throw "Unknown source type ${spec.type}"; + if spec.type == "Git" then + mkGitSource spec + else if spec.type == "GitRelease" then + mkGitSource spec + else if spec.type == "PyPi" then + mkPyPiSource spec + else if spec.type == "Channel" then + mkChannelSource spec + else + builtins.throw "Unknown source type ${spec.type}"; in spec // { outPath = path; }; - mkGitSource = { repository, revision, url ? null, hash, ... }: + mkGitSource = + { + repository, + revision, + url ? null, + hash, + ... + }: assert repository ? type; # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository # In the latter case, there we will always be an url to the tarball @@ -23,19 +37,23 @@ let inherit url; sha256 = hash; # FIXME: check nix version & use SRI hashes }) - else assert repository.type == "Git"; builtins.fetchGit { - url = repository.url; - rev = revision; - # hash = hash; - }; + else + assert repository.type == "Git"; + builtins.fetchGit { + inherit (repository) url; + rev = revision; + # hash = hash; + }; - mkPyPiSource = { url, hash, ... }: + mkPyPiSource = + { url, hash, ... }: builtins.fetchurl { inherit url; sha256 = hash; }; - mkChannelSource = { url, hash, ... }: + mkChannelSource = + { url, hash, ... }: builtins.fetchTarball { inherit url; sha256 = hash; diff --git a/npins/sources.json b/npins/sources.json index 983b82d..e9978f7 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -1,5 +1,17 @@ { "pins": { + "git-hooks": { + "type": "Git", + "repository": { + "type": "GitHub", + "owner": "cachix", + "repo": "git-hooks.nix" + }, + "branch": "master", + "revision": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07", + "url": "https://github.com/cachix/git-hooks.nix/archive/0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07.tar.gz", + "hash": "0bmgc731c5rvky6qxc4f6gvgyiic8dna5dv3j19kya86idf7wn0p" + }, "nix-pkgs": { "type": "Git", "repository": { @@ -19,4 +31,4 @@ } }, "version": 3 -} \ No newline at end of file +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5d7bf33 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.isort] +profile = "black" diff --git a/suggestions/admin.py b/suggestions/admin.py index 417a747..b9e089b 100644 --- a/suggestions/admin.py +++ b/suggestions/admin.py @@ -1,7 +1,9 @@ from django.contrib import admin -from .models import Suggestion, SuggestionComment + from comments.admin import CommentAdmin +from .models import Suggestion, SuggestionComment + class SuggestionAdmin(admin.ModelAdmin): exclude = ("upvoting_users",) diff --git a/suggestions/apps.py b/suggestions/apps.py index 92f3afb..21fa69c 100644 --- a/suggestions/apps.py +++ b/suggestions/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class SuggestionsConfig(AppConfig): - name = 'suggestions' + name = "suggestions" diff --git a/suggestions/forms.py b/suggestions/forms.py index 22704ed..e14a076 100644 --- a/suggestions/forms.py +++ b/suggestions/forms.py @@ -1,4 +1,5 @@ from django import forms + from .models import Suggestion diff --git a/suggestions/migrations/0001_initial.py b/suggestions/migrations/0001_initial.py index f332d27..e536521 100644 --- a/suggestions/migrations/0001_initial.py +++ b/suggestions/migrations/0001_initial.py @@ -1,10 +1,11 @@ # Generated by Django 3.1.2 on 2020-12-29 23:43 import autoslug.fields -from django.conf import settings import django.core.validators -from django.db import migrations, models import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + import website.validators @@ -13,52 +14,189 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('inventory', '0001_initial'), + ("inventory", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='Suggestion', + name="Suggestion", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=256, unique=True, verbose_name='titre du jeu')), - ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='title', unique=True)), - ('price', models.DecimalField(decimal_places=2, max_digits=6, validators=[django.core.validators.MinValueValidator(0)], verbose_name='prix en euros')), - ('buy_link', models.URLField(verbose_name="lien vers un site d'achat")), - ('nb_player_min', models.PositiveSmallIntegerField(verbose_name='nombre de joueur·se·s minimum')), - ('nb_player_max', models.PositiveSmallIntegerField(verbose_name='nombre de joueur·se·s maximum')), - ('player_range_precisions', models.CharField(blank=True, help_text='Pour indiquer une éventuelle contrainte (ex. parité) ou information sur le nombre de joueur·se·s', max_length=256, verbose_name='précisions sur le nombre de joueur·se·s')), - ('duration', models.CharField(max_length=256, verbose_name='durée de partie')), - ('game_designer', models.CharField(blank=True, max_length=256, verbose_name='game designer')), - ('illustrator', models.CharField(blank=True, max_length=256, verbose_name='illustrateur·trice')), - ('editor', models.CharField(blank=True, max_length=256, verbose_name='éditeur')), - ('description', models.TextField(blank=True, help_text="Peut correspondre à celle de l'éditeur et ne doit pas contenir d'avis personnel", verbose_name='description')), - ('image', models.ImageField(blank=True, help_text='Image du jeu de moins de 512 Kio à téléverser (par exemple une photo de sa boite)', upload_to='suggestion_img/', validators=[website.validators.MaxFileSizeValidator(512)], verbose_name='image')), - ('category', models.ForeignKey(blank=True, help_text='Idée de catégorie dans laquelle ranger ce jeu', null=True, on_delete=django.db.models.deletion.SET_NULL, to='inventory.category', verbose_name='catégorie')), - ('tags', models.ManyToManyField(blank=True, help_text="Vous pouvez en sélectionner plusieurs ou aucun (sur ordinateur Ctrl+Clic change l'état de selection d'un tag)", to='inventory.Tag', verbose_name='tags qui correspondent à ce jeu')), - ('upvoting_users', models.ManyToManyField(blank=True, related_name='upvoted_suggestions', to=settings.AUTH_USER_MODEL, verbose_name='personnes intéressées')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "title", + models.CharField( + max_length=256, unique=True, verbose_name="titre du jeu" + ), + ), + ( + "slug", + autoslug.fields.AutoSlugField( + editable=False, populate_from="title", unique=True + ), + ), + ( + "price", + models.DecimalField( + decimal_places=2, + max_digits=6, + validators=[django.core.validators.MinValueValidator(0)], + verbose_name="prix en euros", + ), + ), + ("buy_link", models.URLField(verbose_name="lien vers un site d'achat")), + ( + "nb_player_min", + models.PositiveSmallIntegerField( + verbose_name="nombre de joueur·se·s minimum" + ), + ), + ( + "nb_player_max", + models.PositiveSmallIntegerField( + verbose_name="nombre de joueur·se·s maximum" + ), + ), + ( + "player_range_precisions", + models.CharField( + blank=True, + help_text="Pour indiquer une éventuelle contrainte (ex. parité) ou information sur le nombre de joueur·se·s", + max_length=256, + verbose_name="précisions sur le nombre de joueur·se·s", + ), + ), + ( + "duration", + models.CharField(max_length=256, verbose_name="durée de partie"), + ), + ( + "game_designer", + models.CharField( + blank=True, max_length=256, verbose_name="game designer" + ), + ), + ( + "illustrator", + models.CharField( + blank=True, max_length=256, verbose_name="illustrateur·trice" + ), + ), + ( + "editor", + models.CharField( + blank=True, max_length=256, verbose_name="éditeur" + ), + ), + ( + "description", + models.TextField( + blank=True, + help_text="Peut correspondre à celle de l'éditeur et ne doit pas contenir d'avis personnel", + verbose_name="description", + ), + ), + ( + "image", + models.ImageField( + blank=True, + help_text="Image du jeu de moins de 512 Kio à téléverser (par exemple une photo de sa boite)", + upload_to="suggestion_img/", + validators=[website.validators.MaxFileSizeValidator(512)], + verbose_name="image", + ), + ), + ( + "category", + models.ForeignKey( + blank=True, + help_text="Idée de catégorie dans laquelle ranger ce jeu", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="inventory.category", + verbose_name="catégorie", + ), + ), + ( + "tags", + models.ManyToManyField( + blank=True, + help_text="Vous pouvez en sélectionner plusieurs ou aucun (sur ordinateur Ctrl+Clic change l'état de selection d'un tag)", + to="inventory.Tag", + verbose_name="tags qui correspondent à ce jeu", + ), + ), + ( + "upvoting_users", + models.ManyToManyField( + blank=True, + related_name="upvoted_suggestions", + to=settings.AUTH_USER_MODEL, + verbose_name="personnes intéressées", + ), + ), ], options={ - 'verbose_name': 'suggestion de jeu', - 'verbose_name_plural': 'suggestions de jeux', - 'ordering': ['title'], + "verbose_name": "suggestion de jeu", + "verbose_name_plural": "suggestions de jeux", + "ordering": ["title"], }, ), migrations.CreateModel( - name='SuggestionComment', + name="SuggestionComment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.TextField(verbose_name='texte')), - ('created_on', models.DateTimeField(auto_now_add=True, verbose_name='date de publication')), - ('modified_on', models.DateTimeField(auto_now=True, verbose_name='date de modification')), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='auteur·ice')), - ('commented_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='suggestions.suggestion', verbose_name='suggestion')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("text", models.TextField(verbose_name="texte")), + ( + "created_on", + models.DateTimeField( + auto_now_add=True, verbose_name="date de publication" + ), + ), + ( + "modified_on", + models.DateTimeField( + auto_now=True, verbose_name="date de modification" + ), + ), + ( + "author", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="auteur·ice", + ), + ), + ( + "commented_object", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="comments", + to="suggestions.suggestion", + verbose_name="suggestion", + ), + ), ], options={ - 'verbose_name': 'commentaire sur une suggestion', - 'verbose_name_plural': 'commentaires sur des suggestions', - 'ordering': ['created_on'], + "verbose_name": "commentaire sur une suggestion", + "verbose_name_plural": "commentaires sur des suggestions", + "ordering": ["created_on"], }, ), ] diff --git a/suggestions/migrations/0002_duration_range.py b/suggestions/migrations/0002_duration_range.py index c4f7a01..ca99e92 100644 --- a/suggestions/migrations/0002_duration_range.py +++ b/suggestions/migrations/0002_duration_range.py @@ -6,29 +6,43 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('suggestions', '0001_initial'), + ("suggestions", "0001_initial"), ] operations = [ migrations.RemoveField( - model_name='suggestion', - name='duration', + model_name="suggestion", + name="duration", ), migrations.AddField( - model_name='suggestion', - name='duration_max', - field=models.PositiveSmallIntegerField(blank=True, default=60, help_text="En minutes, telle qu'indiquée par l'éditeur, identique à la durée minimale si laissée vide", verbose_name='durée de partie maximale'), + model_name="suggestion", + name="duration_max", + field=models.PositiveSmallIntegerField( + blank=True, + default=60, + help_text="En minutes, telle qu'indiquée par l'éditeur, identique à la durée minimale si laissée vide", + verbose_name="durée de partie maximale", + ), preserve_default=False, ), migrations.AddField( - model_name='suggestion', - name='duration_min', - field=models.PositiveSmallIntegerField(default=60, help_text="En minutes, telle qu'indiquée par l'éditeur", verbose_name='durée de partie minimale'), + model_name="suggestion", + name="duration_min", + field=models.PositiveSmallIntegerField( + default=60, + help_text="En minutes, telle qu'indiquée par l'éditeur", + verbose_name="durée de partie minimale", + ), preserve_default=False, ), migrations.AddField( - model_name='suggestion', - name='duration_precisions', - field=models.CharField(blank=True, help_text='Pour indiquer des informations complémentaires sur la durée de la partie (ex. évolution en fonction du nombre de joueur·se·s)', max_length=256, verbose_name='précisions sur la durée de partie'), + model_name="suggestion", + name="duration_precisions", + field=models.CharField( + blank=True, + help_text="Pour indiquer des informations complémentaires sur la durée de la partie (ex. évolution en fonction du nombre de joueur·se·s)", + max_length=256, + verbose_name="précisions sur la durée de partie", + ), ), ] diff --git a/suggestions/models.py b/suggestions/models.py index f3ecd4e..1fcafdf 100644 --- a/suggestions/models.py +++ b/suggestions/models.py @@ -1,12 +1,13 @@ +from autoslug import AutoSlugField +from django.contrib.auth.models import User +from django.core.exceptions import ValidationError +from django.core.validators import MinValueValidator from django.db import models from django.urls import reverse -from django.core.validators import MinValueValidator -from django.core.exceptions import ValidationError -from autoslug import AutoSlugField -from website.validators import MaxFileSizeValidator -from django.contrib.auth.models import User -from inventory.models import Category, Tag + from comments.models import AbstractComment +from inventory.models import Category, Tag +from website.validators import MaxFileSizeValidator class Suggestion(models.Model): diff --git a/suggestions/tests.py b/suggestions/tests.py index 7ce503c..a39b155 100644 --- a/suggestions/tests.py +++ b/suggestions/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/suggestions/urls.py b/suggestions/urls.py index 852f1cf..a540659 100644 --- a/suggestions/urls.py +++ b/suggestions/urls.py @@ -1,12 +1,13 @@ from django.urls import path + from .views import ( - SuggestionListView, + AddSuggestionCommentView, AddSuggestionView, + DownvoteSuggestionView, + ModifySuggestionCommentView, + SuggestionListView, SuggestionView, UpvoteSuggestionView, - DownvoteSuggestionView, - AddSuggestionCommentView, - ModifySuggestionCommentView, ) app_name = "suggestions" diff --git a/suggestions/views.py b/suggestions/views.py index b9559d8..ebde924 100644 --- a/suggestions/views.py +++ b/suggestions/views.py @@ -1,12 +1,14 @@ -from django.views.generic import ListView, DetailView, FormView, RedirectView -from django.views.generic.detail import SingleObjectMixin -from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib import messages -from django.shortcuts import redirect +from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models import Count +from django.shortcuts import redirect +from django.views.generic import DetailView, FormView, ListView, RedirectView +from django.views.generic.detail import SingleObjectMixin + from comments.views import AddCommentView, ModifyCommentView -from .models import Suggestion, SuggestionComment + from .forms import AddSuggestionForm +from .models import Suggestion, SuggestionComment class SuggestionListView(ListView): diff --git a/website/admin.py b/website/admin.py index 3d74bd1..6e2017d 100644 --- a/website/admin.py +++ b/website/admin.py @@ -1,5 +1,6 @@ from django.contrib import admin -from .models import MarkdownPage from markdownx.admin import MarkdownxModelAdmin +from .models import MarkdownPage + admin.site.register(MarkdownPage, MarkdownxModelAdmin) diff --git a/website/markdown.py b/website/markdown.py index d6e6a35..cbf72b6 100644 --- a/website/markdown.py +++ b/website/markdown.py @@ -1,6 +1,7 @@ -import markdown import re +import markdown + class NbspPreprocessor(markdown.preprocessors.Preprocessor): """Replace regular spaces with non-breaking spaces within a text around relevant diff --git a/website/migrations/0001_initial.py b/website/migrations/0001_initial.py index 43e117c..deec03c 100644 --- a/website/migrations/0001_initial.py +++ b/website/migrations/0001_initial.py @@ -1,28 +1,43 @@ # Generated by Django 3.1.2 on 2020-12-27 11:34 -from django.db import migrations, models import markdownx.models +from django.db import migrations, models class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='MarkdownPage', + name="MarkdownPage", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('slug', models.SlugField(blank=True, help_text="Identifiant de la page qui se voit dans l'URL. Ne doit pas collisionner avec une page existante. Laisser vide pour la page d'accueil, requis sinon.", unique=True, verbose_name='Adresse de la page')), - ('content', markdownx.models.MarkdownxField(verbose_name='Contenu')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "slug", + models.SlugField( + blank=True, + help_text="Identifiant de la page qui se voit dans l'URL. Ne doit pas collisionner avec une page existante. Laisser vide pour la page d'accueil, requis sinon.", + unique=True, + verbose_name="Adresse de la page", + ), + ), + ("content", markdownx.models.MarkdownxField(verbose_name="Contenu")), ], options={ - 'verbose_name': 'page Markdown', - 'verbose_name_plural': 'pages Markdown', - 'ordering': ['slug'], + "verbose_name": "page Markdown", + "verbose_name_plural": "pages Markdown", + "ordering": ["slug"], }, ), ] diff --git a/website/tests.py b/website/tests.py index 7ce503c..a39b155 100644 --- a/website/tests.py +++ b/website/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/website/urls.py b/website/urls.py index 0983bf9..a49c87f 100644 --- a/website/urls.py +++ b/website/urls.py @@ -1,4 +1,5 @@ from django.urls import path + from .views import MarkdownPageView app_name = "website" diff --git a/website/views.py b/website/views.py index d400236..b83be4b 100644 --- a/website/views.py +++ b/website/views.py @@ -1,6 +1,7 @@ -from django.views.generic import DetailView from django.utils.safestring import mark_safe +from django.views.generic import DetailView from markdownx.utils import markdownify + from .models import MarkdownPage