refactor: Split team routes
The team routes have been split into separate blueprints for better modularity and maintainability. The team invite and team integration routes are now handled by their respective blueprints.master
parent
36591726b9
commit
3394f2271e
|
@ -1,27 +1,25 @@
|
|||
from datetime import UTC, datetime, timedelta, timezone
|
||||
from random import randint, random
|
||||
import sys
|
||||
import time
|
||||
from typing import List, cast
|
||||
from flask import Blueprint, abort, jsonify, make_response, request
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import cast
|
||||
from flask import Blueprint, abort, make_response
|
||||
from pydantic.v1 import validator
|
||||
from spectree import Response
|
||||
from sqlalchemy.orm import joinedload, subqueryload
|
||||
from sqlalchemy.orm import joinedload
|
||||
from app_db import db
|
||||
from models.player import Player, PlayerSchema
|
||||
from models.player_team import PlayerTeam
|
||||
from models.player_team_availability import PlayerTeamAvailability
|
||||
from models.player_team_role import PlayerTeamRole, RoleSchema
|
||||
from models.team import Team, TeamSchema
|
||||
from models.team_invite import TeamInvite, TeamInviteSchema
|
||||
from models.team_integration import AbstractTeamIntegrationSchema, TeamDiscordIntegration, TeamDiscordIntegrationSchema, TeamIntegration, TeamIntegrationSchema
|
||||
from middleware import assert_team_authority, requires_authentication, requires_team_membership
|
||||
import models
|
||||
from middleware import requires_authentication
|
||||
from spec import spec, BaseModel
|
||||
from team_invite import api_team_invite
|
||||
from team_integration import api_team_integration
|
||||
import pytz
|
||||
|
||||
|
||||
api_team = Blueprint("team", __name__, url_prefix="/team")
|
||||
api_team.register_blueprint(api_team_invite)
|
||||
api_team.register_blueprint(api_team_integration)
|
||||
|
||||
def map_player_to_schema(player: Player):
|
||||
return PlayerSchema(
|
||||
|
@ -419,280 +417,3 @@ def edit_member_roles(
|
|||
db.session.commit()
|
||||
|
||||
return make_response({ }, 204)
|
||||
|
||||
@api_team.get("/id/<team_id>/invite")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=list[TeamInviteSchema],
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="get_invites"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def get_invites(team_id: int, **_):
|
||||
invites = db.session.query(
|
||||
TeamInvite
|
||||
).where(
|
||||
TeamInvite.team_id == team_id
|
||||
).all()
|
||||
|
||||
def map_invite_to_schema(invite: TeamInvite):
|
||||
return TeamInviteSchema(
|
||||
key=invite.key,
|
||||
team_id=invite.team_id,
|
||||
created_at=invite.created_at,
|
||||
).dict(by_alias=True)
|
||||
|
||||
return list(map(map_invite_to_schema, invites)), 200
|
||||
|
||||
@api_team.post("/id/<team_id>/invite")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=TeamInviteSchema,
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="create_invite"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def create_invite(team_id: int, **_):
|
||||
team_id_shifted = int(team_id) << 48
|
||||
random_value_shifted = int(randint(0, (1 << 16) - 1)) << 32
|
||||
timestamp = int(time.time()) & ((1 << 32) - 1)
|
||||
|
||||
key_int = timestamp | team_id_shifted | random_value_shifted
|
||||
key_hex = "%0.16X" % key_int
|
||||
|
||||
invite = TeamInvite()
|
||||
invite.team_id = team_id
|
||||
invite.key = key_hex
|
||||
|
||||
db.session.add(invite)
|
||||
db.session.flush()
|
||||
db.session.refresh(invite)
|
||||
|
||||
response = TeamInviteSchema(
|
||||
key=key_hex,
|
||||
team_id=team_id,
|
||||
created_at=invite.created_at
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return response.dict(by_alias=True), 200
|
||||
|
||||
@api_team.post("/id/<team_id>/consume-invite/<key>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_204=None,
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="consume_invite"
|
||||
)
|
||||
@requires_authentication
|
||||
def consume_invite(player: Player, team_id: int, key: str, **kwargs):
|
||||
invite = db.session.query(
|
||||
TeamInvite
|
||||
).where(
|
||||
TeamInvite.team_id == team_id
|
||||
).where(
|
||||
TeamInvite.key == key
|
||||
).one_or_none()
|
||||
|
||||
if not invite:
|
||||
abort(404)
|
||||
|
||||
player_team = db.session.query(
|
||||
PlayerTeam
|
||||
).where(
|
||||
PlayerTeam.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeam.team_id == team_id
|
||||
).one_or_none()
|
||||
|
||||
if player_team:
|
||||
abort(409)
|
||||
|
||||
player_team = PlayerTeam()
|
||||
player_team.player = player
|
||||
player_team.team_id = team_id
|
||||
|
||||
db.session.add(player_team)
|
||||
|
||||
if invite.delete_on_use:
|
||||
db.session.delete(invite)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return make_response({ }, 204)
|
||||
|
||||
@api_team.delete("/id/<team_id>/invite/<key>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_204=None,
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="revoke_invite"
|
||||
)
|
||||
@requires_authentication
|
||||
def revoke_invite(player: Player, team_id: int, key: str, **kwargs):
|
||||
player_team = db.session.query(
|
||||
PlayerTeam
|
||||
).where(
|
||||
PlayerTeam.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeam.team_id == team_id
|
||||
).one_or_none()
|
||||
|
||||
if not player_team:
|
||||
abort(404)
|
||||
|
||||
invite = db.session.query(
|
||||
TeamInvite
|
||||
).where(
|
||||
TeamInvite.team_id == team_id
|
||||
).where(
|
||||
TeamInvite.key == key
|
||||
).one_or_none()
|
||||
|
||||
if not invite:
|
||||
abort(404)
|
||||
|
||||
db.session.delete(invite)
|
||||
db.session.commit()
|
||||
return make_response({ }, 204)
|
||||
|
||||
@api_team.get("/id/<team_id>/integrations")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=list[TeamIntegrationSchema],
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="get_integrations"
|
||||
)
|
||||
@requires_authentication
|
||||
def get_integrations(player: Player, team_id: int, **kwargs):
|
||||
player_team = db.session.query(
|
||||
PlayerTeam
|
||||
).where(
|
||||
PlayerTeam.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeam.team_id == team_id
|
||||
).one_or_none()
|
||||
|
||||
if not player_team:
|
||||
abort(404)
|
||||
|
||||
integrations = db.session.query(
|
||||
TeamIntegration
|
||||
).where(
|
||||
TeamIntegration.team_id == team_id
|
||||
).all()
|
||||
|
||||
def map_integration_to_schema(integration: TeamIntegration):
|
||||
return TeamIntegrationSchema.from_model(
|
||||
integration
|
||||
).dict(by_alias=True)
|
||||
|
||||
return list(map(map_integration_to_schema, integrations))
|
||||
|
||||
@api_team.post("/id/<team_id>/integrations/<integration_type>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=TeamIntegrationSchema,
|
||||
),
|
||||
operation_id="create_integration"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def create_integration(player_team: PlayerTeam, integration_type: str, **_):
|
||||
assert_team_authority(player_team)
|
||||
|
||||
if integration_type == "discord":
|
||||
integration = TeamDiscordIntegration()
|
||||
integration.team_id = player_team.team_id
|
||||
integration.webhook_url = ""
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
db.session.add(integration)
|
||||
db.session.commit()
|
||||
|
||||
return TeamIntegrationSchema.from_model(
|
||||
integration
|
||||
).dict(by_alias=True), 200
|
||||
|
||||
@api_team.delete("/id/<team_id>/integrations/<integration_id>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_204=None,
|
||||
),
|
||||
operation_id="delete_integration"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def delete_integration(player_team: PlayerTeam, integration_id: int, **_):
|
||||
assert_team_authority(player_team)
|
||||
|
||||
integration = db.session.query(
|
||||
TeamIntegration
|
||||
).where(
|
||||
TeamIntegration.team_id == player_team.team_id
|
||||
).where(
|
||||
TeamIntegration.id == integration_id
|
||||
).one_or_none()
|
||||
|
||||
if not integration:
|
||||
abort(404)
|
||||
|
||||
db.session.delete(integration)
|
||||
db.session.commit()
|
||||
|
||||
return make_response({ }, 204)
|
||||
|
||||
@api_team.patch("/id/<team_id>/integrations/<integration_id>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=TeamIntegrationSchema,
|
||||
),
|
||||
operation_id="update_integration"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def update_integration(
|
||||
player_team: PlayerTeam,
|
||||
integration_id: int,
|
||||
json: AbstractTeamIntegrationSchema,
|
||||
**_
|
||||
):
|
||||
assert_team_authority(player_team)
|
||||
|
||||
integration = db.session.query(
|
||||
TeamIntegration
|
||||
).where(
|
||||
TeamIntegration.team_id == player_team.team_id
|
||||
).where(
|
||||
TeamIntegration.id == integration_id
|
||||
).one_or_none()
|
||||
|
||||
if not integration:
|
||||
abort(404)
|
||||
|
||||
if isinstance(integration, TeamDiscordIntegration):
|
||||
print(json.dict(), file=sys.stderr)
|
||||
if json.__root__.integration_type == "team_discord_integrations":
|
||||
discord_integration = cast(TeamDiscordIntegration, json.__root__)
|
||||
integration.webhook_url = discord_integration.webhook_url
|
||||
#if isinstance(json, TeamDiscordIntegrationSchema):
|
||||
# integration.webhook_url = json.webhook_url
|
||||
else:
|
||||
abort(400)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return TeamIntegrationSchema.from_model(
|
||||
integration
|
||||
).dict(by_alias=True), 200
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
from flask import Blueprint, abort, make_response
|
||||
from spectree import Response
|
||||
from typing import cast
|
||||
|
||||
|
||||
from app_db import db
|
||||
from middleware import assert_team_authority, requires_authentication, requires_team_membership
|
||||
from models.player import Player
|
||||
from models.player_team import PlayerTeam
|
||||
from models.team_integration import AbstractTeamIntegrationSchema, TeamDiscordIntegration, TeamIntegration, TeamIntegrationSchema
|
||||
from spec import spec
|
||||
|
||||
|
||||
api_team_integration = Blueprint("team_integration", __name__)
|
||||
|
||||
@api_team_integration.get("/id/<team_id>/integrations")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=list[TeamIntegrationSchema],
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="get_integrations"
|
||||
)
|
||||
@requires_authentication
|
||||
def get_integrations(player: Player, team_id: int, **_):
|
||||
player_team = db.session.query(
|
||||
PlayerTeam
|
||||
).where(
|
||||
PlayerTeam.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeam.team_id == team_id
|
||||
).one_or_none()
|
||||
|
||||
if not player_team:
|
||||
abort(404)
|
||||
|
||||
integrations = db.session.query(
|
||||
TeamIntegration
|
||||
).where(
|
||||
TeamIntegration.team_id == team_id
|
||||
).all()
|
||||
|
||||
def map_integration_to_schema(integration: TeamIntegration):
|
||||
return TeamIntegrationSchema.from_model(
|
||||
integration
|
||||
).dict(by_alias=True)
|
||||
|
||||
return list(map(map_integration_to_schema, integrations))
|
||||
|
||||
@api_team_integration.post("/id/<team_id>/integrations/<integration_type>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=TeamIntegrationSchema,
|
||||
),
|
||||
operation_id="create_integration"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def create_integration(player_team: PlayerTeam, integration_type: str, **_):
|
||||
assert_team_authority(player_team)
|
||||
|
||||
if integration_type == "discord":
|
||||
integration = TeamDiscordIntegration()
|
||||
integration.team_id = player_team.team_id
|
||||
integration.webhook_url = ""
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
db.session.add(integration)
|
||||
db.session.commit()
|
||||
|
||||
return TeamIntegrationSchema.from_model(
|
||||
integration
|
||||
).dict(by_alias=True), 200
|
||||
|
||||
@api_team_integration.delete("/id/<team_id>/integrations/<integration_id>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_204=None,
|
||||
),
|
||||
operation_id="delete_integration"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def delete_integration(player_team: PlayerTeam, integration_id: int, **_):
|
||||
assert_team_authority(player_team)
|
||||
|
||||
integration = db.session.query(
|
||||
TeamIntegration
|
||||
).where(
|
||||
TeamIntegration.team_id == player_team.team_id
|
||||
).where(
|
||||
TeamIntegration.id == integration_id
|
||||
).one_or_none()
|
||||
|
||||
if not integration:
|
||||
abort(404)
|
||||
|
||||
db.session.delete(integration)
|
||||
db.session.commit()
|
||||
|
||||
return make_response({ }, 204)
|
||||
|
||||
@api_team_integration.patch("/id/<team_id>/integrations/<integration_id>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=TeamIntegrationSchema,
|
||||
),
|
||||
operation_id="update_integration"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def update_integration(
|
||||
player_team: PlayerTeam,
|
||||
integration_id: int,
|
||||
json: AbstractTeamIntegrationSchema,
|
||||
**_
|
||||
):
|
||||
assert_team_authority(player_team)
|
||||
|
||||
integration = db.session.query(
|
||||
TeamIntegration
|
||||
).where(
|
||||
TeamIntegration.team_id == player_team.team_id
|
||||
).where(
|
||||
TeamIntegration.id == integration_id
|
||||
).one_or_none()
|
||||
|
||||
if not integration:
|
||||
abort(404)
|
||||
|
||||
if isinstance(integration, TeamDiscordIntegration):
|
||||
if json.__root__.integration_type == "team_discord_integrations":
|
||||
discord_integration = cast(TeamDiscordIntegration, json.__root__)
|
||||
integration.webhook_url = discord_integration.webhook_url
|
||||
else:
|
||||
abort(400)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return TeamIntegrationSchema.from_model(
|
||||
integration
|
||||
).dict(by_alias=True), 200
|
|
@ -0,0 +1,158 @@
|
|||
from random import randint
|
||||
from flask import Blueprint, abort, make_response
|
||||
from spectree import Response
|
||||
import time
|
||||
|
||||
from app_db import db
|
||||
from middleware import requires_authentication, requires_team_membership
|
||||
from models.player import Player
|
||||
from models.player_team import PlayerTeam
|
||||
from models.team_invite import TeamInvite, TeamInviteSchema
|
||||
from spec import spec
|
||||
|
||||
|
||||
api_team_invite = Blueprint("team_invite", __name__)
|
||||
|
||||
@api_team_invite.get("/id/<team_id>/invite")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=list[TeamInviteSchema],
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="get_invites"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def get_invites(team_id: int, **_):
|
||||
invites = db.session.query(
|
||||
TeamInvite
|
||||
).where(
|
||||
TeamInvite.team_id == team_id
|
||||
).all()
|
||||
|
||||
def map_invite_to_schema(invite: TeamInvite):
|
||||
return TeamInviteSchema(
|
||||
key=invite.key,
|
||||
team_id=invite.team_id,
|
||||
created_at=invite.created_at,
|
||||
).dict(by_alias=True)
|
||||
|
||||
return list(map(map_invite_to_schema, invites)), 200
|
||||
|
||||
@api_team_invite.post("/id/<team_id>/invite")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_200=TeamInviteSchema,
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="create_invite"
|
||||
)
|
||||
@requires_authentication
|
||||
@requires_team_membership
|
||||
def create_invite(team_id: int, **_):
|
||||
team_id_shifted = int(team_id) << 48
|
||||
random_value_shifted = int(randint(0, (1 << 16) - 1)) << 32
|
||||
timestamp = int(time.time()) & ((1 << 32) - 1)
|
||||
|
||||
key_int = timestamp | team_id_shifted | random_value_shifted
|
||||
key_hex = "%0.16X" % key_int
|
||||
|
||||
invite = TeamInvite()
|
||||
invite.team_id = team_id
|
||||
invite.key = key_hex
|
||||
|
||||
db.session.add(invite)
|
||||
db.session.flush()
|
||||
db.session.refresh(invite)
|
||||
|
||||
response = TeamInviteSchema(
|
||||
key=key_hex,
|
||||
team_id=team_id,
|
||||
created_at=invite.created_at
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return response.dict(by_alias=True), 200
|
||||
|
||||
@api_team_invite.post("/id/<team_id>/consume-invite/<key>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_204=None,
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="consume_invite"
|
||||
)
|
||||
@requires_authentication
|
||||
def consume_invite(player: Player, team_id: int, key: str, **_):
|
||||
invite = db.session.query(
|
||||
TeamInvite
|
||||
).where(
|
||||
TeamInvite.team_id == team_id
|
||||
).where(
|
||||
TeamInvite.key == key
|
||||
).one_or_none()
|
||||
|
||||
if not invite:
|
||||
abort(404)
|
||||
|
||||
player_team = db.session.query(
|
||||
PlayerTeam
|
||||
).where(
|
||||
PlayerTeam.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeam.team_id == team_id
|
||||
).one_or_none()
|
||||
|
||||
if player_team:
|
||||
abort(409)
|
||||
|
||||
player_team = PlayerTeam()
|
||||
player_team.player = player
|
||||
player_team.team_id = team_id
|
||||
|
||||
db.session.add(player_team)
|
||||
|
||||
if invite.delete_on_use:
|
||||
db.session.delete(invite)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return make_response({ }, 204)
|
||||
|
||||
@api_team_invite.delete("/id/<team_id>/invite/<key>")
|
||||
@spec.validate(
|
||||
resp=Response(
|
||||
HTTP_204=None,
|
||||
HTTP_404=None,
|
||||
),
|
||||
operation_id="revoke_invite"
|
||||
)
|
||||
@requires_authentication
|
||||
def revoke_invite(player: Player, team_id: int, key: str, **_):
|
||||
player_team = db.session.query(
|
||||
PlayerTeam
|
||||
).where(
|
||||
PlayerTeam.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeam.team_id == team_id
|
||||
).one_or_none()
|
||||
|
||||
if not player_team:
|
||||
abort(404)
|
||||
|
||||
invite = db.session.query(
|
||||
TeamInvite
|
||||
).where(
|
||||
TeamInvite.team_id == team_id
|
||||
).where(
|
||||
TeamInvite.key == key
|
||||
).one_or_none()
|
||||
|
||||
if not invite:
|
||||
abort(404)
|
||||
|
||||
db.session.delete(invite)
|
||||
db.session.commit()
|
||||
return make_response({ }, 204)
|
||||
|
Loading…
Reference in New Issue