diff --git a/beesgospel/admin.py b/beesgospel/admin.py new file mode 100644 index 0000000..916000f --- /dev/null +++ b/beesgospel/admin.py @@ -0,0 +1,56 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin + +from beesgospel.models import Agenda, Document, Membre, User + + +@admin.register(Agenda) +class AgendaAdmin(admin.ModelAdmin): + list_display = ["titre", "lieu", "date_heure", "prive"] + ordering = ["-date_heure"] + search_fields = ["titre", "lieu"] + date_hierarchy = "date_heure" + + +@admin.register(Document) +class DocumentAdmin(admin.ModelAdmin): + list_display = ["titre", "quand", "prive"] + ordering = ["-quand"] + + +@admin.register(Membre) +class MembreAdmin(admin.ModelAdmin): + list_display = ["nom", "prenom", "localite", "user__email"] + ordering = ["nom"] + + +@admin.register(User) +class UserAdmin(UserAdmin): + list_display = ["email", "is_active", "is_staff", "last_login"] + search_fields = ["email"] + ordering = ["email"] + fieldsets = ( + (None, {"fields": ("email", "password",)}), + ( + "Permissions", + { + "fields": ( + "is_active", + "is_staff", + "is_superuser", + "groups", + "user_permissions", + ), + }, + ), + ("Important dates", {"fields": ("last_login", "date_joined")}), + ) + add_fieldsets = ( + ( + None, + { + "classes": ("wide",), + "fields": ("email", "usable_password", "password1", "password2"), + }, + ), + ) diff --git a/beesgospel/migrations/0001_initial.py b/beesgospel/migrations/0001_initial.py new file mode 100644 index 0000000..cffd9fb --- /dev/null +++ b/beesgospel/migrations/0001_initial.py @@ -0,0 +1,166 @@ +import beesgospel.models +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("auth", "0012_alter_user_first_name_max_length"), + ] + + operations = [ + migrations.CreateModel( + 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", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=150, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ( + "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", + ), + ), + ], + managers=[ + ("objects", beesgospel.models.CustomUserManager()), + ], + ), + migrations.CreateModel( + name="Membre", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("nom", models.CharField(max_length=40, verbose_name="Nom")), + ("prenom", models.CharField(max_length=40, verbose_name="Prénom")), + ( + "avatar", + models.ImageField( + blank=True, upload_to="avatars", verbose_name="Avatar" + ), + ), + ( + "rue", + models.CharField(blank=True, max_length=80, verbose_name="Rue"), + ), + ("npa", models.CharField(blank=True, max_length=5, verbose_name="NPA")), + ( + "localite", + models.CharField( + blank=True, max_length=40, verbose_name="Localité" + ), + ), + ( + "tel1", + models.CharField(blank=True, max_length=20, verbose_name="Tél. 1"), + ), + ( + "tel2", + models.CharField(blank=True, max_length=20, verbose_name="Tél. 2"), + ), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + migrations.AddConstraint( + model_name="user", + constraint=models.UniqueConstraint( + fields=("email",), name="unique_user_email" + ), + ), + ] diff --git a/beesgospel/migrations/0002_agenda_document.py b/beesgospel/migrations/0002_agenda_document.py new file mode 100644 index 0000000..7093470 --- /dev/null +++ b/beesgospel/migrations/0002_agenda_document.py @@ -0,0 +1,73 @@ +# Generated by Django 5.2.5.dev20250725113223 on 2025-07-26 15:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("beesgospel", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="Agenda", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("titre", models.CharField(max_length=150, verbose_name="Titre")), + ( + "lieu", + models.CharField(blank=True, max_length=80, verbose_name="Lieu"), + ), + ("date_heure", models.DateTimeField(verbose_name="Date/heure")), + ("infos", models.TextField(verbose_name="Informations")), + ( + "prive", + models.BooleanField( + default=False, + help_text="Un évènement privé ne peut être consulté que par les membres de l'association, tandis qu'un évènement public est visible de tous.", + verbose_name="Privé", + ), + ), + ], + ), + migrations.CreateModel( + name="Document", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "fichier", + models.FileField( + blank=True, upload_to="documents", verbose_name="Fichier" + ), + ), + ("url", models.URLField(blank=True, verbose_name="URL")), + ("quand", models.DateField(verbose_name="Date")), + ("titre", models.CharField(max_length=150, verbose_name="Titre")), + ("infos", models.TextField(blank=True, verbose_name="Infos")), + ( + "prive", + models.BooleanField( + default=False, + help_text="Un document privé ne peut être consulté que par les membres de l'association, tandis qu'un document public est visible de tous.", + verbose_name="Privé", + ), + ), + ], + ), + ] diff --git a/beesgospel/migrations/__init__.py b/beesgospel/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/beesgospel/models.py b/beesgospel/models.py new file mode 100644 index 0000000..51695ea --- /dev/null +++ b/beesgospel/models.py @@ -0,0 +1,71 @@ +from django.contrib.auth.models import AbstractUser, UserManager +from django.db import models + + +class CustomUserManager(UserManager): + def create_superuser(self, **kwargs): + return super().create_superuser("foo", **kwargs) + + +class User(AbstractUser): + username = None + USERNAME_FIELD = "email" + REQUIRED_FIELDS = [] + + objects = CustomUserManager() + + class Meta: + constraints = [ + models.UniqueConstraint(name="unique_user_email", fields=["email"]), + ] + + def __init__(self, *args, username=None, **kwargs): + super().__init__(*args, **kwargs) + + +class Membre(models.Model): + nom = models.CharField("Nom", max_length=40) + prenom = models.CharField("Prénom", max_length=40) + user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) + avatar = models.ImageField("Avatar", upload_to="avatars", blank=True) + rue = models.CharField("Rue", max_length=80, blank=True) + npa = models.CharField("NPA", max_length=5, blank=True) + localite = models.CharField("Localité", max_length=40, blank=True) + tel1 = models.CharField("Tél. 1", max_length=20, blank=True) + tel2 =models.CharField("Tél. 2", max_length=20, blank=True) + + def __str__(self): + return f"{self.nom} {self.prenom}" + + +class Agenda(models.Model): + titre = models.CharField("Titre", max_length=150) + lieu = models.CharField("Lieu", max_length=80, blank=True) + date_heure = models.DateTimeField("Date/heure") + infos = models.TextField("Informations") + prive = models.BooleanField( + "Privé", default=False, help_text=( + "Un évènement privé ne peut être consulté que par les membres de " + "l'association, tandis qu'un évènement public est visible de tous." + ) + ) + + def __str__(self): + return f"{self.titre} {self.date_heure}" + + +class Document(models.Model): + fichier = models.FileField("Fichier", upload_to="documents", blank=True) + url = models.URLField("URL", blank=True) + quand = models.DateField("Date") + titre = models.CharField("Titre", max_length=150) + infos = models.TextField("Infos", blank=True) + prive = models.BooleanField( + "Privé", default=False, help_text=( + "Un document privé ne peut être consulté que par les membres de " + "l'association, tandis qu'un document public est visible de tous." + ) + ) + + def __str__(self): + return f"{self.titre} {self.date}" diff --git a/common/settings.py b/common/settings.py index 6f00a18..b5d3dc2 100644 --- a/common/settings.py +++ b/common/settings.py @@ -69,7 +69,7 @@ DATABASES = { "NAME": BASE_DIR / "db.sqlite3", } } - +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Password validation # https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators @@ -88,6 +88,7 @@ AUTH_PASSWORD_VALIDATORS = [ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] +AUTH_USER_MODEL = "beesgospel.User" # Internationalization