structure du projet + docker, back: mise en place BD et apps, front: début de dev pour le header et mise en place du thème et css global (override des variables bootstrap)

This commit is contained in:
2026-06-01 15:21:47 +02:00
parent b3c027794c
commit e8e6122a45
111 changed files with 6778 additions and 1 deletions
+65
View File
@@ -0,0 +1,65 @@
# users/signals.py
import io
import random
from PIL import Image, ImageDraw, ImageFont
from django.conf import settings
from django.core.files.base import ContentFile
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import User
PALETTE = ["#34344A", "#845A6D", "#D47386", "#C89B7B", "#32746D"]
def initials_for(user: User) -> str:
if getattr(user, "initials", None):
return user.initials[:2].upper()
first = (user.first_name or "").strip()
last = (user.last_name or "").strip()
if first and last:
return (first[0] + last[0]).upper()
if first:
return first[:2].upper()
# fallback: email
return (user.email or "U")[:2].upper()
def generate_avatar_png(text: str, bg_hex: str, size: int = 256) -> bytes:
img = Image.new("RGBA", (size, size), bg_hex)
draw = ImageDraw.Draw(img)
font_path = getattr(settings, "AVATAR_FONT_PATH", None)
if font_path:
font = ImageFont.truetype(font_path, int(size * 0.42))
else:
font = ImageFont.load_default()
bbox = draw.textbbox((0, 0), text, font=font)
tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
x = (size - tw) / 2
y = (size - th) / 2 - (size * 0.05)
draw.text((x, y), text, font=font, fill="white")
out = io.BytesIO()
img.save(out, format="PNG", optimize=True)
return out.getvalue()
@receiver(post_save, sender=User)
def set_default_avatar(sender, instance: User, created: bool, **kwargs):
if not created:
return
if instance.image:
return
text = initials_for(instance)
bg = random.choice(PALETTE)
png_bytes = generate_avatar_png(text=text, bg_hex=bg, size=256)
filename = f"user_{instance.pk}_avatar.png"
instance.image.save(filename, ContentFile(png_bytes), save=False)
User.objects.filter(pk=instance.pk).update(
image=instance.image.name,
)