Add team integration endpoints
- Add new endpoints for managing team integrations: - GET /id/<team_id>/integrations - POST /id/<team_id>/integrations/<integration_type> - DELETE /id/<team_id>/integrations/<integration_id> - PATCH /id/<team_id>/integrations/<integration_id> - Introduce schemas for TeamIntegration and TeamDiscordIntegration - Update models to include nullable webhook_urlmaster
							parent
							
								
									3cb9084a69
								
							
						
					
					
						commit
						8a00c53479
					
				| 
						 | 
				
			
			@ -1,8 +1,10 @@
 | 
			
		|||
#from typing import cast, override
 | 
			
		||||
from sqlalchemy.orm import mapped_column, relationship
 | 
			
		||||
from sqlalchemy.orm.attributes import Mapped
 | 
			
		||||
from sqlalchemy.orm.properties import ForeignKey
 | 
			
		||||
from sqlalchemy.types import Integer, String
 | 
			
		||||
import app_db
 | 
			
		||||
import spec
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TeamIntegration(app_db.BaseModel):
 | 
			
		||||
| 
						 | 
				
			
			@ -23,10 +25,35 @@ class TeamDiscordIntegration(TeamIntegration):
 | 
			
		|||
    __tablename__ = "team_discord_integrations"
 | 
			
		||||
 | 
			
		||||
    integration_id: Mapped[int] = mapped_column(ForeignKey("team_integrations.id"), primary_key=True)
 | 
			
		||||
    webhook_url: Mapped[str] = mapped_column(String(255))
 | 
			
		||||
    webhook_url: Mapped[str] = mapped_column(String(255), nullable=True)
 | 
			
		||||
 | 
			
		||||
    __mapper_args__ = {
 | 
			
		||||
        "polymorphic_identity": "team_discord_integrations",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
class TeamIntegrationSchema(spec.BaseModel):
 | 
			
		||||
    id: int
 | 
			
		||||
    team_id: int
 | 
			
		||||
    integration_type: str
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_model(cls, model: TeamIntegration):
 | 
			
		||||
        if model.integration_type == "team_discord_integrations":
 | 
			
		||||
            if isinstance(model, TeamDiscordIntegration):
 | 
			
		||||
                return TeamDiscordIntegrationSchema._from_model_discord(model)
 | 
			
		||||
        raise TypeError()
 | 
			
		||||
 | 
			
		||||
class TeamDiscordIntegrationSchema(TeamIntegrationSchema):
 | 
			
		||||
    webhook_url: str
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def _from_model_discord(cls, model: TeamDiscordIntegration):
 | 
			
		||||
        assert model.integration_id != None
 | 
			
		||||
        return cls(
 | 
			
		||||
            id=model.integration_id,
 | 
			
		||||
            team_id=model.team_id,
 | 
			
		||||
            integration_type=model.integration_type,
 | 
			
		||||
            webhook_url=model.webhook_url
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
from models.team import Team
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ 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 TeamDiscordIntegration, TeamDiscordIntegrationSchema, TeamIntegration, TeamIntegrationSchema
 | 
			
		||||
from middleware import assert_team_authority, requires_authentication, requires_team_membership
 | 
			
		||||
import models
 | 
			
		||||
from spec import spec, BaseModel
 | 
			
		||||
| 
						 | 
				
			
			@ -561,3 +562,129 @@ def revoke_invite(player: Player, team_id: int, key: str, **kwargs):
 | 
			
		|||
    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"
 | 
			
		||||
)
 | 
			
		||||
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"
 | 
			
		||||
)
 | 
			
		||||
def update_integration(
 | 
			
		||||
    player_team: PlayerTeam,
 | 
			
		||||
    integration_id: int,
 | 
			
		||||
    json: TeamIntegrationSchema,
 | 
			
		||||
    **_
 | 
			
		||||
):
 | 
			
		||||
    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 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue