aurweb/migrations/versions/84cd90073dde_relocate_vote_decisions_into_tuvote.py
Kevin Morris a29701459c
feat: add Decision column to TUVote
In preparation for allowing TUs to change their votes on proposals,
we need a way to track what users vote for.

Without this, the vote decisions are stored within the related
TU_VoteInfo record, decoupled from the user who made the vote.

That being the case meant we cannot actually change a vote, because
we can't figure out what TU_VoteInfo decision columns to decrement
when the vote has changed.

You may be wondering why we aren't removing the decision columns out
of TU_VoteInfo with the advent of this new column. The reason being:
previous votes are all calculated off of the TU_VoteInfo columns, so
without a manual DB rework, relocating them to the user-related vote
records would break outcomes of old proposals. So, the plan is:
we'll solely use this column for votes from this point on to track
what decision a user made internally, which will open up TUs changing
their decision.

In addition, this migration resets all running proposals:
- all votes are deleted
- time is reset to Start when migration is run

This was necessary to put running proposals into a state that can
take advantage of the new revote system.

Signed-off-by: Kevin Morris <kevr@0cost.org>
2022-03-07 22:35:52 -08:00

61 lines
2 KiB
Python

"""relocate vote decisions into TUVote
Revision ID: 84cd90073dde
Revises: d64e5571bc8d
Create Date: 2022-03-07 18:02:28.791103
This migration allows us to give Trusted Users the ability to
modify a vote they made on a proposal. Previously, the decision
was tracked purely through TU_VoteInfo records, which removes
tracking of what decisions users made. This blocks us from being
able to modify votes, because we can't update the TU_VoteInfo
Yes, No or Abstain columns properly.
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects.mysql import TINYINT
from aurweb import db, logging, time
from aurweb.models import TUVoteInfo
logger = logging.get_logger("alembic")
# revision identifiers, used by Alembic.
revision = '84cd90073dde'
down_revision = 'd64e5571bc8d'
branch_labels = None
depends_on = None
TABLE = "TU_Votes"
def upgrade():
decision = sa.Column("Decision", TINYINT(unsigned=True))
op.add_column(TABLE, decision)
# For each proposal which is running at the time this migration
# is applied, eradicate all related votes. We will restart the votes.
# In addition, reset the Submitted and End columns based on the current
# timestamp; essentially resetting the proposal's state.
utcnow = time.utcnow()
running_proposals = db.query(TUVoteInfo).filter(TUVoteInfo.End > utcnow)
with db.begin():
for proposal in running_proposals:
logger.info(f"Resetting proposal with ID {proposal.ID}: "
"Yes = 0, No = 0, Abstain = 0, deleted vote records")
# Reset the Submitted and End columns.
length = proposal.End - proposal.Submitted
proposal.Submitted = utcnow
proposal.End = utcnow + length
proposal.Yes = proposal.No = proposal.Abstain = 0
db.delete_all(proposal.tu_votes)
logger.info(f"Proposal time range was reset: Submitted = "
f"{proposal.Submitted} and End = {proposal.End}")
def downgrade():
op.drop_column(TABLE, "Decision")