"""Send initial welcome and roster messages to all team Discord channels. Creates a pinned roster message in each team channel and stores the resulting message ID, channel ID, and role ID in team_message_ids.json for use by other scripts (send_checkin.py, update_roster_messages.py, etc.). Data files (place in data/): - team_assignments.json Team rosters with leaders and participants per team - applicants_to_evaluate.json Applicant data including Discord channel/role IDs Outputs (written to data/): - team_message_ids.json Channel ID, message ID, and role ID per team Env vars: - DISCORD_BOT_TOKEN Bot token for the Discord API """ import json import os import time from pathlib import Path import requests DATA_DIR = Path(__file__).parent.parent.parent / "data" TOKEN = os.environ["DISCORD_BOT_TOKEN"] GUILD_ID = "692816967895220344" # File to save message IDs MESSAGE_IDS_FILE = "team_message_ids.json" # Team channel IDs and role IDs TEAMS = { "Jade Jasmine": { "channel_id": "1464316501573107886", "role_id": "1464314923780931677", }, "Crimson Dahlia": { "channel_id": "1464316744909852682", "role_id": "1464315093402784015", }, "Rose Camellia": { "channel_id": "1464316751268286611", "role_id": "1464315098452726106", }, "Amber Wisteria": { "channel_id": "1464316761410113641", "role_id": "1464315105264275600", }, "Ivory Orchid": { "channel_id": "1464316770889240730", "role_id": "1464315109873684593", }, "Teal Iris": { "channel_id": "1464316776459407448", "role_id": "1464315114378498152", }, "Peach Gardenia": { "channel_id": "1464316785040953543", "role_id": "1464315118904152107", }, "Violet Carnation": { "channel_id": "1464316805261824032", "role_id": "1464315124251754559", }, "Azure Lotus": { "channel_id": "1464316814455472139", "role_id": "1464315128437801177", }, "Coral Sunflower": { "channel_id": "1464316819711066263", "role_id": "1464315132896088168", }, "Indigo Tulip": { "channel_id": "1464316826384072925", "role_id": "1464315138428633241", }, "Scarlet Hydrangea": { "channel_id": "1464316839306985506", "role_id": "1464315142710890520", }, "Mint Narcissus": { "channel_id": "1464316844251807952", "role_id": "1464315149203804405", }, "Sage Marigold": { "channel_id": "1464316850669093040", "role_id": "1464315153599299803", }, } # Load team assignments and convert to dict by team name with open(DATA_DIR / "team_assignments.json") as f: team_list = json.load(f) team_data = {team["name"]: team for team in team_list} # Load applicants to get project_url by discord_id with open(DATA_DIR / "applicants_to_evaluate.json") as f: applicants = json.load(f) applicant_lookup = {str(a["discord_id"]): a for a in applicants} def extract_github_username(url): """Extract GitHub username from various URL formats""" if not url: return "unknown" url = url.strip() # Handle GitLab special case (RashiqAzhan) if "gitlab.com" in url: # We know this is RashiqAzhan from earlier confirmation return "RashiqAzhan" # Handle GitHub Pages URLs if ".github.io" in url: # Extract username from username.github.io format parts = url.replace("https://", "").replace("http://", "").split(".") if parts: return parts[0] # Handle plain usernames (no URL) if not url.startswith("http"): return url # Handle standard GitHub URLs if "github.com" in url: # Remove protocol and github.com path = ( url.replace("https://", "") .replace("http://", "") .replace("github.com/", "") ) # Get just the username (first part of path) username = path.split("/")[0] return username return url def build_message(team_name, role_id, leader_ids, participant_ids): """Build the welcome message for a team""" lines = [ f"# {team_name}", "", f"Welcome, <@&{role_id}>. This is your private team channel — a space " "for you to collaborate, support one another, and build something " "meaningful together.", "", "## Roster", "", "**Leadership**", ] for discord_id in leader_ids: applicant = applicant_lookup.get(str(discord_id), {}) project_url = applicant.get("project_url", "") github_username = extract_github_username(project_url) lines.append(f"- <@{discord_id}>: https://github.com/{github_username}") lines.append("") lines.append("**Participants**") for discord_id in participant_ids: applicant = applicant_lookup.get(str(discord_id), {}) project_url = applicant.get("project_url", "") github_username = extract_github_username(project_url) lines.append(f"- <@{discord_id}>: https://github.com/{github_username}") lines.append("") lines.append("## Project Info") lines.append("") lines.append("Coming soon. 💜") return "\n".join(lines) def send_message(channel_id, content): """Send a message to a channel""" url = f"https://discord.com/api/v10/channels/{channel_id}/messages" headers = {"Authorization": f"Bot {TOKEN}", "Content-Type": "application/json"} data = {"content": content} response = requests.post(url, headers=headers, json=data) if response.status_code == 429: retry_after = float( response.headers.get( "Retry-After", response.headers.get("X-RateLimit-Reset-After", 1) ) ) print(f"Rate limited, waiting {retry_after}s...") time.sleep(retry_after) return send_message(channel_id, content) if response.status_code == 200: return response.json() else: print(f"Error sending message: {response.status_code} - {response.text}") return None def pin_message(channel_id, message_id): """Pin a message in a channel""" url = f"https://discord.com/api/v10/channels/{channel_id}/pins/{message_id}" headers = { "Authorization": f"Bot {TOKEN}", } response = requests.put(url, headers=headers) if response.status_code == 429: retry_after = float( response.headers.get( "Retry-After", response.headers.get("X-RateLimit-Reset-After", 1) ) ) print(f"Rate limited, waiting {retry_after}s...") time.sleep(retry_after) return pin_message(channel_id, message_id) return response.status_code == 204 def main(): message_ids = {} for team_name, team_info in TEAMS.items(): channel_id = team_info["channel_id"] role_id = team_info["role_id"] # Get team members from team_data team = team_data.get(team_name, {"leaders": [], "participants": []}) leaders = team.get("leaders", []) participants = team.get("participants", []) # Build the message message_content = build_message(team_name, role_id, leaders, participants) print(f"Sending message to {team_name}...") # Send the message result = send_message(channel_id, message_content) if result: message_id = result["id"] message_ids[team_name] = { "channel_id": channel_id, "message_id": message_id, "role_id": role_id, } print(f" Message sent! ID: {message_id}") # Pin the message print(" Pinning message...") if pin_message(channel_id, message_id): print(" Pinned!") else: print(" Failed to pin") else: print(" Failed to send message") # Small delay between teams time.sleep(0.2) # Save message IDs to file with open(MESSAGE_IDS_FILE, "w") as f: json.dump(message_ids, f, indent=2) print(f"\nDone! Message IDs saved to {MESSAGE_IDS_FILE}") print(f"Successfully sent and pinned messages for {len(message_ids)} teams") if __name__ == "__main__": main()