# Copyright (c) 2026 bdperkin
# SPDX-License-Identifier: MIT
"""Deletion functions and raw handlers for schedule resources."""
from __future__ import annotations
import json
from http import HTTPStatus
from typing import TYPE_CHECKING, Any
from gamesheet_sdk.common.auth.constants import DEFAULT_TIMEOUT_S
from gamesheet_sdk.common.exceptions import AuthenticationError, GameSheetError
from gamesheet_sdk.teams.schedule.models import ScheduleDeleteResult
from gamesheet_sdk.teams.shared.constants import (
TEAMS_API_GATEWAY,
TEAMS_CALENDAR_EVENTS_PATH,
TEAMS_CALENDAR_OCCURRENCES_PATH,
TEAMS_SCHEDULE_GAME_PATH,
)
if TYPE_CHECKING:
from gamesheet_sdk.common.auth.session import BaseAuthenticatedSession
[docs]
def delete_schedule_game_raw(
session: BaseAuthenticatedSession,
game_id: str | int,
*,
timeout: float = DEFAULT_TIMEOUT_S,
) -> dict[str, Any]:
"""Execute raw HTTP DELETE request to delete a scheduled game via DELETE /api/schedule-game/{game_id}.
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
game_id (str | int): ID of the scheduled game to delete.
timeout (float): Request timeout in seconds.
Returns:
dict[str, Any]: Parsed JSON response from the API.
Raises:
AuthenticationError: If the user is not authenticated (401).
GameSheetError: If the server returns an error or malformed response.
"""
path = f"{TEAMS_SCHEDULE_GAME_PATH}/{game_id}"
url = f"{TEAMS_API_GATEWAY}{path}"
resp = session.delete(url, timeout=timeout)
if resp.status_code == HTTPStatus.UNAUTHORIZED:
msg = "Authentication required: token is invalid or expired. Run `gamesheet-teams login`."
raise AuthenticationError(msg)
if resp.status_code >= HTTPStatus.BAD_REQUEST:
msg = f"DELETE {path} returned HTTP {resp.status_code}: {resp.text}"
raise GameSheetError(msg)
try:
data = resp.json()
except (ValueError, json.JSONDecodeError) as exc:
msg = f"Failed to parse delete game JSON response: {exc}"
raise GameSheetError(msg) from exc
if not isinstance(data, dict):
msg = "Unexpected response format from schedule-game API: expected a JSON object."
raise GameSheetError(msg)
return data
[docs]
def delete_game(
session: BaseAuthenticatedSession,
game_id: str | int,
*,
timeout: float = DEFAULT_TIMEOUT_S,
) -> ScheduleDeleteResult:
"""Delete a scheduled game.
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
game_id (str | int): Identifier of the scheduled game.
timeout (float): Request timeout in seconds.
Returns:
ScheduleDeleteResult: Result of deletion containing success flag and message.
"""
raw = delete_schedule_game_raw(session, game_id, timeout=timeout)
msg = str(raw.get("message") or "Game deleted successfully")
return ScheduleDeleteResult(success=True, message=msg, id=game_id)
[docs]
def delete_calendar_event_raw(
session: BaseAuthenticatedSession,
event_id: str,
*,
timeout: float = DEFAULT_TIMEOUT_S,
) -> dict[str, Any]:
"""Execute raw HTTP DELETE request to delete a calendar event series.
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
event_id (str): ID of the calendar event series to delete.
timeout (float): Request timeout in seconds.
Returns:
dict[str, Any]: Parsed JSON response from the API.
Raises:
AuthenticationError: If the user is not authenticated (401).
GameSheetError: If the server returns an error or malformed response.
"""
path = f"{TEAMS_CALENDAR_EVENTS_PATH}/{event_id}"
url = f"{TEAMS_API_GATEWAY}{path}"
resp = session.delete(url, timeout=timeout)
if resp.status_code == HTTPStatus.UNAUTHORIZED:
msg = "Authentication required: token is invalid or expired. Run `gamesheet-teams login`."
raise AuthenticationError(msg)
if resp.status_code >= HTTPStatus.BAD_REQUEST:
msg = f"DELETE {path} returned HTTP {resp.status_code}: {resp.text}"
raise GameSheetError(msg)
try:
data = resp.json()
except (ValueError, json.JSONDecodeError) as exc:
msg = f"Failed to parse delete calendar event JSON response: {exc}"
raise GameSheetError(msg) from exc
if not isinstance(data, dict):
msg = "Unexpected response format from calendar event delete API: expected a JSON object."
raise GameSheetError(msg)
return data
[docs]
def delete_calendar_event(
session: BaseAuthenticatedSession,
event_id: str,
*,
timeout: float = DEFAULT_TIMEOUT_S,
) -> ScheduleDeleteResult:
"""Delete a calendar event and all of its occurrences.
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
event_id (str): Identifier of the calendar event series.
timeout (float): Request timeout in seconds.
Returns:
ScheduleDeleteResult: Result of deletion containing success flag and message.
"""
raw = delete_calendar_event_raw(session, event_id, timeout=timeout)
raw_data = raw.get("data")
msg_val = raw_data.get("message") if isinstance(raw_data, dict) else None
msg = str(
msg_val or raw.get("message") or "Calendar event and all occurrences deleted successfully",
)
return ScheduleDeleteResult(success=True, message=msg, id=event_id)
[docs]
def delete_calendar_occurrence_raw(
session: BaseAuthenticatedSession,
occurrence_id: str,
*,
delete_future: bool = False,
timeout: float = DEFAULT_TIMEOUT_S,
) -> dict[str, Any]:
"""Execute raw HTTP DELETE request to delete a calendar occurrence.
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
occurrence_id (str): ID of the calendar occurrence to delete.
delete_future (bool): Whether to delete this and all future occurrences.
timeout (float): Request timeout in seconds.
Returns:
dict[str, Any]: Parsed JSON response from the API.
Raises:
AuthenticationError: If the user is not authenticated (401).
GameSheetError: If the server returns an error or malformed response.
"""
path = f"{TEAMS_CALENDAR_OCCURRENCES_PATH}/{occurrence_id}"
url = f"{TEAMS_API_GATEWAY}{path}"
params = {"deleteFuture": "true" if delete_future else "false"}
resp = session.delete(url, params=params, timeout=timeout)
if resp.status_code == HTTPStatus.UNAUTHORIZED:
msg = "Authentication required: token is invalid or expired. Run `gamesheet-teams login`."
raise AuthenticationError(msg)
if resp.status_code >= HTTPStatus.BAD_REQUEST:
msg = f"DELETE {path} returned HTTP {resp.status_code}: {resp.text}"
raise GameSheetError(msg)
try:
data = resp.json()
except (ValueError, json.JSONDecodeError) as exc:
msg = f"Failed to parse delete calendar occurrence JSON response: {exc}"
raise GameSheetError(msg) from exc
if not isinstance(data, dict):
msg = "Unexpected response format from calendar occurrence delete API: expected a JSON object."
raise GameSheetError(msg)
return data
[docs]
def delete_calendar_occurrence(
session: BaseAuthenticatedSession,
occurrence_id: str,
*,
delete_future: bool = False,
timeout: float = DEFAULT_TIMEOUT_S,
) -> ScheduleDeleteResult:
"""Delete a calendar occurrence (optionally including all future occurrences).
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
occurrence_id (str): Identifier of the occurrence.
delete_future (bool): If True, delete this and all future occurrences.
timeout (float): Request timeout in seconds.
Returns:
ScheduleDeleteResult: Result of deletion containing success flag and message.
"""
raw = delete_calendar_occurrence_raw(
session,
occurrence_id,
delete_future=delete_future,
timeout=timeout,
)
raw_data = raw.get("data")
msg_val = raw_data.get("message") if isinstance(raw_data, dict) else None
fallback_msg = (
"Occurrence and all future occurrences deleted successfully"
if delete_future
else "Occurrence deleted successfully"
)
msg = str(msg_val or raw.get("message") or fallback_msg)
return ScheduleDeleteResult(success=True, message=msg, id=occurrence_id)
[docs]
def delete_event(
session: BaseAuthenticatedSession,
event_id: str,
*,
delete_future: bool = False,
all_occurrences: bool = False,
timeout: float = DEFAULT_TIMEOUT_S,
) -> ScheduleDeleteResult:
"""Delete a calendar event series or occurrence.
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
event_id (str): Identifier of the calendar event or occurrence.
delete_future (bool): If True, delete this and all future occurrences.
all_occurrences (bool): If True, delete the entire event series via /api/calendar/events.
timeout (float): Request timeout in seconds.
Returns:
ScheduleDeleteResult: Result of deletion containing success flag and message.
"""
if all_occurrences:
return delete_calendar_event(session, event_id, timeout=timeout)
return delete_calendar_occurrence(session, event_id, delete_future=delete_future, timeout=timeout)
[docs]
def delete_practice(
session: BaseAuthenticatedSession,
practice_id: str,
*,
delete_future: bool = False,
all_occurrences: bool = False,
timeout: float = DEFAULT_TIMEOUT_S,
) -> ScheduleDeleteResult:
"""Delete a practice calendar event series or occurrence.
Args:
session (BaseAuthenticatedSession): Authenticated session instance.
practice_id (str): Identifier of the practice event or occurrence.
delete_future (bool): If True, delete this and all future occurrences.
all_occurrences (bool): If True, delete the entire practice series via /api/calendar/events.
timeout (float): Request timeout in seconds.
Returns:
ScheduleDeleteResult: Result of deletion containing success flag and message.
"""
if all_occurrences:
return delete_calendar_event(session, practice_id, timeout=timeout)
return delete_calendar_occurrence(session, practice_id, delete_future=delete_future, timeout=timeout)
__all__ = [
"delete_calendar_event",
"delete_calendar_event_raw",
"delete_calendar_occurrence",
"delete_calendar_occurrence_raw",
"delete_event",
"delete_game",
"delete_practice",
"delete_schedule_game_raw",
]