diff --git a/api/__init__.py b/api/__init__.py index e51aa0b..029ccb5 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -6,9 +6,7 @@ date_format_string = "%Y-%m-%d %H:%M:%S %z" logging.basicConfig( - format=format_string, - datefmt=date_format_string, - level=getattr(logging, constants.Config.LOG_LEVEL.upper()) + format=format_string, datefmt=date_format_string, level=getattr(logging, constants.Config.LOG_LEVEL.upper()) ) logging.getLogger().info("Logging initialization complete") diff --git a/api/database.py b/api/database.py index 28720c0..99d9213 100644 --- a/api/database.py +++ b/api/database.py @@ -15,9 +15,7 @@ class TeamUser(Base): """A user who belongs to a team.""" __tablename__ = "team_has_user" - __table_args__ = ( - PrimaryKeyConstraint('team_id', 'user_id'), - ) + __table_args__ = (PrimaryKeyConstraint("team_id", "user_id"),) team_id = Column(ForeignKey("teams.id"), nullable=False) user_id = Column(ForeignKey("users.id"), nullable=False) @@ -65,18 +63,14 @@ class Team(Base): jam = relationship("Jam", back_populates="teams", lazy="joined") users = relationship("TeamUser", back_populates="team", lazy="joined") - __table_args__ = ( - Index('team_name_jam_unique', text("lower(name)"), "jam_id", unique=True), - ) + __table_args__ = (Index("team_name_jam_unique", text("lower(name)"), "jam_id", unique=True),) class Winner(Base): """A user who has won a code jam.""" __tablename__ = "winners" - __table_args__ = ( - PrimaryKeyConstraint('jam_id', 'user_id'), - ) + __table_args__ = (PrimaryKeyConstraint("jam_id", "user_id"),) jam_id = Column(ForeignKey("jams.id"), nullable=False) user_id = Column(ForeignKey("users.id"), nullable=False) diff --git a/api/middleware.py b/api/middleware.py index 1324616..f9e7b6c 100644 --- a/api/middleware.py +++ b/api/middleware.py @@ -15,9 +15,7 @@ class TokenAuthentication(AuthenticationBackend): def __init__(self, token: str) -> None: self.expected_auth_header = f"Token {token}" - async def authenticate( - self, request: Request - ) -> tuple[AuthCredentials, SimpleUser]: + async def authenticate(self, request: Request) -> tuple[AuthCredentials, SimpleUser]: """Authenticate the request based on the Authorization header.""" if Config.DEBUG: credentials = AuthCredentials(scopes=["debug"]) diff --git a/api/routers/codejams.py b/api/routers/codejams.py index d11fb92..f1c3893 100644 --- a/api/routers/codejams.py +++ b/api/routers/codejams.py @@ -24,11 +24,7 @@ async def get_codejams(session: AsyncSession = Depends(get_db_session)) -> list[ @router.get( "/{codejam_id}", response_model=CodeJamResponse, - responses={ - 404: { - "description": "CodeJam could not be found or there is no ongoing code jam." - } - } + responses={404: {"description": "CodeJam could not be found or there is no ongoing code jam."}}, ) async def get_codejam(codejam_id: int, session: AsyncSession = Depends(get_db_session)) -> Jam: """ @@ -37,9 +33,7 @@ async def get_codejam(codejam_id: int, session: AsyncSession = Depends(get_db_se Passing -1 as the codejam ID will return the ongoing codejam. """ if codejam_id == -1: - ongoing_jams = ( - await session.execute(select(Jam).where(Jam.ongoing == True)) - ).unique().scalars().all() + ongoing_jams = (await session.execute(select(Jam).where(Jam.ongoing == True))).unique().scalars().all() if not ongoing_jams: raise HTTPException(status_code=404, detail="There is no ongoing codejam.") @@ -56,19 +50,12 @@ async def get_codejam(codejam_id: int, session: AsyncSession = Depends(get_db_se return jam -@router.patch( - "/{codejam_id}", - responses={ - 404: { - "description": "Code Jam with specified ID does not exist." - } - } -) +@router.patch("/{codejam_id}", responses={404: {"description": "Code Jam with specified ID does not exist."}}) async def modify_codejam( codejam_id: int, name: Optional[str] = None, ongoing: Optional[bool] = None, - session: AsyncSession = Depends(get_db_session) + session: AsyncSession = Depends(get_db_session), ) -> None: """Modify the specified codejam to change its name and/or whether it's the ongoing code jam.""" codejam = await session.execute(select(Jam).where(Jam.id == codejam_id)) @@ -113,16 +100,19 @@ async def create_codejam(codejam: CodeJam, session: AsyncSession = Depends(get_d jam_id=jam.id, name=raw_team.name, discord_role_id=raw_team.discord_role_id, - discord_channel_id=raw_team.discord_channel_id + discord_channel_id=raw_team.discord_channel_id, ) session.add(team) # Flush here to receive team ID await session.flush() for raw_user in raw_team.users: - if not ( - await session.execute(select(User).where(User.id == raw_user.user_id)) - ).unique().scalars().one_or_none(): + if ( + not (await session.execute(select(User).where(User.id == raw_user.user_id))) + .unique() + .scalars() + .one_or_none() + ): user = User(id=raw_user.user_id) session.add(user) diff --git a/api/routers/infractions.py b/api/routers/infractions.py index cc374f8..c76a020 100644 --- a/api/routers/infractions.py +++ b/api/routers/infractions.py @@ -22,11 +22,7 @@ async def get_infractions(session: AsyncSession = Depends(get_db_session)) -> li @router.get( "/{infraction_id}", response_model=InfractionResponse, - responses={ - 404: { - "description": "Infraction could not be found." - } - } + responses={404: {"description": "Infraction could not be found."}}, ) async def get_infraction(infraction_id: int, session: AsyncSession = Depends(get_db_session)) -> DbInfraction: """Get a specific infraction stored in the database by ID.""" @@ -40,13 +36,7 @@ async def get_infraction(infraction_id: int, session: AsyncSession = Depends(get @router.post( - "/", - response_model=InfractionResponse, - responses={ - 404: { - "Description": "Jam ID or User ID could not be found." - } - } + "/", response_model=InfractionResponse, responses={404: {"Description": "Jam ID or User ID could not be found."}} ) async def create_infraction(infraction: Infraction, session: AsyncSession = Depends(get_db_session)) -> DbInfraction: """Add an infraction for a user to the database.""" @@ -61,10 +51,7 @@ async def create_infraction(infraction: Infraction, session: AsyncSession = Depe raise HTTPException(404, "User with specified ID could not be found.") infraction = DbInfraction( - user_id=user_id, - jam_id=jam_id, - infraction_type=infraction.infraction_type, - reason=infraction.reason + user_id=user_id, jam_id=jam_id, infraction_type=infraction.infraction_type, reason=infraction.reason ) session.add(infraction) await session.flush() diff --git a/api/routers/teams.py b/api/routers/teams.py index 3b283cd..96b340c 100644 --- a/api/routers/teams.py +++ b/api/routers/teams.py @@ -47,15 +47,7 @@ async def get_teams(current_jam: bool = False, session: AsyncSession = Depends(g return teams.scalars().all() -@router.get( - "/find", - response_model=TeamResponse, - responses={ - 404: { - "description": "Team could not be found." - } - } -) +@router.get("/find", response_model=TeamResponse, responses={404: {"description": "Team could not be found."}}) async def find_team_by_name( name: str, jam_id: Optional[int] = None, session: AsyncSession = Depends(get_db_session) ) -> Team: @@ -77,29 +69,13 @@ async def find_team_by_name( return team -@router.get( - "/{team_id}", - response_model=TeamResponse, - responses={ - 404: { - "description": "Team could not be found." - } - } -) +@router.get("/{team_id}", response_model=TeamResponse, responses={404: {"description": "Team could not be found."}}) async def get_team(team_id: int, session: AsyncSession = Depends(get_db_session)) -> Team: """Get a specific code jam team in the database by ID.""" return await ensure_team_exists(team_id, session) -@router.get( - "/{team_id}/users", - response_model=list[User], - responses={ - 404: { - "description": "Team could not be found." - } - } -) +@router.get("/{team_id}/users", response_model=list[User], responses={404: {"description": "Team could not be found."}}) async def get_team_users(team_id: int, session: AsyncSession = Depends(get_db_session)) -> list[TeamUser]: """Get the users of a specific code jam team in the database.""" await ensure_team_exists(team_id, session) @@ -117,10 +93,8 @@ async def get_team_users(team_id: int, session: AsyncSession = Depends(get_db_se 404: { "description": "Team or user could not be found.", }, - 400: { - "description": "This user is already on the team." - } - } + 400: {"description": "This user is already on the team."}, + }, ) async def add_user_to_team( team_id: int, user_id: int, is_leader: bool = False, session: AsyncSession = Depends(get_db_session) @@ -151,10 +125,8 @@ async def add_user_to_team( 404: { "description": "Team or user could not be found.", }, - 400: { - "description": "This user is not on this team." - } - } + 400: {"description": "This user is not on this team."}, + }, ) async def remove_user_from_team( team_id: int, user_id: int, session: AsyncSession = Depends(get_db_session) diff --git a/api/routers/users.py b/api/routers/users.py index 853d1d4..3587519 100644 --- a/api/routers/users.py +++ b/api/routers/users.py @@ -33,8 +33,12 @@ async def get_user_data(session: AsyncSession, user_id: int) -> dict[str, Any]: participation_history.append( { - "jam_id": user_team.team.jam.id, "top_10": top_10, "first_place": first_place, - "team_id": user_team.team.id, "is_leader": user_team.is_leader, "infractions": infractions + "jam_id": user_team.team.jam.id, + "top_10": top_10, + "first_place": first_place, + "team_id": user_team.team.id, + "is_leader": user_team.is_leader, + "infractions": infractions, } ) @@ -52,15 +56,7 @@ async def get_users(session: AsyncSession = Depends(get_db_session)) -> list[dic return [await get_user_data(session, user) for user in users.scalars().all()] -@router.get( - "/{user_id}", - response_model=UserResponse, - responses={ - 404: { - "description": "User could not be found." - } - } -) +@router.get("/{user_id}", response_model=UserResponse, responses={404: {"description": "User could not be found."}}) async def get_user(user_id: int, session: AsyncSession = Depends(get_db_session)) -> dict[str, Any]: """Get a specific user stored in the database by ID.""" user = await session.execute(select(User).where(User.id == user_id)) @@ -72,15 +68,7 @@ async def get_user(user_id: int, session: AsyncSession = Depends(get_db_session) return await get_user_data(session, user_id) -@router.post( - "/{user_id}", - response_model=UserResponse, - responses={ - 400: { - "description": "User already exists." - } - } -) +@router.post("/{user_id}", response_model=UserResponse, responses={400: {"description": "User already exists."}}) async def create_user(user_id: int, session: AsyncSession = Depends(get_db_session)) -> dict[str, Any]: """Create a new user with the specified ID to the database.""" user = await session.execute(select(User).where(User.id == user_id)) @@ -102,12 +90,10 @@ async def create_user(user_id: int, session: AsyncSession = Depends(get_db_sessi responses={ 404: { "description": ( - "User not found, " - "there is no ongoing code jam or " - "user isn't participating in current code jam." + "User not found, " "there is no ongoing code jam or " "user isn't participating in current code jam." ) } - } + }, ) async def get_current_team(user_id: int, session: AsyncSession = Depends(get_db_session)) -> dict[str, Any]: """Get a user's current team information.""" @@ -117,16 +103,12 @@ async def get_current_team(user_id: int, session: AsyncSession = Depends(get_db_ if not user.scalars().one_or_none(): raise HTTPException(status_code=404, detail="User with specified ID could not be found.") - ongoing_jam = ( - await session.execute(select(Jam).where(Jam.ongoing == True)) - ).unique().scalars().one_or_none() + ongoing_jam = (await session.execute(select(Jam).where(Jam.ongoing == True))).unique().scalars().one_or_none() if not ongoing_jam: raise HTTPException(status_code=404, detail="There is no ongoing codejam.") - user_teams = ( - await session.execute(select(TeamUser).where(TeamUser.user_id == user_id)) - ).unique().scalars().all() + user_teams = (await session.execute(select(TeamUser).where(TeamUser.user_id == user_id))).unique().scalars().all() current_team = None for user_team in user_teams: @@ -135,9 +117,6 @@ async def get_current_team(user_id: int, session: AsyncSession = Depends(get_db_ break if not current_team: - raise HTTPException( - status_code=404, - detail="User with specified ID isn't participating in ongoing codejam." - ) + raise HTTPException(status_code=404, detail="User with specified ID isn't participating in ongoing codejam.") return current_team diff --git a/api/routers/winners.py b/api/routers/winners.py index 9375010..24ca0a6 100644 --- a/api/routers/winners.py +++ b/api/routers/winners.py @@ -14,11 +14,7 @@ @router.get( "/{jam_id}", response_model=list[WinnerResponse], - responses={ - 404: { - "description": "The specified codejam could not be found." - } - } + responses={404: {"description": "The specified codejam could not be found."}}, ) async def get_winners(jam_id: int, session: AsyncSession = Depends(get_db_session)) -> list[DbWinner]: """Get the top ten winners from the specified codejam.""" @@ -37,16 +33,12 @@ async def get_winners(jam_id: int, session: AsyncSession = Depends(get_db_sessio "/{jam_id}", response_model=list[WinnerResponse], responses={ - 400: { - "description": "The provided winners list is empty or contains duplicate users." - }, + 400: {"description": "The provided winners list is empty or contains duplicate users."}, 404: { "description": "The codejam or one of the users provided could not be found.", }, - 409: { - "description": "One or more users are already a winner in the specified codejam." - } - } + 409: {"description": "One or more users are already a winner in the specified codejam."}, + }, ) async def create_winners( jam_id: int, winners: list[Winner], session: AsyncSession = Depends(get_db_session) diff --git a/migrations/env.py b/migrations/env.py index 7d76428..598ef92 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -50,10 +50,7 @@ def run_migrations_offline() -> None: def do_run_migrations(connection: AsyncConnection): """Run all migrations on the given connection.""" context.configure( - connection=connection, - target_metadata=target_metadata, - compare_type=True, - compare_server_default=True + connection=connection, target_metadata=target_metadata, compare_type=True, compare_server_default=True ) with context.begin_transaction(): diff --git a/migrations/versions/103ccfde4460_create_tables.py b/migrations/versions/103ccfde4460_create_tables.py index 3c95374..ceafdbe 100644 --- a/migrations/versions/103ccfde4460_create_tables.py +++ b/migrations/versions/103ccfde4460_create_tables.py @@ -9,7 +9,7 @@ from alembic import op # revision identifiers, used by Alembic. -revision = '103ccfde4460' +revision = "103ccfde4460" down_revision = None branch_labels = None depends_on = None @@ -17,57 +17,82 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table('jams', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.Text(), nullable=False), - sa.PrimaryKeyConstraint('id') + op.create_table( + "jams", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("name", sa.Text(), nullable=False), + sa.PrimaryKeyConstraint("id"), ) - op.create_table('users', - sa.Column('id', sa.BigInteger(), autoincrement=False, nullable=False), - sa.PrimaryKeyConstraint('id') + op.create_table( + "users", sa.Column("id", sa.BigInteger(), autoincrement=False, nullable=False), sa.PrimaryKeyConstraint("id") ) - op.create_table('infractions', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('user_id', sa.BigInteger(), nullable=True), - sa.Column('jam_id', sa.Integer(), nullable=True), - sa.Column('infraction_type', sa.Enum('note', 'ban', 'warning', name='infraction_type'), nullable=False), - sa.Column('reason', sa.Text(), nullable=False), - sa.ForeignKeyConstraint(['jam_id'], ['jams.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id') + op.create_table( + "infractions", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("user_id", sa.BigInteger(), nullable=True), + sa.Column("jam_id", sa.Integer(), nullable=True), + sa.Column("infraction_type", sa.Enum("note", "ban", "warning", name="infraction_type"), nullable=False), + sa.Column("reason", sa.Text(), nullable=False), + sa.ForeignKeyConstraint( + ["jam_id"], + ["jams.id"], + ), + sa.ForeignKeyConstraint( + ["user_id"], + ["users.id"], + ), + sa.PrimaryKeyConstraint("id"), ) - op.create_table('teams', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('jam_id', sa.Integer(), nullable=False), - sa.Column('name', sa.Text(), nullable=False), - sa.ForeignKeyConstraint(['jam_id'], ['jams.id'], ), - sa.PrimaryKeyConstraint('id') + op.create_table( + "teams", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("jam_id", sa.Integer(), nullable=False), + sa.Column("name", sa.Text(), nullable=False), + sa.ForeignKeyConstraint( + ["jam_id"], + ["jams.id"], + ), + sa.PrimaryKeyConstraint("id"), ) - op.create_table('winners', - sa.Column('jam_id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.BigInteger(), nullable=False), - sa.Column('first_place', sa.Boolean(), nullable=False), - sa.ForeignKeyConstraint(['jam_id'], ['jams.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('jam_id', 'user_id') + op.create_table( + "winners", + sa.Column("jam_id", sa.Integer(), nullable=False), + sa.Column("user_id", sa.BigInteger(), nullable=False), + sa.Column("first_place", sa.Boolean(), nullable=False), + sa.ForeignKeyConstraint( + ["jam_id"], + ["jams.id"], + ), + sa.ForeignKeyConstraint( + ["user_id"], + ["users.id"], + ), + sa.PrimaryKeyConstraint("jam_id", "user_id"), ) - op.create_table('team_has_user', - sa.Column('team_id', sa.Integer(), nullable=False), - sa.Column('user_id', sa.BigInteger(), nullable=False), - sa.Column('is_leader', sa.Boolean(), nullable=False), - sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('team_id', 'user_id') + op.create_table( + "team_has_user", + sa.Column("team_id", sa.Integer(), nullable=False), + sa.Column("user_id", sa.BigInteger(), nullable=False), + sa.Column("is_leader", sa.Boolean(), nullable=False), + sa.ForeignKeyConstraint( + ["team_id"], + ["teams.id"], + ), + sa.ForeignKeyConstraint( + ["user_id"], + ["users.id"], + ), + sa.PrimaryKeyConstraint("team_id", "user_id"), ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('team_has_user') - op.drop_table('winners') - op.drop_table('teams') - op.drop_table('infractions') - op.drop_table('users') - op.drop_table('jams') + op.drop_table("team_has_user") + op.drop_table("winners") + op.drop_table("teams") + op.drop_table("infractions") + op.drop_table("users") + op.drop_table("jams") # ### end Alembic commands ### diff --git a/migrations/versions/3bb5cc4b5d48_add_unique_team_name_and_jam_constraint.py b/migrations/versions/3bb5cc4b5d48_add_unique_team_name_and_jam_constraint.py index a2fd131..9ed5db1 100644 --- a/migrations/versions/3bb5cc4b5d48_add_unique_team_name_and_jam_constraint.py +++ b/migrations/versions/3bb5cc4b5d48_add_unique_team_name_and_jam_constraint.py @@ -9,15 +9,15 @@ from alembic import op # revision identifiers, used by Alembic. -revision = '3bb5cc4b5d48' -down_revision = 'a2c25c740f2a' +revision = "3bb5cc4b5d48" +down_revision = "a2c25c740f2a" branch_labels = None depends_on = None def upgrade(): - op.create_index('team_name_jam_unique', 'teams', [sa.text('lower(name)'), 'jam_id'], unique=True) + op.create_index("team_name_jam_unique", "teams", [sa.text("lower(name)"), "jam_id"], unique=True) def downgrade(): - op.drop_index('team_name_jam_unique', 'teams') + op.drop_index("team_name_jam_unique", "teams") diff --git a/migrations/versions/89e175c77aea_add_jam_column.py b/migrations/versions/89e175c77aea_add_jam_column.py index 81874a2..d93df18 100644 --- a/migrations/versions/89e175c77aea_add_jam_column.py +++ b/migrations/versions/89e175c77aea_add_jam_column.py @@ -9,19 +9,19 @@ from alembic import op # revision identifiers, used by Alembic. -revision = '89e175c77aea' -down_revision = '103ccfde4460' +revision = "89e175c77aea" +down_revision = "103ccfde4460" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('jams', sa.Column('ongoing', sa.Boolean(), server_default='false', nullable=False)) + op.add_column("jams", sa.Column("ongoing", sa.Boolean(), server_default="false", nullable=False)) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('jams', 'ongoing') + op.drop_column("jams", "ongoing") # ### end Alembic commands ### diff --git a/migrations/versions/a2c25c740f2a_add_discord_identifiers_to_team.py b/migrations/versions/a2c25c740f2a_add_discord_identifiers_to_team.py index 506e71b..afd831a 100644 --- a/migrations/versions/a2c25c740f2a_add_discord_identifiers_to_team.py +++ b/migrations/versions/a2c25c740f2a_add_discord_identifiers_to_team.py @@ -9,21 +9,21 @@ from alembic import op # revision identifiers, used by Alembic. -revision = 'a2c25c740f2a' -down_revision = '89e175c77aea' +revision = "a2c25c740f2a" +down_revision = "89e175c77aea" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.add_column('teams', sa.Column('discord_role_id', sa.BigInteger(), nullable=True)) - op.add_column('teams', sa.Column('discord_channel_id', sa.BigInteger(), nullable=True)) + op.add_column("teams", sa.Column("discord_role_id", sa.BigInteger(), nullable=True)) + op.add_column("teams", sa.Column("discord_channel_id", sa.BigInteger(), nullable=True)) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('teams', 'discord_channel_id') - op.drop_column('teams', 'discord_role_id') + op.drop_column("teams", "discord_channel_id") + op.drop_column("teams", "discord_role_id") # ### end Alembic commands ### diff --git a/tests/conftest.py b/tests/conftest.py index 7fca83d..cc0d763 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -69,5 +69,5 @@ def app(override_db_session: Callable) -> FastAPI: @pytest.fixture() async def client(app: FastAPI) -> AsyncClient: """Return a client for testing the app.""" - async with AsyncClient(app=app, base_url='http://testserver', follow_redirects=True) as ac: + async with AsyncClient(app=app, base_url="http://testserver", follow_redirects=True) as ac: yield ac diff --git a/tests/routers/conftest.py b/tests/routers/conftest.py index eb39c4a..ae8e17a 100644 --- a/tests/routers/conftest.py +++ b/tests/routers/conftest.py @@ -29,35 +29,33 @@ async def delete_jam(jam: models.CodeJamResponse, session: AsyncSession) -> None def codejam() -> models.CodeJam: """Build a codejam for test purposes.""" return models.CodeJam( - name='Python Discord Test Jam 1 - Break your coverage!', + name="Python Discord Test Jam 1 - Break your coverage!", ongoing=True, teams=[ models.Team( - name='lemoncluster 1', + name="lemoncluster 1", users=[ models.User(user_id=1337, is_leader=True), models.User(user_id=109248, is_leader=False), ], discord_role_id=1, - discord_channel_id=1 + discord_channel_id=1, ), models.Team( - name='lemoncluster 2', + name="lemoncluster 2", users=[ models.User(user_id=298, is_leader=False), models.User(user_id=2180, is_leader=True), ], discord_role_id=2, - discord_channel_id=2 + discord_channel_id=2, ), - ] + ], ) @pytest.fixture -async def created_codejam( - client: AsyncClient, codejam: models.CodeJam, session: AsyncSession -) -> models.CodeJam: +async def created_codejam(client: AsyncClient, codejam: models.CodeJam, session: AsyncSession) -> models.CodeJam: """Create the codejam via the API and yield it.""" # Ensure no users are in the database. current_users = len((await session.execute(select(User))).unique().scalars().all()) @@ -66,7 +64,7 @@ async def created_codejam( # Create the codejam and parse it into the expected # response model. This also double-checks proper response # structure. - response = await client.post('/codejams', json=codejam.dict()) + response = await client.post("/codejams", json=codejam.dict()) assert response.status_code == 200, "Failed to create test codejam" created_jam = response.json() parsed = models.CodeJamResponse(**created_jam) @@ -75,10 +73,7 @@ async def created_codejam( @pytest.fixture async def created_infraction( - client: AsyncClient, - app: FastAPI, - session: AsyncSession, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, session: AsyncSession, created_codejam: models.CodeJamResponse ) -> models.InfractionResponse: """Create a test Infraction via the API and yield it.""" # Select one of the test users, so that we can issue an infraction to that user @@ -86,31 +81,30 @@ async def created_infraction( jam_id = created_codejam.id response = await client.post( app.url_path_for("create_infraction"), - json={"user_id": user_id, "jam_id": jam_id, "reason": "Too good to be true", "infraction_type": "warning"} + json={"user_id": user_id, "jam_id": jam_id, "reason": "Too good to be true", "infraction_type": "warning"}, ) parsed_infraction = models.InfractionResponse(**response.json()) assert response.status_code == 200 # Check whether the infraction was actually created, and insterted into the db assert ( - await (session.execute(select(Infraction).where(Infraction.id == parsed_infraction.id))) - ).unique().scalars().one_or_none(), "Failed to create Infraction" + (await (session.execute(select(Infraction).where(Infraction.id == parsed_infraction.id)))) + .unique() + .scalars() + .one_or_none() + ), "Failed to create Infraction" yield parsed_infraction @pytest.fixture async def created_winner( - client: AsyncClient, - app: FastAPI, - session: AsyncSession, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, session: AsyncSession, created_codejam: models.CodeJamResponse ) -> models.WinnerResponse: """Create a single test Winner via the API and yield it.""" # Select a test user, so that we can use it to create the winner user_id = created_codejam.teams[0].users[0].user_id jam_id = created_codejam.id response = await client.post( - app.url_path_for("create_winners", jam_id=jam_id), - json=[{"user_id": user_id, "first_place": True}] + app.url_path_for("create_winners", jam_id=jam_id), json=[{"user_id": user_id, "first_place": True}] ) assert response.status_code == 200 @@ -118,7 +112,10 @@ async def created_winner( parsed_winner = models.WinnerResponse(**raw_winner) assert ( - await session.execute(select(Winner).where(Winner.user_id == parsed_winner.user_id)) - ).unique().scalars().one_or_none(), "Failed to create Winner" + (await session.execute(select(Winner).where(Winner.user_id == parsed_winner.user_id))) + .unique() + .scalars() + .one_or_none() + ), "Failed to create Winner" yield parsed_winner diff --git a/tests/routers/test_codejams.py b/tests/routers/test_codejams.py index 1dd569d..d76b028 100644 --- a/tests/routers/test_codejams.py +++ b/tests/routers/test_codejams.py @@ -35,10 +35,7 @@ async def test_get_nonexistent_ongoing_code_jam(client: AsyncClient, app: FastAP assert response.status_code == 404 -async def test_modify_nonexistent_codejam( - client: AsyncClient, - app: FastAPI -) -> None: +async def test_modify_nonexistent_codejam(client: AsyncClient, app: FastAPI) -> None: """Setting the ongoing code jam to a nonexistent code jam should return a 404.""" response = await client.patch( app.url_path_for("modify_codejam", codejam_id=42392), json={"name": "Non-existent CodeJam", "ongoing": True} @@ -47,9 +44,7 @@ async def test_modify_nonexistent_codejam( async def test_get_existing_code_jam( - client: AsyncClient, - created_codejam: models.CodeJamResponse, - app: FastAPI + client: AsyncClient, created_codejam: models.CodeJamResponse, app: FastAPI ) -> None: """Getting an existing code jam should return 200.""" response = await client.get(app.url_path_for("get_codejam", codejam_id=created_codejam.id)) @@ -60,9 +55,7 @@ async def test_get_existing_code_jam( async def test_list_codejams_with_existing_jam( - client: AsyncClient, - created_codejam: models.CodeJamResponse, - app: FastAPI + client: AsyncClient, created_codejam: models.CodeJamResponse, app: FastAPI ) -> None: """Listing all code jams should return the created jam.""" response = await client.get(app.url_path_for("get_codejams")) @@ -78,11 +71,7 @@ async def test_list_codejams_with_existing_jam( assert jam == created_codejam -async def test_get_ongoing_codejam( - client: AsyncClient, - created_codejam: models.CodeJamResponse, - app: FastAPI -) -> None: +async def test_get_ongoing_codejam(client: AsyncClient, created_codejam: models.CodeJamResponse, app: FastAPI) -> None: """Getting a code jam with an ID that is -1 should return the ongoing code jam.""" response = await client.get(app.url_path_for("get_codejam", codejam_id=-1)) assert response.status_code == 200 @@ -99,38 +88,34 @@ async def test_create_codejams_rejects_invalid_data(client: AsyncClient, app: Fa async def test_create_codejams_accepts_valid_data_and_creates_user( - client: AsyncClient, - app: FastAPI, session: AsyncSession + client: AsyncClient, app: FastAPI, session: AsyncSession ) -> None: """Posting a valid JSON data should return 200 and the record should exist in the DB.""" - response = await client.post(app.url_path_for("create_codejam"), json={ - "name": "CodeJam Test", - "teams": [ - { - "name": "Dramatic Dragonflies", - "discord_channel_id": 1, - "discord_role_id": 1, - "users": [ - {"user_id": 1, "is_leader": True} - ] - } - ] - }) + response = await client.post( + app.url_path_for("create_codejam"), + json={ + "name": "CodeJam Test", + "teams": [ + { + "name": "Dramatic Dragonflies", + "discord_channel_id": 1, + "discord_role_id": 1, + "users": [{"user_id": 1, "is_leader": True}], + } + ], + }, + ) assert response.status_code == 200 # Checks whether the previously added user was actually inserted into the database. assert (await session.execute(select(User).where(User.id == 1))).scalars().unique().one_or_none() -async def test_modify_codejam( - client: AsyncClient, - app: FastAPI, - created_codejam: models.CodeJamResponse -) -> None: +async def test_modify_codejam(client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse) -> None: """Modifying an existing code jam should return 200.""" response = await client.patch( app.url_path_for("modify_codejam", codejam_id=created_codejam.id), - json={"name": "CodeJam Test", "ongoing": True} + json={"name": "CodeJam Test", "ongoing": True}, ) assert response.status_code == 200 raw = response.json() @@ -139,26 +124,17 @@ async def test_modify_codejam( async def test_set_ongoing_codejam_to_new_codejam( - client: AsyncClient, - app: FastAPI, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse ) -> None: """Modifying new code jam to be ongoing should return 200 and should remove the created_codejam as ongoing.""" response = await client.post( - app.url_path_for("create_codejam"), - json={ - "name": "CodeJam Test", - "teams": [], - "ongoing": False - } + app.url_path_for("create_codejam"), json={"name": "CodeJam Test", "teams": [], "ongoing": False} ) assert response.status_code == 200 new_codejam_id = response.json()["id"] - response = await client.patch( - app.url_path_for("modify_codejam", codejam_id=new_codejam_id), json={"ongoing": True} - ) + response = await client.patch(app.url_path_for("modify_codejam", codejam_id=new_codejam_id), json={"ongoing": True}) assert response.status_code == 200 diff --git a/tests/routers/test_infractions.py b/tests/routers/test_infractions.py index 42a9a65..8d249db 100644 --- a/tests/routers/test_infractions.py +++ b/tests/routers/test_infractions.py @@ -23,9 +23,7 @@ async def test_get_nonexsistent_infraction(client: AsyncClient, app: FastAPI) -> async def test_get_existent_infraction( - client: AsyncClient, - app: FastAPI, - created_infraction: models.InfractionResponse + client: AsyncClient, app: FastAPI, created_infraction: models.InfractionResponse ) -> None: """Getting an existing infraction should return 200.""" response = await client.get(app.url_path_for("get_infraction", infraction_id=created_infraction.id)) diff --git a/tests/routers/test_teams.py b/tests/routers/test_teams.py index 0b272df..23188c9 100644 --- a/tests/routers/test_teams.py +++ b/tests/routers/test_teams.py @@ -30,24 +30,18 @@ async def test_list_team_users_without_db_entries(client: AsyncClient, app: Fast async def test_add_user_to_nonexistent_team(client: AsyncClient, app: FastAPI) -> None: """Adding a user to a nonexistent team should return a 404.""" - response = await client.post( - app.url_path_for("add_user_to_team", team_id=123826, user_id=123124) - ) + response = await client.post(app.url_path_for("add_user_to_team", team_id=123826, user_id=123124)) assert response.status_code == 404 async def test_remove_user_from_nonexistent_team(client: AsyncClient, app: FastAPI) -> None: """Deleting a user from a nonexistent team should return a 404.""" - response = await client.delete( - app.url_path_for("remove_user_from_team", team_id=123826, user_id=123124) - ) + response = await client.delete(app.url_path_for("remove_user_from_team", team_id=123826, user_id=123124)) assert response.status_code == 404 async def test_get_team_with_existing_jam( - client: AsyncClient, - app: FastAPI, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse ) -> None: """Getting an existing infraction should return 200.""" team = created_codejam.teams[0] @@ -59,9 +53,7 @@ async def test_get_team_with_existing_jam( async def test_list_team_with_existing_jam( - client: AsyncClient, - app: FastAPI, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse ) -> None: """Getting an existing team should return 200.""" response = await client.get(app.url_path_for("get_teams")) @@ -82,7 +74,7 @@ async def test_add_user_to_team( response = await client.post( app.url_path_for("add_user_to_team", team_id=team_2.id, user_id=user.user_id), - params={"is_leader": user.is_leader} + params={"is_leader": user.is_leader}, ) assert response.status_code == 200 @@ -101,9 +93,7 @@ async def test_remove_user_from_team( team = created_codejam.teams[0] user = team.users[0] - response = await client.delete( - app.url_path_for("remove_user_from_team", team_id=team.id, user_id=user.user_id) - ) + response = await client.delete(app.url_path_for("remove_user_from_team", team_id=team.id, user_id=user.user_id)) assert response.status_code == 204 @@ -127,7 +117,7 @@ async def test_add_existing_team_user( response = await client.post( app.url_path_for("add_user_to_team", team_id=team.id, user_id=user.user_id), - params={"is_leader": user.is_leader} + params={"is_leader": user.is_leader}, ) assert response.status_code == 400 @@ -142,38 +132,25 @@ async def test_remove_nonexisting_team_user( team = created_codejam.teams[0] user = created_codejam.teams[1].users[0] - response = await client.delete( - app.url_path_for("remove_user_from_team", team_id=team.id, user_id=user.user_id) - ) + response = await client.delete(app.url_path_for("remove_user_from_team", team_id=team.id, user_id=user.user_id)) assert response.status_code == 400 -async def test_find_nonexisting_team( - client: AsyncClient, - app: FastAPI -) -> None: +async def test_find_nonexisting_team(client: AsyncClient, app: FastAPI) -> None: """Getting a non-existing team by name should return 404.""" - response = await client.get( - app.url_path_for("find_team_by_name"), - params={"name": "team that should never exist"} - ) + response = await client.get(app.url_path_for("find_team_by_name"), params={"name": "team that should never exist"}) assert response.status_code == 404 async def test_find_existing_team_case_insensitive_current_jam( - client: AsyncClient, - app: FastAPI, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse ) -> None: """Getting an existing team (current jam) should return 200 and be case-insensitive.""" team = created_codejam.teams[0] - response = await client.get( - app.url_path_for("find_team_by_name"), - params={"name": team.name.upper()} - ) + response = await client.get(app.url_path_for("find_team_by_name"), params={"name": team.name.upper()}) assert response.status_code == 200 parsed = models.TeamResponse(**response.json()) @@ -181,29 +158,23 @@ async def test_find_existing_team_case_insensitive_current_jam( async def test_find_team_by_name_wrong_jam( - client: AsyncClient, - app: FastAPI, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse ) -> None: """Getting an existing team from wrong code jam should return 404.""" response = await client.get( - app.url_path_for("find_team_by_name"), - params={"name": created_codejam.teams[0].name.upper(), "jam_id": 9999} + app.url_path_for("find_team_by_name"), params={"name": created_codejam.teams[0].name.upper(), "jam_id": 9999} ) assert response.status_code == 404 async def test_find_team_by_name_using_specific_jam( - client: AsyncClient, - app: FastAPI, - created_codejam: models.CodeJamResponse + client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse ) -> None: """Getting an existing team using right jam ID should return 200 and be case-insensitive.""" team = created_codejam.teams[0] response = await client.get( - app.url_path_for("find_team_by_name"), - params={"name": team.name.upper(), "jam_id": created_codejam.id} + app.url_path_for("find_team_by_name"), params={"name": team.name.upper(), "jam_id": created_codejam.id} ) assert response.status_code == 200 diff --git a/tests/routers/test_users.py b/tests/routers/test_users.py index 31dbcb6..2f4cb7f 100644 --- a/tests/routers/test_users.py +++ b/tests/routers/test_users.py @@ -24,9 +24,7 @@ async def test_get_nonexistent_user(client: AsyncClient, app: FastAPI) -> None: async def test_list_users_with_existing_jam( - client: AsyncClient, - created_codejam: models.CodeJamResponse, - app: FastAPI + client: AsyncClient, created_codejam: models.CodeJamResponse, app: FastAPI ) -> None: """Listing users with an existing jam should display the users in the jam.""" response = await client.get(app.url_path_for("get_users")) @@ -58,9 +56,7 @@ async def test_create_user_without_db_entries(client: AsyncClient, app: FastAPI) async def test_create_user_existing_user( - client: AsyncClient, - created_codejam: models.CodeJamResponse, - app: FastAPI + client: AsyncClient, created_codejam: models.CodeJamResponse, app: FastAPI ) -> None: """Creating a user with an existing user should return a 400.""" user = created_codejam.teams[0].users[0] @@ -69,10 +65,7 @@ async def test_create_user_existing_user( assert response.status_code == 400 -async def test_get_current_team_no_ongoing_jam( - client: AsyncClient, - app: FastAPI -) -> None: +async def test_get_current_team_no_ongoing_jam(client: AsyncClient, app: FastAPI) -> None: """Getting current team without ongoing jam should return code 404.""" await client.post(app.url_path_for("create_user", user_id=1234)) @@ -80,19 +73,14 @@ async def test_get_current_team_no_ongoing_jam( assert response.status_code == 404 -async def test_get_current_team_user_not_found( - client: AsyncClient, - app: FastAPI -) -> None: +async def test_get_current_team_user_not_found(client: AsyncClient, app: FastAPI) -> None: """Getting current team with unknown user ID should return code 404.""" response = await client.get(app.url_path_for("get_current_team", user_id=1234)) assert response.status_code == 404 async def test_get_current_team_user_not_participating( - client: AsyncClient, - created_codejam: models.CodeJamResponse, - app: FastAPI + client: AsyncClient, created_codejam: models.CodeJamResponse, app: FastAPI ) -> None: """Getting current team when user not participating in ongoing jam should return code 404.""" team = created_codejam.teams[0] @@ -102,18 +90,14 @@ async def test_get_current_team_user_not_participating( response = await client.get(app.url_path_for("get_current_team", user_id=user.user_id)) assert response.status_code == 200 - await client.delete( - app.url_path_for("remove_user_from_team", team_id=team.id, user_id=user.user_id) - ) + await client.delete(app.url_path_for("remove_user_from_team", team_id=team.id, user_id=user.user_id)) response = await client.get(app.url_path_for("get_current_team", user_id=user.user_id)) assert response.status_code == 404 async def test_get_current_team_with_participating_user( - client: AsyncClient, - created_codejam: models.CodeJamResponse, - app: FastAPI + client: AsyncClient, created_codejam: models.CodeJamResponse, app: FastAPI ) -> None: """Getting current team of participating user should return code 200.""" team = created_codejam.teams[0] diff --git a/tests/routers/test_winners.py b/tests/routers/test_winners.py index 517db03..8c92993 100644 --- a/tests/routers/test_winners.py +++ b/tests/routers/test_winners.py @@ -52,14 +52,9 @@ async def test_create_winners_with_duplicates( client: AsyncClient, app: FastAPI, created_codejam: models.CodeJamResponse ) -> None: """Adding duplicate winners should return a 400.""" - winner = { - "user_id": created_codejam.teams[0].users[0].user_id, - "first_place": False - } + winner = {"user_id": created_codejam.teams[0].users[0].user_id, "first_place": False} - response = await client.post( - app.url_path_for("create_winners", jam_id=created_codejam.id), json=[winner, winner] - ) + response = await client.post(app.url_path_for("create_winners", jam_id=created_codejam.id), json=[winner, winner]) assert response.status_code == 400 @@ -69,8 +64,6 @@ async def test_create_winners_with_existing_winner( ) -> None: """Adding a winner that already exists in the jam should return a 409.""" response = await client.post( - app.url_path_for("create_winners", jam_id=created_winner.jam_id), json=[ - created_winner.dict(exclude={"jam_id"}) - ] + app.url_path_for("create_winners", jam_id=created_winner.jam_id), json=[created_winner.dict(exclude={"jam_id"})] ) assert response.status_code == 409 diff --git a/tests/test_token_auth.py b/tests/test_token_auth.py index c0a76d9..d6ba353 100644 --- a/tests/test_token_auth.py +++ b/tests/test_token_auth.py @@ -43,7 +43,7 @@ def mock_settings(monkeypatch: MonkeyPatch) -> None: async def test_authenticates_with_valid_token( - auth_middleware: TokenAuthentication, + auth_middleware: TokenAuthentication, ) -> None: """Test authentication with a valid token.""" request = create_request("/", API_TOKEN) @@ -56,7 +56,7 @@ async def test_authenticates_with_valid_token( async def test_authentication_fails_without_auth_header( - auth_middleware: TokenAuthentication, + auth_middleware: TokenAuthentication, ) -> None: """Test authentication without providing a Authentication header.""" request = create_request("/", None) @@ -68,8 +68,8 @@ async def test_authentication_fails_without_auth_header( @given(text()) async def test_authentication_fails_with_incorrect_token( - auth_middleware: TokenAuthentication, - invalid_token: str, + auth_middleware: TokenAuthentication, + invalid_token: str, ) -> None: """Test authentication with an invalid token.""" assume(invalid_token != API_TOKEN) @@ -82,8 +82,8 @@ async def test_authentication_fails_with_incorrect_token( async def test_debug_unauthenticated_access( - auth_middleware: TokenAuthentication, - monkeypatch: MonkeyPatch, + auth_middleware: TokenAuthentication, + monkeypatch: MonkeyPatch, ) -> None: """Test unauthenticated access to some endpoints in DEBUG mode.""" monkeypatch.setattr(Config, "DEBUG", True)