"""Bank content belongs to a role, not to a person. The bank was full of rows with somebody's name on them: 571 categories, 21 uploaded documents, 14 articles, 8 card decks, the shared tests. Most of them said daniel@danvics.com, an address that is not even the working administrator any more — so "who may edit this" partly depended on who happened to have created it years ago, and handing the site to somebody else would have meant rewriting every one of those rows. Ownership of the bank is now the `admin` role plus CategoryGrant, and these columns are emptied to say so. Nothing is deleted and no row moves: only the name comes off. What keeps its owner, deliberately, because it is genuinely one person's: quiz_attempts, question_notes, article_section_notes, favorites, user_collections, question_folders, study_plan_* progress, and the quizzes that are somebody's own sittings (is_shared = 0) rather than bank tests. study_plans needed nothing: it never had an owner column. Revision ID: q6a7b8c9d0e1 Revises: p5f6a7b8c9d0 """ from alembic import op import sqlalchemy as sa revision = "q6a7b8c9d0e1" down_revision = "p5f6a7b8c9d0" branch_labels = None depends_on = None #: Everything in the bank, and the condition that picks the bank rows out of a #: table that also holds personal ones. BANK = [ ("question_categories", None), ("articles", None), ("pdf_documents", None), ("flashcard_decks", None), ("questions", None), ("media_assets", None), ("media_libraries", None), ("quiz_categories", None), # A shared test is the bank's; an unshared one is a sitting of somebody's # own and stays theirs. ("quizzes", "is_shared = 1"), ] #: Tables whose user_id was declared NOT NULL. "Ownerless" is now a legitimate #: state for bank content, so the column has to be allowed to say so — and a #: NOT NULL owner column is exactly the thing that forced a person's name onto #: every row in the first place. NULLABLE = ("question_categories", "pdf_documents", "flashcard_decks", "quiz_categories", "quizzes") def upgrade(): for table in NULLABLE: op.alter_column(table, "user_id", existing_type=sa.Integer(), nullable=True) for table, where in BANK: clause = f" AND {where}" if where else "" op.execute(sa.text( f"UPDATE {table} SET user_id = NULL WHERE user_id IS NOT NULL{clause}")) def downgrade(): # Deliberately not reversible. The names are not recorded anywhere once # they are gone, and inventing an owner would be worse than admitting the # information is not here: restore from the dump taken beside this change. pass