File size: 4,138 Bytes
b4f2238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""MessageSource Admin — 消息来源管理。"""

from __future__ import annotations

from typing import Any, ClassVar

from django.contrib import admin, messages
from django.http import HttpRequest, HttpResponse
from django.urls import path
from django.utils.html import format_html
from django.utils.safestring import SafeString
from django.utils.translation import gettext_lazy as _

from apps.message_hub.models import MessageSource, SyncStatus


@admin.register(MessageSource)
class MessageSourceAdmin(admin.ModelAdmin[MessageSource]):
    list_display = [
        "id",
        "display_name",
        "source_type_badge",
        "credential",
        "is_enabled",
        "poll_interval_minutes",
        "sync_status_badge",
        "last_sync_at",
        "refresh_button",
    ]
    list_filter: ClassVar = ["source_type", "is_enabled", "last_sync_status"]
    search_fields: ClassVar = ("display_name", "credential__account", "credential__site_name")
    autocomplete_fields: ClassVar = ("credential",)
    readonly_fields: ClassVar = ["last_sync_at", "last_sync_status", "last_sync_error", "last_synced_uid", "created_at"]

    fieldsets: ClassVar = (
        (
            _("基本配置"),
            {
                "fields": (
                    "display_name",
                    "credential",
                    "source_type",
                    "is_enabled",
                    "poll_interval_minutes",
                    "sync_since",
                )
            },
        ),
        (
            _("发件人过滤"),
            {
                "fields": ("sender_whitelist", "sender_blacklist"),
                "description": _("可输入邮箱地址或发件人名称,每行一个,大小写不敏感。白名单优先于黑名单。"),
            },
        ),
        (_("IMAP 配置"), {"fields": ("imap_host", "imap_account"), "classes": ("collapse",)}),
        (
            _("同步状态"),
            {"fields": ("last_sync_at", "last_sync_status", "last_sync_error", "last_synced_uid", "created_at")},
        ),
    )

    def get_urls(self) -> list[Any]:
        urls = super().get_urls()
        custom = [
            path("<int:pk>/sync/", self.admin_site.admin_view(self._sync_view), name="message_hub_messagesource_sync"),
        ]
        return custom + urls

    def _sync_view(self, request: HttpRequest, pk: int) -> HttpResponse:
        from django.shortcuts import redirect
        from django_q.tasks import async_task

        async_task("apps.message_hub.tasks.sync_source_by_id", pk)
        self.message_user(request, _("同步任务已提交,稍后刷新查看结果"), messages.SUCCESS)
        return redirect("..")

    @admin.display(description=_("来源类型"))
    def source_type_badge(self, obj: MessageSource) -> SafeString:
        colors = {"imap": "#007bff", "court_inbox": "#6f42c1", "court_schedule": "#e85d04"}
        color = colors.get(obj.source_type, "#6c757d")
        return format_html(
            '<span style="background:{};color:#fff;padding:2px 8px;border-radius:4px;font-size:12px">{}</span>',
            color,
            obj.get_source_type_display(),
        )

    @admin.display(description=_("同步状态"))
    def sync_status_badge(self, obj: MessageSource) -> SafeString:
        colors = {SyncStatus.SUCCESS: "#28a745", SyncStatus.FAILED: "#dc3545", SyncStatus.PENDING: "#6c757d"}
        color = colors.get(obj.last_sync_status, "#6c757d")
        return format_html(
            '<span style="background:{};color:#fff;padding:2px 8px;border-radius:4px;font-size:12px">{}</span>',
            color,
            obj.get_last_sync_status_display(),
        )

    @admin.display(description=_("操作"))
    def refresh_button(self, obj: MessageSource) -> SafeString:
        from django.urls import reverse

        url = reverse("admin:message_hub_messagesource_sync", args=[obj.pk])
        return format_html(
            '<a class="button" href="{}" style="background:#17a2b8;color:#fff;padding:4px 10px;border-radius:4px;text-decoration:none;font-size:12px">立即同步</a>',
            url,
        )