File size: 3,242 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
"""MessageSource — 消息来源配置。"""

from __future__ import annotations

from typing import ClassVar

from django.db import models
from django.utils.translation import gettext_lazy as _


class SourceType(models.TextChoices):
    IMAP = "imap", _("IMAP 邮箱")
    COURT_INBOX = "court_inbox", _("一张网收件箱")
    COURT_SCHEDULE = "court_schedule", _("一张网庭审日程")


class SyncStatus(models.TextChoices):
    PENDING = "pending", _("待同步")
    SUCCESS = "success", _("同步成功")
    FAILED = "failed", _("同步失败")


class MessageSource(models.Model):
    """消息来源配置,关联 AccountCredential,描述如何拉取消息。"""

    credential = models.ForeignKey(
        "organization.AccountCredential",
        on_delete=models.CASCADE,
        related_name="message_sources",
        verbose_name=_("账号凭证"),
    )
    source_type = models.CharField(
        max_length=32,
        choices=SourceType.choices,
        default=SourceType.IMAP,
        verbose_name=_("来源类型"),
    )
    display_name = models.CharField(max_length=128, verbose_name=_("显示名称"))
    is_enabled = models.BooleanField(default=True, verbose_name=_("启用"))
    poll_interval_minutes = models.PositiveIntegerField(default=30, verbose_name=_("轮询间隔(分钟)"))
    sync_since = models.DateTimeField(verbose_name=_("同步起始时间"), help_text=_("只拉取此时间之后的消息"))

    # IMAP 专用:主机名(覆盖从 credential.url 推断的值)和最后同步 UID
    imap_host = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_("IMAP 主机"),
        help_text=_("留空则从凭证 URL 自动推断,如 mail.jtn.com"),
    )
    imap_account = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_("IMAP 账号"),
        help_text=_("留空则使用凭证账号,如需覆盖填写完整邮箱地址"),
    )
    last_synced_uid = models.PositiveIntegerField(null=True, blank=True, verbose_name=_("最后同步 UID"))

    # 发件人过滤(邮箱或名称,每行一个,大小写不敏感)
    sender_whitelist = models.TextField(
        blank=True,
        verbose_name=_("只同步这些发件人"),
        help_text=_("每行一个邮箱或名称,留空则不限制"),
    )
    sender_blacklist = models.TextField(
        blank=True,
        verbose_name=_("不同步这些发件人"),
        help_text=_("每行一个邮箱或名称,留空则不排除"),
    )

    last_sync_at = models.DateTimeField(null=True, blank=True, verbose_name=_("最后同步时间"))
    last_sync_status = models.CharField(
        max_length=16,
        choices=SyncStatus.choices,
        default=SyncStatus.PENDING,
        verbose_name=_("同步状态"),
    )
    last_sync_error = models.TextField(blank=True, verbose_name=_("同步错误信息"))
    created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("创建时间"))

    class Meta:
        verbose_name = _("消息来源")
        verbose_name_plural = _("消息来源")
        ordering: ClassVar = ["-created_at"]

    def __str__(self) -> str:
        return f"{self.display_name} ({self.source_type})"