-
Notifications
You must be signed in to change notification settings - Fork 0
First Elections PR #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
d67b000
Added elections model to alembic/env.py
DerpyWasHere 905170b
Added election tables revision to alembic
DerpyWasHere 7cb496c
Initial elections model implementation
DerpyWasHere 8b06dda
Redid revision, added position column to NomineeAplication, renamed N…
DerpyWasHere b5103ca
Added ElectionOfficer class, created has_permission() to check whethe…
DerpyWasHere b579e08
Changed date to be nonnull, officer_id in alembic revision
DerpyWasHere c89e659
Removed unique constraint on officer_id
DerpyWasHere 117611a
Removed unique constraint on officer_id, removed nullability from date
DerpyWasHere 3aded13
properly handled session validation on create_elections
DerpyWasHere fc8def5
created create_election stub
DerpyWasHere d9b8e52
added elections router to main
DerpyWasHere e239b9b
Working commit containing fns to create, delete, and update elections
DerpyWasHere 8bf5dcb
Merge branch 'main' into dev-issue-25
EarthenSky 06fe816
switch from models to tables
EarthenSky 82685ef
fix small import bug
EarthenSky 0c299d2
fix past alembic migration
EarthenSky 5a2b886
Removed enum in urls.py, satisfied linter for tables.py
DerpyWasHere 5faad35
Changed old ElectionTypes enum into a string array
DerpyWasHere 7b465b5
Changed query in get_election() to be more SQL-like.
DerpyWasHere 44d60f3
Changed list comprehension in create_election() to just a 'if not in'…
DerpyWasHere 40eedd7
Made change referenced in pr 63 wrt committing transactions in get_el…
DerpyWasHere e2bb4db
Removed commits from crud.py and added commits to endpoints in urls.py
DerpyWasHere 50302b1
Changed occurrences of websurvey to survey_link to match that websurv…
DerpyWasHere 82ccc24
Changed election parameters from a list to a dedicated dataclass, ref…
DerpyWasHere a36eef6
Changed parameter orders to be consistent with other crud functions i…
DerpyWasHere 057e405
Merge branch 'main' into dev-issue-25
DerpyWasHere ff2951c
Appeased linter
DerpyWasHere 8d0e267
Reintroduced elections router into main.py
DerpyWasHere 40041ad
update down revision to be blog posts
EarthenSky 853038d
Added lost default param in elections table migration
DerpyWasHere 2dee83a
Changed discord id length in election_nominee table from 18 to 32.
DerpyWasHere 945fb29
Changed date -> start_date in elections table
DerpyWasHere 57f4b2a
Changed date -> start_datetime, start_date -> start_datetime, end_dat…
DerpyWasHere 1c61134
Changed date -> start_datetime, end_date -> end_datetime
DerpyWasHere def5346
update formatting & fix some small access bugs
EarthenSky dadd620
update comment
EarthenSky 3a66f37
Update urls.py
EarthenSky 80a6105
update POST election
EarthenSky bfbd082
Update urls.py
EarthenSky df870d0
fix import style
EarthenSky 8e64f4d
complete election crud and election crud urls
EarthenSky 551e73f
add test data, fix bugs, refactor
EarthenSky d54ec21
test all endpoints & fix bugs
EarthenSky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
src/alembic/versions/243190df5588_create_election_tables.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| """create election tables | ||
|
|
||
| Revision ID: 243190df5588 | ||
| Revises: 43f71e4bd6fc | ||
| Create Date: 2024-08-10 08:32:54.037614 | ||
|
|
||
| """ | ||
| from collections.abc import Sequence | ||
| from typing import Union | ||
|
|
||
| import sqlalchemy as sa | ||
|
|
||
| from alembic import op | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision: str = "243190df5588" | ||
| down_revision: str | None = "2a6ea95342dc" | ||
| branch_labels: str | Sequence[str] | None = None | ||
| depends_on: str | Sequence[str] | None = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| op.create_table( | ||
| "election", | ||
| sa.Column("slug", sa.String(length=64), nullable=False), | ||
| sa.Column("name", sa.String(length=64), nullable=False), | ||
| sa.Column("type", sa.String(length=64), default="general_election"), | ||
| sa.Column("datetime_start_nominations", sa.DateTime(), nullable=False), | ||
| sa.Column("datetime_start_voting", sa.DateTime(), nullable=False), | ||
| sa.Column("datetime_end_voting", sa.DateTime(), nullable=False), | ||
| sa.Column("survey_link", sa.String(length=300), nullable=True), | ||
| sa.PrimaryKeyConstraint("slug") | ||
| ) | ||
| op.create_table( | ||
| "election_nominee", | ||
| sa.Column("computing_id", sa.String(length=32), nullable=False), | ||
| sa.Column("full_name", sa.String(length=64), nullable=False), | ||
| sa.Column("facebook", sa.String(length=128), nullable=True), | ||
| sa.Column("instagram", sa.String(length=128), nullable=True), | ||
| sa.Column("email", sa.String(length=64), nullable=True), | ||
| sa.Column("discord", sa.String(length=32), nullable=True), | ||
| sa.Column("discord_id", sa.String(length=32), nullable=True), | ||
| sa.Column("discord_username", sa.String(length=32), nullable=True), | ||
| sa.PrimaryKeyConstraint("computing_id") | ||
| ) | ||
| op.create_table( | ||
| "nominee_application", | ||
| sa.Column("computing_id", sa.String(length=32), nullable=False), | ||
| sa.Column("nominee_election", sa.String(length=32), nullable=False), | ||
| sa.Column("speech", sa.Text(), nullable=True), | ||
| sa.Column("position", sa.String(length=64), nullable=False), | ||
| sa.ForeignKeyConstraint(["computing_id"], ["election_nominee.computing_id"]), | ||
| sa.ForeignKeyConstraint(["nominee_election"], ["election.slug"]), | ||
| sa.PrimaryKeyConstraint("computing_id", "nominee_election") | ||
| ) | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| op.drop_table("nominee_application") | ||
| op.drop_table("election_nominee") | ||
| op.drop_table("election") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import logging | ||
|
|
||
| import sqlalchemy | ||
| from sqlalchemy.ext.asyncio import AsyncSession | ||
|
|
||
| from elections.tables import Election | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
| async def get_election(db_session: AsyncSession, election_slug: str) -> Election | None: | ||
| return await db_session.scalar( | ||
| sqlalchemy | ||
| .select(Election) | ||
| .where(Election.slug == election_slug) | ||
| ) | ||
|
|
||
| async def create_election(db_session: AsyncSession, election: Election) -> None: | ||
| """ | ||
| Creates a new election with given parameters. | ||
| Does not validate if an election _already_ exists | ||
| """ | ||
| db_session.add(election) | ||
|
|
||
| async def delete_election(db_session: AsyncSession, slug: str) -> None: | ||
| """ | ||
| Deletes a given election by its slug. | ||
| Does not validate if an election exists | ||
| """ | ||
| await db_session.execute( | ||
| sqlalchemy | ||
| .delete(Election) | ||
| .where(Election.slug == slug) | ||
| ) | ||
|
|
||
| async def update_election(db_session: AsyncSession, new_election: Election) -> bool: | ||
| """ | ||
| You attempting to change the name or slug will fail. Instead, you must create a new election. | ||
| """ | ||
| target_slug = new_election.slug | ||
| target_election = await get_election(db_session, target_slug) | ||
|
|
||
| if target_election is None: | ||
| return False | ||
| else: | ||
| await db_session.execute( | ||
| sqlalchemy | ||
| .update(Election) | ||
| .where(Election.slug == target_slug) | ||
| .values(new_election.to_update_dict()) | ||
| ) | ||
| return True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| from sqlalchemy import ( | ||
| Column, | ||
| DateTime, | ||
| ForeignKey, | ||
| PrimaryKeyConstraint, | ||
| String, | ||
| Text, | ||
| ) | ||
|
|
||
| from constants import ( | ||
| COMPUTING_ID_LEN, | ||
| DISCORD_ID_LEN, | ||
| DISCORD_NAME_LEN, | ||
| DISCORD_NICKNAME_LEN, | ||
| ) | ||
| from database import Base | ||
|
|
||
| election_types = ["general_election", "by_election", "council_rep_election"] | ||
|
|
||
| MAX_ELECTION_NAME = 64 | ||
| MAX_ELECTION_SLUG = 64 | ||
|
|
||
| class Election(Base): | ||
| __tablename__ = "election" | ||
|
|
||
| # Slugs are unique identifiers | ||
| slug = Column(String(MAX_ELECTION_SLUG), primary_key=True) | ||
| name = Column(String(MAX_ELECTION_NAME), nullable=False) | ||
| type = Column(String(64), default="general_election") | ||
| datetime_start_nominations = Column(DateTime, nullable=False) | ||
| datetime_start_voting = Column(DateTime, nullable=False) | ||
| datetime_end_voting = Column(DateTime, nullable=False) | ||
| survey_link = Column(String(300)) | ||
|
|
||
| def serializable_dict(self) -> dict: | ||
| return { | ||
| "slug": self.slug, | ||
| "name": self.name, | ||
| "type": self.type, | ||
|
|
||
| "datetime_start_nominations": self.datetime_start_nominations.isoformat(), | ||
| "datetime_start_voting": self.datetime_start_voting.isoformat(), | ||
| "datetime_end_voting": self.datetime_end_voting.isoformat(), | ||
|
|
||
| "survey_link": self.survey_link, | ||
| } | ||
|
|
||
| def public_details(self) -> dict: | ||
| return { | ||
| "slug": self.slug, | ||
| "name": self.name, | ||
| "type": self.type, | ||
|
|
||
| "datetime_start_nominations": self.datetime_start_nominations.isoformat(), | ||
| "datetime_start_voting": self.datetime_start_voting.isoformat(), | ||
| "datetime_end_voting": self.datetime_end_voting.isoformat(), | ||
| } | ||
|
|
||
| def to_update_dict(self) -> dict: | ||
| return { | ||
| "slug": self.slug, | ||
| "name": self.name, | ||
| "type": self.type, | ||
|
|
||
| "datetime_start_nominations": self.datetime_start_nominations, | ||
| "datetime_start_voting": self.datetime_start_voting, | ||
| "datetime_end_voting": self.datetime_end_voting, | ||
|
|
||
| "survey_link": self.survey_link, | ||
| } | ||
|
|
||
| # Each row represents a nominee of a given election | ||
| class Nominee(Base): | ||
| __tablename__ = "election_nominee" | ||
|
|
||
| # Previously named sfuid | ||
| computing_id = Column(String(COMPUTING_ID_LEN), primary_key=True) | ||
| full_name = Column(String(64), nullable=False) | ||
| facebook = Column(String(128)) | ||
| instagram = Column(String(128)) | ||
| email = Column(String(64)) | ||
| discord = Column(String(DISCORD_NAME_LEN)) | ||
| discord_id = Column(String(DISCORD_ID_LEN)) | ||
| discord_username = Column(String(DISCORD_NICKNAME_LEN)) | ||
|
|
||
| class NomineeApplication(Base): | ||
| __tablename__ = "nominee_application" | ||
|
|
||
| computing_id = Column(ForeignKey("election_nominee.computing_id"), primary_key=True) | ||
| nominee_election = Column(ForeignKey("election.slug"), primary_key=True) | ||
| speech = Column(Text) | ||
| position = Column(String(64), nullable=False) | ||
|
|
||
| __table_args__ = ( | ||
| PrimaryKeyConstraint(computing_id, nominee_election), | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.