Écrans bénévole et référent redessinés, messages aux bénévoles
Étape 55 : écrans /mobile-benevole et /mobile-referent d'après la maquette (design/Planning bénévole mobile) — créneau en cours ou prochain mis en avant, planning par journée de festival avec frise horaire, compteurs et pointage du référent par créneau. Étape 56 : message de l'organisation (Edition.volunteer_message, onglet « Message aux bénévoles ») et message de chaque poste (Position.message, saisi par le référent), migration 0029, affichés sur l'écran bénévole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4a3f93e137
commit
16d8fb44a7
@@ -14,7 +14,7 @@ from PIL import Image, UnidentifiedImageError
|
||||
from sqlalchemy import delete
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.models import Artist, Position, VolunteerArtist, VolunteerPositionWish
|
||||
from app.models import Artist, Position, VolunteerArtist, VolunteerPositionWish, local_now
|
||||
|
||||
|
||||
def owned_or_404(instance, edition_id: uuid.UUID):
|
||||
@@ -119,3 +119,15 @@ async def read_photo(photo: UploadFile | None) -> tuple[bytes, str] | None:
|
||||
status_code=422, detail={"code": "form.photo_type_not_supported"}
|
||||
) from exc
|
||||
return content, content_type
|
||||
|
||||
|
||||
def set_message(target: object, field: str, value: str | None) -> None:
|
||||
"""Message affiché aux bénévoles (`Edition.volunteer_message`,
|
||||
`Position.message`) : espaces de bord retirés, vide = plus de message.
|
||||
`{field}_updated_at` n'est daté que si le texte change vraiment — il dit
|
||||
aux bénévoles de quand date le message."""
|
||||
text = (value or "").strip() or None
|
||||
if text == getattr(target, field):
|
||||
return
|
||||
setattr(target, field, text)
|
||||
setattr(target, f"{field}_updated_at", local_now() if text else None)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlmodel import Session
|
||||
|
||||
from app.api._common import set_message
|
||||
from app.api.deps import get_edition
|
||||
from app.api.schemas import EditionRead, EditionUpdate
|
||||
from app.auth.deps import current_account_in_edition, require_coordinator
|
||||
@@ -27,7 +28,10 @@ def update_edition(
|
||||
_guard: Account = Depends(require_coordinator),
|
||||
session: Session = Depends(get_session),
|
||||
) -> Edition:
|
||||
for field, value in payload.model_dump(exclude_unset=True).items():
|
||||
changes = payload.model_dump(exclude_unset=True)
|
||||
if "volunteer_message" in changes:
|
||||
set_message(edition, "volunteer_message", changes.pop("volunteer_message"))
|
||||
for field, value in changes.items():
|
||||
setattr(edition, field, value)
|
||||
if edition.end_date < edition.start_date:
|
||||
raise HTTPException(
|
||||
|
||||
@@ -10,7 +10,7 @@ import uuid
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.api._common import owned_or_404
|
||||
from app.api._common import owned_or_404, set_message
|
||||
from app.api._shiftgen import generate_missing_shifts
|
||||
from app.api.deps import get_edition
|
||||
from app.api.schemas import (
|
||||
@@ -103,6 +103,8 @@ def update_position(
|
||||
ensure_can_write_position(account, position)
|
||||
changes = payload.model_dump(exclude_unset=True)
|
||||
_check_lead_account(session, edition, changes.get("lead_account_id"))
|
||||
if "message" in changes:
|
||||
set_message(position, "message", changes.pop("message"))
|
||||
for field, value in changes.items():
|
||||
setattr(position, field, value)
|
||||
session.commit()
|
||||
|
||||
@@ -35,16 +35,25 @@ class EditionRead(ApiModel):
|
||||
start_date: dt.date
|
||||
end_date: dt.date
|
||||
retention_days: int | None
|
||||
volunteer_message: str | None
|
||||
volunteer_message_updated_at: dt.datetime | None
|
||||
created_at: dt.datetime
|
||||
updated_at: dt.datetime
|
||||
|
||||
|
||||
# Plafond d'un message (organisation, poste) : quelques paragraphes, pas un
|
||||
# document.
|
||||
MESSAGE_MAX_LENGTH = 2000
|
||||
|
||||
|
||||
class EditionUpdate(ApiModel):
|
||||
name: str | None = None
|
||||
year: int | None = None
|
||||
start_date: dt.date | None = None
|
||||
end_date: dt.date | None = None
|
||||
retention_days: int | None = None
|
||||
# Vide ou blanc = plus de message.
|
||||
volunteer_message: str | None = Field(default=None, max_length=MESSAGE_MAX_LENGTH)
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Volunteer #
|
||||
@@ -141,6 +150,9 @@ class VolunteerPlanningEntry(ApiModel):
|
||||
# pas rattaché à une fiche bénévole (pas de téléphone à donner alors).
|
||||
referent_name: str | None
|
||||
referent_phone: str | None
|
||||
# Message du poste (voir `Position.message`).
|
||||
position_message: str | None
|
||||
position_message_updated_at: dt.datetime | None
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -187,6 +199,8 @@ class PositionUpdate(ApiModel):
|
||||
location: str | None = None
|
||||
category: PositionCategory | None = None
|
||||
lead_account_id: uuid.UUID | None = None
|
||||
# Vide ou blanc = plus de message.
|
||||
message: str | None = Field(default=None, max_length=MESSAGE_MAX_LENGTH)
|
||||
|
||||
|
||||
class PositionRead(ApiModel):
|
||||
@@ -196,6 +210,8 @@ class PositionRead(ApiModel):
|
||||
location: str | None
|
||||
category: PositionCategory
|
||||
lead_account_id: uuid.UUID | None
|
||||
message: str | None
|
||||
message_updated_at: dt.datetime | None
|
||||
created_at: dt.datetime
|
||||
updated_at: dt.datetime
|
||||
|
||||
|
||||
@@ -317,6 +317,8 @@ def get_volunteer_planning(
|
||||
position_location=p.location,
|
||||
referent_name=f"{r.first_name} {r.last_name}" if r else None,
|
||||
referent_phone=r.phone if r else None,
|
||||
position_message=p.message,
|
||||
position_message_updated_at=p.message_updated_at,
|
||||
)
|
||||
for a, s, p, r in rows
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user