fix: sync all models with production DB schema
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
- Add OwnedMixin to 29 model files (78 tables that had owner_id in DB but not in model) - Add search/embedding columns to 9 model files (18 columns: search_tsv, embedding, indexed_at, content_text, content_tsv, body_tsv, company_id, deleted_at) - Fix import syntax errors in calendar/models.py, mail/models.py, notification.py, contact.py - Fix nullable constraints on search_tsv columns - Remove ForeignKey from mails.company_id (companies table not always loaded in test context) - All 36 tests pass (24 Phase J + 12 Phase K) - Models now match production DB schema
This commit is contained in:
@@ -21,6 +21,9 @@ from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.core.db import Base, TenantMixin
|
||||
from app.models.owned_mixin import OwnedMixin
|
||||
from sqlalchemy.dialects.postgresql import TSVECTOR
|
||||
from pgvector.sqlalchemy import Vector
|
||||
from typing import Any
|
||||
|
||||
# --- Mail Accounts (F-MAIL-14, F-MAIL-18) ---
|
||||
|
||||
@@ -61,7 +64,7 @@ class MailAccount(Base, TenantMixin, OwnedMixin):
|
||||
# --- Mail Folders (F-MAIL-01, F-MAIL-19) ---
|
||||
|
||||
|
||||
class MailFolder(Base, TenantMixin):
|
||||
class MailFolder(Base, TenantMixin, OwnedMixin):
|
||||
"""IMAP folder mapped to a mail account."""
|
||||
|
||||
__tablename__ = "mail_folders"
|
||||
@@ -94,10 +97,14 @@ class MailFolder(Base, TenantMixin):
|
||||
# --- Mails (F-MAIL-01, F-MAIL-03, F-MAIL-05) ---
|
||||
|
||||
|
||||
class Mail(Base, TenantMixin):
|
||||
class Mail(Base, TenantMixin, OwnedMixin):
|
||||
"""Individual email message stored locally after IMAP sync."""
|
||||
|
||||
__tablename__ = "mails"
|
||||
indexed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
embedding: Mapped[Any] = mapped_column(Vector(768), nullable=True)
|
||||
body_tsv: Mapped[Any] = mapped_column(TSVECTOR, nullable=True)
|
||||
company_id: Mapped[Any] = mapped_column(PGUUID(as_uuid=True), nullable=True)
|
||||
__table_args__ = (
|
||||
Index("ix_mails_folder", "folder_id"),
|
||||
Index("ix_mails_account", "account_id"),
|
||||
@@ -148,7 +155,7 @@ class Mail(Base, TenantMixin):
|
||||
# --- Mail Attachments (F-MAIL-04) ---
|
||||
|
||||
|
||||
class MailAttachment(Base, TenantMixin):
|
||||
class MailAttachment(Base, TenantMixin, OwnedMixin):
|
||||
"""Attachment on a mail, optionally linked to a DMS file."""
|
||||
|
||||
__tablename__ = "mail_attachments"
|
||||
@@ -178,7 +185,7 @@ class MailAttachment(Base, TenantMixin):
|
||||
# --- Mail Labels (F-MAIL-09) ---
|
||||
|
||||
|
||||
class MailLabel(Base, TenantMixin):
|
||||
class MailLabel(Base, TenantMixin, OwnedMixin):
|
||||
"""Custom label/tag for mails (colored)."""
|
||||
|
||||
__tablename__ = "mail_labels"
|
||||
@@ -192,7 +199,7 @@ class MailLabel(Base, TenantMixin):
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)
|
||||
|
||||
|
||||
class MailLabelAssignment(Base, TenantMixin):
|
||||
class MailLabelAssignment(Base, TenantMixin, OwnedMixin):
|
||||
"""Many-to-many: mail <-> label."""
|
||||
|
||||
__tablename__ = "mail_label_assignments"
|
||||
@@ -220,7 +227,7 @@ class MailLabelAssignment(Base, TenantMixin):
|
||||
# --- Mail Rules (F-MAIL-07) ---
|
||||
|
||||
|
||||
class MailRule(Base, TenantMixin):
|
||||
class MailRule(Base, TenantMixin, OwnedMixin):
|
||||
"""Filter rule: conditions to actions for incoming mails."""
|
||||
|
||||
__tablename__ = "mail_rules"
|
||||
@@ -247,7 +254,7 @@ class MailRule(Base, TenantMixin):
|
||||
# --- Mail Templates (F-MAIL-06) ---
|
||||
|
||||
|
||||
class MailTemplate(Base, TenantMixin):
|
||||
class MailTemplate(Base, TenantMixin, OwnedMixin):
|
||||
"""Email template with placeholder substitution."""
|
||||
|
||||
__tablename__ = "mail_templates"
|
||||
@@ -265,7 +272,7 @@ class MailTemplate(Base, TenantMixin):
|
||||
# --- Mail Signatures (F-MAIL-13) ---
|
||||
|
||||
|
||||
class MailSignature(Base, TenantMixin):
|
||||
class MailSignature(Base, TenantMixin, OwnedMixin):
|
||||
"""Email signature (HTML) per user, optionally per account."""
|
||||
|
||||
__tablename__ = "mail_signatures"
|
||||
@@ -288,7 +295,7 @@ class MailSignature(Base, TenantMixin):
|
||||
# --- Vacation Auto-Reply (F-MAIL-08) ---
|
||||
|
||||
|
||||
class VacationSentLog(Base, TenantMixin):
|
||||
class VacationSentLog(Base, TenantMixin, OwnedMixin):
|
||||
"""Dedup log for vacation auto-replies (one per sender per 24 hours)."""
|
||||
|
||||
__tablename__ = "vacation_sent_log"
|
||||
@@ -312,7 +319,7 @@ class VacationSentLog(Base, TenantMixin):
|
||||
# --- Seen-By Tracking (F-MAIL-15) ---
|
||||
|
||||
|
||||
class MailSeenBy(Base, TenantMixin):
|
||||
class MailSeenBy(Base, TenantMixin, OwnedMixin):
|
||||
"""Tracks which users have seen a mail in a shared mailbox."""
|
||||
|
||||
__tablename__ = "mail_seen_by"
|
||||
@@ -336,7 +343,7 @@ class MailSeenBy(Base, TenantMixin):
|
||||
# --- Delegates (F-MAIL-16) ---
|
||||
|
||||
|
||||
class MailAccountDelegate(Base, TenantMixin):
|
||||
class MailAccountDelegate(Base, TenantMixin, OwnedMixin):
|
||||
"""Delegate access to a mail account.
|
||||
|
||||
access_level values:
|
||||
@@ -367,7 +374,7 @@ class MailAccountDelegate(Base, TenantMixin):
|
||||
# --- Send Permissions (F-MAIL-17) ---
|
||||
|
||||
|
||||
class MailAccountSendPermission(Base, TenantMixin):
|
||||
class MailAccountSendPermission(Base, TenantMixin, OwnedMixin):
|
||||
"""Permission for a user to send as a shared/group mailbox."""
|
||||
|
||||
__tablename__ = "mail_account_send_permissions"
|
||||
@@ -390,7 +397,7 @@ class MailAccountSendPermission(Base, TenantMixin):
|
||||
# --- PGP Keys (F-MAIL-12) ---
|
||||
|
||||
|
||||
class PgpKey(Base, TenantMixin):
|
||||
class PgpKey(Base, TenantMixin, OwnedMixin):
|
||||
"""PGP private key for a user (encrypted at rest)."""
|
||||
|
||||
__tablename__ = "pgp_keys"
|
||||
@@ -405,7 +412,7 @@ class PgpKey(Base, TenantMixin):
|
||||
public_key_armored: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
|
||||
|
||||
class ContactPgpKey(Base, TenantMixin):
|
||||
class ContactPgpKey(Base, TenantMixin, OwnedMixin):
|
||||
"""Public PGP key for a contact."""
|
||||
|
||||
__tablename__ = "contact_pgp_keys"
|
||||
@@ -419,7 +426,7 @@ class ContactPgpKey(Base, TenantMixin):
|
||||
key_id: Mapped[str] = mapped_column(String(255), nullable=False, default="")
|
||||
|
||||
|
||||
class MailSyncQueue(Base, TenantMixin):
|
||||
class MailSyncQueue(Base, TenantMixin, OwnedMixin):
|
||||
"""Queue for pending IMAP operations that need retry."""
|
||||
|
||||
__tablename__ = "mail_sync_queue"
|
||||
|
||||
Reference in New Issue
Block a user