39491-vm/core/views.py
Flatlogic Bot db8313c88e V2
2026-04-05 20:23:53 +00:00

265 lines
10 KiB
Python

import os
import platform
from django import get_version as django_version
from django.contrib import messages
from django.db.models import Count, Prefetch, Q
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from .forms import ConversationStartForm, MessageForm, ProfileForm, REACTION_CHOICES, ReactionForm
from .models import Conversation, Message, ResakaProfile
DEFAULT_META_DESCRIPTION = (
"RJL Resaka est une messagerie privée moderne pour lancer des conversations, "
"envoyer des messages et suivre les notifications de lecture."
)
def _profile_from_request(request):
profiles = ResakaProfile.objects.order_by("display_name")
profile = None
requested_id = request.GET.get("profile") or request.session.get("active_profile_id")
if requested_id:
try:
profile = profiles.get(pk=requested_id)
except (ResakaProfile.DoesNotExist, ValueError, TypeError):
profile = None
if not profile and profiles.exists():
profile = profiles.first()
if profile:
request.session["active_profile_id"] = profile.pk
return profile, profiles
def _profile_query_suffix(profile):
return f"?profile={profile.pk}" if profile else ""
def _conversation_queryset(active_profile):
base = Conversation.objects.select_related("starter", "recipient").prefetch_related(
Prefetch(
"messages",
queryset=Message.objects.select_related("author").order_by("created_at"),
)
)
if active_profile:
base = base.filter(Q(starter=active_profile) | Q(recipient=active_profile)).annotate(
unread_count=Count(
"messages",
filter=Q(messages__is_read=False) & ~Q(messages__author=active_profile),
)
)
else:
base = base.none()
return base.order_by("-updated_at")
def home(request):
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
active_profile, profiles = _profile_from_request(request)
conversations = list(_conversation_queryset(active_profile))
for conversation in conversations:
message_list = list(conversation.messages.all())
conversation.last_message = message_list[-1] if message_list else None
conversation.counterpart = conversation.counterpart_for(active_profile)
stats = {
"profiles": profiles.count(),
"conversations": len(conversations),
"messages": Message.objects.count(),
}
context = {
"project_name": "RJL Resaka",
"agent_brand": agent_brand,
"django_version": django_version(),
"python_version": platform.python_version(),
"current_time": now,
"host_name": host_name,
"project_description": os.getenv("PROJECT_DESCRIPTION", DEFAULT_META_DESCRIPTION),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
"page_title": "RJL Resaka | Messagerie privée moderne",
"page_description": DEFAULT_META_DESCRIPTION,
"active_profile": active_profile,
"profiles": profiles,
"profile_form": ProfileForm(),
"conversation_form": ConversationStartForm(active_profile=active_profile),
"conversations": conversations,
"stats": stats,
"profile_query": _profile_query_suffix(active_profile),
}
return render(request, "core/index.html", context)
def create_profile(request):
if request.method != "POST":
return redirect("home")
form = ProfileForm(request.POST)
if form.is_valid():
profile = form.save()
request.session["active_profile_id"] = profile.pk
messages.success(request, f"Profil {profile.display_name} créé. Vous pouvez maintenant lancer une discussion.")
return redirect(f"{reverse('home')}?profile={profile.pk}")
active_profile, profiles = _profile_from_request(request)
conversations = list(_conversation_queryset(active_profile))
for conversation in conversations:
message_list = list(conversation.messages.all())
conversation.last_message = message_list[-1] if message_list else None
conversation.counterpart = conversation.counterpart_for(active_profile)
context = {
"project_name": "RJL Resaka",
"page_title": "Créer un profil | RJL Resaka",
"page_description": DEFAULT_META_DESCRIPTION,
"active_profile": active_profile,
"profiles": profiles,
"profile_form": form,
"conversation_form": ConversationStartForm(active_profile=active_profile),
"conversations": conversations,
"stats": {
"profiles": profiles.count(),
"conversations": len(conversations),
"messages": Message.objects.count(),
},
"profile_query": _profile_query_suffix(active_profile),
"current_time": timezone.now(),
"django_version": django_version(),
"python_version": platform.python_version(),
}
return render(request, "core/index.html", context, status=400)
def start_conversation(request):
if request.method != "POST":
return redirect("home")
active_profile, _profiles = _profile_from_request(request)
if not active_profile:
messages.error(request, "Créez ou sélectionnez d'abord un profil pour discuter.")
return redirect("home")
form = ConversationStartForm(request.POST, active_profile=active_profile)
if not form.is_valid():
messages.error(request, "Impossible de lancer la discussion. Vérifiez les champs du formulaire.")
return redirect(f"{reverse('home')}?profile={active_profile.pk}")
recipient = form.cleaned_data["recipient"]
body = form.cleaned_data["body"]
conversation = (
Conversation.objects.filter(
(Q(starter=active_profile) & Q(recipient=recipient))
| (Q(starter=recipient) & Q(recipient=active_profile))
)
.select_related("starter", "recipient")
.first()
)
created = False
if not conversation:
conversation = Conversation.objects.create(
starter=active_profile,
recipient=recipient,
subject=f"Discussion privée · {active_profile.display_name} & {recipient.display_name}",
)
created = True
Message.objects.create(
conversation=conversation,
author=active_profile,
body=body,
is_read=False,
)
conversation.save(update_fields=["updated_at"])
if created:
messages.success(request, f"Nouvelle conversation lancée avec {recipient.display_name}.")
else:
messages.success(request, f"Message envoyé à {recipient.display_name}.")
return redirect(f"{conversation.get_absolute_url()}?profile={active_profile.pk}")
def conversation_detail(request, pk):
active_profile, profiles = _profile_from_request(request)
conversation = get_object_or_404(
Conversation.objects.select_related("starter", "recipient").prefetch_related(
Prefetch("messages", queryset=Message.objects.select_related("author").order_by("created_at"))
),
pk=pk,
)
if not active_profile or active_profile.pk not in {conversation.starter_id, conversation.recipient_id}:
if active_profile:
messages.error(request, "Cette conversation n'appartient pas au profil sélectionné.")
return redirect(f"{reverse('home')}?profile={active_profile.pk}")
messages.error(request, "Sélectionnez un profil pour ouvrir une conversation.")
return redirect("home")
if request.method == "POST":
form = MessageForm(request.POST)
if form.is_valid():
message = form.save(commit=False)
message.conversation = conversation
message.author = active_profile
message.is_read = False
message.save()
conversation.save(update_fields=["updated_at"])
messages.success(request, "Message envoyé.")
return redirect(f"{conversation.get_absolute_url()}?profile={active_profile.pk}")
else:
form = MessageForm()
Message.objects.filter(conversation=conversation).exclude(author=active_profile).filter(is_read=False).update(is_read=True)
message_list = list(conversation.messages.all())
counterpart = conversation.counterpart_for(active_profile)
reaction_forms = {message.pk: ReactionForm() for message in message_list}
context = {
"project_name": "RJL Resaka",
"page_title": f"Chat avec {counterpart.display_name} | RJL Resaka",
"page_description": f"Conversation privée entre {active_profile.display_name} et {counterpart.display_name} sur RJL Resaka.",
"active_profile": active_profile,
"profiles": profiles,
"conversation": conversation,
"counterpart": counterpart,
"message_form": form,
"messages_list": message_list,
"reaction_forms": reaction_forms,
"reaction_choices": REACTION_CHOICES,
"profile_query": _profile_query_suffix(active_profile),
}
return render(request, "core/chat_detail.html", context)
def react_message(request, pk):
if request.method != "POST":
raise Http404
active_profile, _profiles = _profile_from_request(request)
message = get_object_or_404(Message.objects.select_related("conversation", "author"), pk=pk)
conversation = message.conversation
if not active_profile or active_profile.pk not in {conversation.starter_id, conversation.recipient_id}:
messages.error(request, "Sélectionnez un profil valide pour réagir au message.")
return redirect("home")
form = ReactionForm(request.POST)
if form.is_valid():
message.reaction = form.cleaned_data["reaction"]
message.save(update_fields=["reaction"])
messages.success(request, "Réaction envoyée.")
else:
messages.error(request, "Réaction invalide.")
return redirect(f"{conversation.get_absolute_url()}?profile={active_profile.pk}")