Add dispute system
This commit is contained in:
@@ -7,6 +7,7 @@ from app.models.assignment import Assignment, AssignmentStatus
|
||||
from app.models.activity import Activity, ActivityType
|
||||
from app.models.event import Event, EventType
|
||||
from app.models.swap_request import SwapRequest, SwapRequestStatus
|
||||
from app.models.dispute import Dispute, DisputeStatus, DisputeComment, DisputeVote
|
||||
|
||||
__all__ = [
|
||||
"User",
|
||||
@@ -30,4 +31,8 @@ __all__ = [
|
||||
"EventType",
|
||||
"SwapRequest",
|
||||
"SwapRequestStatus",
|
||||
"Dispute",
|
||||
"DisputeStatus",
|
||||
"DisputeComment",
|
||||
"DisputeVote",
|
||||
]
|
||||
|
||||
@@ -10,6 +10,7 @@ class AssignmentStatus(str, Enum):
|
||||
ACTIVE = "active"
|
||||
COMPLETED = "completed"
|
||||
DROPPED = "dropped"
|
||||
RETURNED = "returned" # Disputed and needs to be redone
|
||||
|
||||
|
||||
class Assignment(Base):
|
||||
@@ -34,3 +35,4 @@ class Assignment(Base):
|
||||
participant: Mapped["Participant"] = relationship("Participant", back_populates="assignments")
|
||||
challenge: Mapped["Challenge"] = relationship("Challenge", back_populates="assignments")
|
||||
event: Mapped["Event | None"] = relationship("Event", back_populates="assignments")
|
||||
dispute: Mapped["Dispute | None"] = relationship("Dispute", back_populates="assignment", uselist=False)
|
||||
|
||||
66
backend/app/models/dispute.py
Normal file
66
backend/app/models/dispute.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from sqlalchemy import String, Text, DateTime, ForeignKey, Boolean, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class DisputeStatus(str, Enum):
|
||||
OPEN = "open"
|
||||
RESOLVED_VALID = "valid"
|
||||
RESOLVED_INVALID = "invalid"
|
||||
|
||||
|
||||
class Dispute(Base):
|
||||
"""Dispute against a completed assignment's proof"""
|
||||
__tablename__ = "disputes"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
assignment_id: Mapped[int] = mapped_column(ForeignKey("assignments.id", ondelete="CASCADE"), unique=True, index=True)
|
||||
raised_by_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"))
|
||||
reason: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(20), default=DisputeStatus.OPEN.value)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
resolved_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
# Relationships
|
||||
assignment: Mapped["Assignment"] = relationship("Assignment", back_populates="dispute")
|
||||
raised_by: Mapped["User"] = relationship("User", foreign_keys=[raised_by_id])
|
||||
comments: Mapped[list["DisputeComment"]] = relationship("DisputeComment", back_populates="dispute", cascade="all, delete-orphan")
|
||||
votes: Mapped[list["DisputeVote"]] = relationship("DisputeVote", back_populates="dispute", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class DisputeComment(Base):
|
||||
"""Comment in a dispute discussion"""
|
||||
__tablename__ = "dispute_comments"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
dispute_id: Mapped[int] = mapped_column(ForeignKey("disputes.id", ondelete="CASCADE"), index=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"))
|
||||
text: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
dispute: Mapped["Dispute"] = relationship("Dispute", back_populates="comments")
|
||||
user: Mapped["User"] = relationship("User")
|
||||
|
||||
|
||||
class DisputeVote(Base):
|
||||
"""Vote in a dispute (valid or invalid)"""
|
||||
__tablename__ = "dispute_votes"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
dispute_id: Mapped[int] = mapped_column(ForeignKey("disputes.id", ondelete="CASCADE"), index=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"))
|
||||
vote: Mapped[bool] = mapped_column(Boolean, nullable=False) # True = valid, False = invalid
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||
|
||||
# Unique constraint: one vote per user per dispute
|
||||
__table_args__ = (
|
||||
UniqueConstraint("dispute_id", "user_id", name="uq_dispute_vote_user"),
|
||||
)
|
||||
|
||||
# Relationships
|
||||
dispute: Mapped["Dispute"] = relationship("Dispute", back_populates="votes")
|
||||
user: Mapped["User"] = relationship("User")
|
||||
Reference in New Issue
Block a user