gabriel / musehub public
musehub_collaborator_models.py python
65 lines 2.2 KB
cd448303 Initial extraction of MuseHub from maestro monorepo. Gabriel Cardona <gabriel@tellurstori.com> 7d ago
1 """SQLAlchemy ORM model for Muse Hub collaborators.
2
3 Collaborators are users granted explicit push/admin access to a repo beyond
4 the owner. Permission levels: read | write | admin (default: write).
5 """
6 from __future__ import annotations
7
8 import uuid
9 from datetime import datetime, timezone
10
11 from sqlalchemy import DateTime, ForeignKey, Index, String, UniqueConstraint
12 from sqlalchemy.orm import Mapped, mapped_column
13
14 from musehub.db.database import Base
15
16
17 def _new_uuid() -> str:
18 return str(uuid.uuid4())
19
20
21 def _utc_now() -> datetime:
22 return datetime.now(tz=timezone.utc)
23
24
25 class MusehubCollaborator(Base):
26 """A collaborator record granting a user explicit access to a repo.
27
28 ``permission`` is one of "read" | "write" | "admin"; defaults to "write".
29 ``invited_by`` references the user who extended the invitation (nullable
30 some collaborators may be added programmatically without an inviter).
31 ``accepted_at`` is null until the invited user explicitly accepts.
32 """
33
34 __tablename__ = "musehub_collaborators"
35 __table_args__ = (
36 UniqueConstraint("repo_id", "user_id", name="uq_musehub_collaborators_repo_user"),
37 Index("ix_musehub_collaborators_repo_id", "repo_id"),
38 Index("ix_musehub_collaborators_user_id", "user_id"),
39 )
40
41 id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_uuid)
42 repo_id: Mapped[str] = mapped_column(
43 String(36),
44 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
45 nullable=False,
46 )
47 user_id: Mapped[str] = mapped_column(
48 String(36),
49 ForeignKey("maestro_users.id", ondelete="CASCADE"),
50 nullable=False,
51 )
52 # Permission level: "read" | "write" | "admin"
53 permission: Mapped[str] = mapped_column(String(20), nullable=False, default="write")
54 invited_by: Mapped[str | None] = mapped_column(
55 String(36),
56 ForeignKey("maestro_users.id", ondelete="SET NULL"),
57 nullable=True,
58 )
59 invited_at: Mapped[datetime] = mapped_column(
60 DateTime(timezone=True), nullable=False, default=_utc_now
61 )
62 # Null until the invited user accepts the invitation
63 accepted_at: Mapped[datetime | None] = mapped_column(
64 DateTime(timezone=True), nullable=True
65 )