File size: 4,847 Bytes
c6abe34 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | from uuid import uuid4
from datetime import datetime
from typing import List
from fastapi import APIRouter, Depends, HTTPException, status
from app.dependencies import (
get_supabase,
get_current_user,
require_team_account,
require_staff_member,
require_linked_account
)
from app.services.supabase_client import SupabaseService
from app.models.communication import Announcement, AnnouncementCreate, AnnouncementListResponse
router = APIRouter()
@router.get("/announcements", response_model=AnnouncementListResponse)
async def get_announcements(
current_user: dict = Depends(get_current_user),
supabase: SupabaseService = Depends(get_supabase),
):
"""
Get all announcements for the user's organization.
Accessible by Team Owners, Coaches, and Linked Players.
"""
org_id = current_user.get("organization_id")
# Fallback to DB check if not in token (account might have been linked after login)
if not org_id:
user_id = current_user["id"]
user_record = await supabase.select_one("users", user_id)
if user_record and user_record.get("organization_id"):
org_id = user_record["organization_id"]
elif current_user.get("account_type") == "team":
# Extra fallback for Owners
orgs = await supabase.select("organizations", filters={"owner_id": user_id})
if orgs:
org_id = orgs[0]["id"]
if not org_id:
# User is not linked to any organization
return AnnouncementListResponse(announcements=[], total=0)
announcements_data = await supabase.select(
"announcements",
filters={"organization_id": org_id},
order_by="created_at",
ascending=False
)
# Enrich with author name if needed (optional)
announcements = []
for item in announcements_data:
announcement = Announcement(**item)
# Fetch author name for UI
author = await supabase.select_one("users", str(item["author_id"]))
if author:
announcement.author_name = author.get("full_name") or author.get("email")
announcements.append(announcement)
return AnnouncementListResponse(announcements=announcements, total=len(announcements))
@router.post("/announcements", response_model=Announcement, status_code=status.HTTP_201_CREATED)
async def create_announcement(
data: AnnouncementCreate,
current_user: dict = Depends(require_staff_member),
supabase: SupabaseService = Depends(get_supabase),
):
"""
Create a new announcement for the organization.
Restricted to Coaching Staff (per user request).
"""
org_id = current_user.get("organization_id")
if not org_id:
raise HTTPException(status_code=403, detail="You must be linked to an organization")
announcement_id = str(uuid4())
record = {
"id": announcement_id,
"organization_id": org_id,
"author_id": current_user["id"],
"title": data.title,
"content": data.content,
"created_at": datetime.now().isoformat(),
"updated_at": datetime.now().isoformat()
}
saved = await supabase.insert("announcements", record)
# Create notifications for all players in the roster
try:
players = await supabase.select("players", filters={"organization_id": org_id})
for player in players:
if player.get("user_id"):
await supabase.insert("notifications", {
"id": str(uuid4()),
"recipient_id": player["user_id"],
"title": f"New Announcement: {data.title}",
"message": f"Coach {current_user.get('email')} posted a new announcement.",
"type": "announcement",
"read": False,
"created_at": datetime.now().isoformat()
})
except Exception as e:
print(f"Warning: Failed to send announcement notifications: {e}")
return Announcement(**saved)
@router.delete("/announcements/{announcement_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_announcement(
announcement_id: str,
current_user: dict = Depends(require_staff_member),
supabase: SupabaseService = Depends(get_supabase),
):
"""
Delete an announcement.
Restricted to Coaches.
"""
org_id = current_user.get("organization_id")
announcement = await supabase.select_one("announcements", announcement_id)
if not announcement:
raise HTTPException(status_code=404, detail="Announcement not found")
if str(announcement["organization_id"]) != str(org_id):
raise HTTPException(status_code=403, detail="Access denied")
await supabase.delete("announcements", announcement_id)
return None
|