generated from nhcarrigan/template
a40188413a
All Python cohort scripts now use DATA_DIR = Path(__file__).parent.parent.parent / "data" to correctly resolve the repo-root data/ directory regardless of the working directory set by run.sh. All TypeScript scripts have expanded JSDoc headers documenting data file requirements and environment variables.
277 lines
8.2 KiB
Python
277 lines
8.2 KiB
Python
"""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()
|