作成・変更したファイル バックエンド(新規): apps/mail/models.py — MailSender, MailEmail, MailNotificationToken apps/mail/serializers.py apps/mail/views.py — Windmill用API、フィードバック、ルール管理 apps/mail/urls.py apps/mail/admin.py マイグレーション(自動生成・適用済み) バックエンド(変更): settings.py — apps.mail 追加、MAIL_API_KEY/FRONTEND_URL 環境変数 urls.py — /api/mail/ 追加 フロントエンド(新規): mail/feedback/[token]/page.tsx — 認証不要、フィードバック3択+スコープ選択 mail/rules/page.tsx — ルール管理(一覧・追加・削除) フロントエンド(変更): Navbar.tsx — 「メールルール」メニュー追加 types/index.ts — MailSender, MailEmailFeedback 型追加 次のステップ(Windmill側) Keinaシステム側の実装は完了しています。次はWindmillにIMAPポーリングスクリプトを書く必要があります。Windmillのスクリプトが必要になったタイミングでお声がけください。
100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
import uuid
|
||
from django.db import models
|
||
|
||
|
||
class MailSender(models.Model):
|
||
"""送信者ルール(never_notify: 通知しない)"""
|
||
email = models.EmailField(null=True, blank=True, verbose_name="メールアドレス")
|
||
domain = models.CharField(max_length=255, null=True, blank=True, verbose_name="ドメイン")
|
||
rule = models.CharField(
|
||
max_length=20,
|
||
choices=[('never_notify', '通知しない')],
|
||
default='never_notify',
|
||
verbose_name="ルール"
|
||
)
|
||
note = models.TextField(blank=True, verbose_name="メモ")
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
verbose_name = "送信者ルール"
|
||
verbose_name_plural = "送信者ルール"
|
||
constraints = [
|
||
models.CheckConstraint(
|
||
check=(
|
||
models.Q(email__isnull=False, domain__isnull=True) |
|
||
models.Q(email__isnull=True, domain__isnull=False)
|
||
),
|
||
name='mail_sender_email_or_domain'
|
||
)
|
||
]
|
||
|
||
def __str__(self):
|
||
value = self.email or self.domain
|
||
kind = "アドレス" if self.email else "ドメイン"
|
||
return f"[{kind}] {value}"
|
||
|
||
|
||
ACCOUNT_CHOICES = [
|
||
('xserver', 'Xserver'),
|
||
('gmail', 'Gmail'),
|
||
('hotmail', 'Hotmail'),
|
||
]
|
||
|
||
FEEDBACK_CHOICES = [
|
||
('important', '重要だった'),
|
||
('not_important', '普通のメール'),
|
||
('never_notify', '今後通知しない'),
|
||
]
|
||
|
||
|
||
class MailEmail(models.Model):
|
||
"""受信メール記録(LLMに渡したメール)"""
|
||
account = models.CharField(max_length=20, choices=ACCOUNT_CHOICES, verbose_name="アカウント")
|
||
message_id = models.CharField(max_length=500, unique=True, verbose_name="Message-ID")
|
||
sender_email = models.EmailField(verbose_name="送信者アドレス")
|
||
sender_domain = models.CharField(max_length=255, verbose_name="送信者ドメイン")
|
||
subject = models.CharField(max_length=500, verbose_name="件名")
|
||
body_preview = models.TextField(verbose_name="本文冒頭")
|
||
received_at = models.DateTimeField(verbose_name="受信日時")
|
||
llm_verdict = models.CharField(
|
||
max_length=20,
|
||
choices=[('important', '重要'), ('not_important', '重要でない')],
|
||
verbose_name="LLM判定"
|
||
)
|
||
notified_at = models.DateTimeField(null=True, blank=True, verbose_name="LINE通知日時")
|
||
feedback = models.CharField(
|
||
max_length=20,
|
||
choices=FEEDBACK_CHOICES,
|
||
null=True, blank=True,
|
||
verbose_name="フィードバック"
|
||
)
|
||
feedback_at = models.DateTimeField(null=True, blank=True, verbose_name="フィードバック日時")
|
||
|
||
class Meta:
|
||
verbose_name = "受信メール"
|
||
verbose_name_plural = "受信メール"
|
||
ordering = ['-received_at']
|
||
|
||
def __str__(self):
|
||
return f"{self.subject} ({self.sender_email})"
|
||
|
||
|
||
class MailNotificationToken(models.Model):
|
||
"""LINEフィードバックURL用トークン(有効期限なし)"""
|
||
email = models.OneToOneField(
|
||
MailEmail,
|
||
on_delete=models.CASCADE,
|
||
related_name='notification_token',
|
||
verbose_name="メール"
|
||
)
|
||
token = models.UUIDField(default=uuid.uuid4, unique=True, verbose_name="トークン")
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
class Meta:
|
||
verbose_name = "通知トークン"
|
||
verbose_name_plural = "通知トークン"
|
||
|
||
def __str__(self):
|
||
return str(self.token)
|