loko/streetup/notifications/admin.py
2026-07-22 14:48:40 +02:00

164 lines
6.5 KiB
Python

from django.contrib import admin
from .models import (
Team, Notification, NotificationAttachment, NotificationRecipient,
TeamNotificationTarget, TeamNotificationRead,
Discussion, Message, MessageAttachment,
NotificationRule,
)
class NotificationRecipientInline(admin.TabularInline):
model = NotificationRecipient
extra = 0
readonly_fields = ['read_at', 'archived_at']
class TeamNotificationTargetInline(admin.TabularInline):
model = TeamNotificationTarget
extra = 0
class NotificationAttachmentInline(admin.TabularInline):
model = NotificationAttachment
extra = 0
readonly_fields = ['uploaded_at', 'name']
@admin.register(Team)
class TeamAdmin(admin.ModelAdmin):
list_display = ['name', 'member_count', 'created_by', 'created_at']
search_fields = ['name', 'description']
filter_horizontal = ['members']
def member_count(self, obj):
return obj.members.count()
member_count.short_description = 'Membres'
@admin.register(Notification)
class NotificationAdmin(admin.ModelAdmin):
list_display = [
'title', 'notification_type', 'sender',
'created_at', 'expires_at', 'is_system', 'source_app',
]
list_filter = ['notification_type', 'is_system', 'source_app', 'created_at']
search_fields = ['title', 'content']
readonly_fields = ['created_at']
inlines = [NotificationAttachmentInline, NotificationRecipientInline, TeamNotificationTargetInline]
date_hierarchy = 'created_at'
@admin.register(NotificationAttachment)
class NotificationAttachmentAdmin(admin.ModelAdmin):
list_display = ['name', 'notification', 'uploaded_by', 'uploaded_at', 'is_image']
search_fields = ['name', 'notification__title']
readonly_fields = ['uploaded_at', 'is_image']
@admin.register(NotificationRecipient)
class NotificationRecipientAdmin(admin.ModelAdmin):
list_display = ['notification', 'user', 'read_at', 'archived_at']
list_filter = ['read_at', 'archived_at']
search_fields = ['user__username', 'notification__title']
readonly_fields = ['read_at', 'archived_at']
@admin.register(TeamNotificationTarget)
class TeamNotificationTargetAdmin(admin.ModelAdmin):
list_display = ['notification', 'team']
search_fields = ['team__name', 'notification__title']
@admin.register(TeamNotificationRead)
class TeamNotificationReadAdmin(admin.ModelAdmin):
list_display = ['team_notification', 'user', 'read_at']
search_fields = ['user__username']
readonly_fields = ['read_at']
# ─────────────────────────────────────────────────────────────────────────────
# Règles de notification
# ─────────────────────────────────────────────────────────────────────────────
@admin.register(NotificationRule)
class NotificationRuleAdmin(admin.ModelAdmin):
list_display = [
'name', 'is_active', 'trigger_event', 'trigger_cancellation_type',
'notification_type', 'team_list', 'updated_at',
]
list_filter = ['is_active', 'trigger_event', 'trigger_cancellation_type', 'notification_type']
search_fields = ['name', 'title_template', 'content_template']
filter_horizontal = ['recipient_teams', 'recipient_users']
readonly_fields = ['created_at', 'updated_at']
fieldsets = [
(None, {
'fields': ['name', 'is_active'],
}),
('Déclencheur', {
'fields': ['trigger_event', 'trigger_cancellation_type'],
'description': (
'Sélectionnez l\'événement qui déclenche cette règle. '
'Utilisez le filtre « Type d\'annulation » pour ne cibler qu\'un cas précis.'
),
}),
('Contenu de la notification', {
'fields': ['notification_type', 'single_claim', 'title_template', 'content_template'],
'description': (
'Variables disponibles dans les modèles : '
'{intervention_code}, {intervention_title}, '
'{cancellation_type_label}, {cancellation_reason}'
),
}),
('Destinataires', {
'fields': ['recipient_teams', 'recipient_users'],
}),
('Informations système', {
'fields': ['created_at', 'updated_at'],
'classes': ['collapse'],
}),
]
def team_list(self, obj):
teams = obj.recipient_teams.select_related('company').values_list('name', 'company__name')
return ', '.join(f"{n} ({c})" for n, c in teams) or '—'
team_list.short_description = 'Équipes'
# ─────────────────────────────────────────────────────────────────────────────
# Discussion / Messaging
# ─────────────────────────────────────────────────────────────────────────────
class MessageInline(admin.TabularInline):
model = Message
extra = 0
readonly_fields = ['created_at', 'author']
fields = ['author', 'content', 'created_at', 'is_deleted']
@admin.register(Discussion)
class DiscussionAdmin(admin.ModelAdmin):
list_display = ['title', 'created_by', 'created_at', 'updated_at', 'is_closed', 'object_label', 'message_count']
list_filter = ['is_closed', 'created_at']
search_fields = ['title', 'object_label', 'created_by__username']
readonly_fields = ['created_at', 'updated_at', 'content_type', 'object_id', 'object_url', 'object_label']
filter_horizontal = ['participants']
inlines = [MessageInline]
def message_count(self, obj):
return obj.messages.filter(is_deleted=False).count()
message_count.short_description = 'Messages'
class MessageAttachmentInline(admin.TabularInline):
model = MessageAttachment
extra = 0
readonly_fields = ['uploaded_at', 'name', 'is_image']
@admin.register(Message)
class MessageAdmin(admin.ModelAdmin):
list_display = ['author', 'discussion', 'created_at', 'is_deleted']
list_filter = ['is_deleted', 'created_at']
search_fields = ['author__username', 'content', 'discussion__title']
readonly_fields = ['created_at']
inlines = [MessageAttachmentInline]