Question ids come from a sequence and are never reissued, and fourteen tables point at them — attempts, quiz membership, exam membership, media, article links, notes, favourites, feedback. Deleting the row took all of that with it, so "restore" could only ever have meant typing the text in again as a different question. DELETE now sets deleted_at. The question leaves the bank, the builder, search and every share path at once, because the exclusion lives in general_question_predicate rather than at each call site. Restoring puts back the same id, so everything that pointed at it still does. Erasing for real requires the trash first and a moderator, and the confirmation says what goes with it. The trash page holds questions instead of tests. A test is a selection you can remake in a minute; nobody wanted those back. Used and withdrawn invite codes can be removed — an unused one is still withdrawn rather than deleted, so it stays visible as having been issued and stopped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
27 lines
872 B
Python
27 lines
872 B
Python
"""Questions are soft-deleted.
|
|
|
|
A question id comes from a sequence and is never reissued, and fourteen tables
|
|
reference it — attempts, quiz membership, exam membership, media, article
|
|
links, notes, favourites, feedback. Deleting the row took all of that with it,
|
|
so "restore" could never have meant more than "type it in again with a new id".
|
|
|
|
Revision ID: f6a7b8c9d0e1
|
|
Revises: e5f6a7b8c9d0
|
|
"""
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision = "f6a7b8c9d0e1"
|
|
down_revision = "e5f6a7b8c9d0"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column("questions", sa.Column("deleted_at", sa.DateTime(), nullable=True))
|
|
op.create_index("ix_questions_deleted_at", "questions", ["deleted_at"])
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_index("ix_questions_deleted_at", table_name="questions")
|
|
op.drop_column("questions", "deleted_at")
|