Files
ephemere/python/cohort/create_team_voice_channels.py
T
naomi f5e8deca59
CI / dependency-pin-check-typescript (push) Successful in 5s
CI / dependency-pin-check-python (push) Successful in 4s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 54s
CI / python (push) Successful in 9m24s
CI / typescript (push) Successful in 9m41s
feat: add remaining cohort scripts (#4)
### Explanation

_No response_

### Issue

_No response_

### Attestations

- [ ] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/)
- [ ] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/).
- [ ] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/).

### Dependencies

- [ ] I have pinned the dependencies to a specific patch version.

### Style

- [ ] I have run the linter and resolved any errors.
- [ ] My pull request uses an appropriate title, matching the conventional commit standards.
- [ ] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request.

### Tests

- [ ] My contribution adds new code, and I have added tests to cover it.
- [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes.
- [ ] All new and existing tests pass locally with my changes.
- [ ] Code coverage remains at or above the configured threshold.

### Documentation

_No response_

### Versioning

_No response_

Reviewed-on: #4
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
2026-02-02 12:36:44 -08:00

123 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Create private voice channels for each team in the specified category.
Each channel will be visible and joinable only by the team's role.
"""
import os
import time
import requests
# Discord configuration
BOT_TOKEN = os.environ["DISCORD_BOT_TOKEN"]
GUILD_ID = "692816967895220344"
CATEGORY_ID = "1464311813620502638"
BASE_URL = "https://discord.com/api/v10"
# Team role IDs from send_team_messages.py
TEAMS = {
"Jade Jasmine": {"role_id": "1464314923780931677"},
"Crimson Dahlia": {"role_id": "1464315093402784015"},
"Rose Camellia": {"role_id": "1464315098452726106"},
"Amber Wisteria": {"role_id": "1464315105264275600"},
"Ivory Orchid": {"role_id": "1464315109873684593"},
"Teal Iris": {"role_id": "1464315114378498152"},
"Peach Gardenia": {"role_id": "1464315118904152107"},
"Violet Carnation": {"role_id": "1464315124251754559"},
"Azure Lotus": {"role_id": "1464315128437801177"},
"Coral Sunflower": {"role_id": "1464315132896088168"},
"Indigo Tulip": {"role_id": "1464315138428633241"},
"Scarlet Hydrangea": {"role_id": "1464315142710890520"},
"Mint Narcissus": {"role_id": "1464315149203804405"},
"Sage Marigold": {"role_id": "1464315153599299803"},
}
HEADERS = {"Authorization": f"Bot {BOT_TOKEN}", "Content-Type": "application/json"}
def create_voice_channel(team_name, role_id):
"""Create a voice channel with specific permissions"""
url = f"{BASE_URL}/guilds/{GUILD_ID}/channels"
# Permission overwrites:
# - Deny @everyone from viewing and connecting
# - Allow the team role to view and connect
permission_overwrites = [
{
"id": GUILD_ID, # @everyone role ID is same as guild ID
"type": 0, # Role type
"deny": "1049600", # VIEW_CHANNEL (1 << 10) + CONNECT (1 << 20) = 1049600
"allow": "0",
},
{
"id": role_id, # Team role
"type": 0, # Role type
"allow": "1049600", # VIEW_CHANNEL + CONNECT
"deny": "0",
},
]
data = {
"name": f"{team_name} Voice",
"type": 2, # Voice channel
"parent_id": CATEGORY_ID,
"permission_overwrites": permission_overwrites,
"user_limit": 0, # No user limit
"bitrate": 64000, # 64 kbps
"rtc_region": None, # Auto-select region
}
response = requests.post(url, headers=HEADERS, json=data)
if response.status_code == 201:
channel_data = response.json()
print(f"✓ Created voice channel for {team_name} (ID: {channel_data['id']})")
return True
elif response.status_code == 429:
retry_after = float(response.headers.get("Retry-After", 1))
print(f" Rate limited! Waiting {retry_after:.2f}s...")
time.sleep(retry_after)
return create_voice_channel(team_name, role_id)
else:
print(
f"✗ Failed to create channel for {team_name}: "
f"{response.status_code} - {response.text}"
)
return False
def main():
print(f"Creating private voice channels for {len(TEAMS)} teams...")
print(f"Category ID: {CATEGORY_ID}")
print("-" * 50)
success_count = 0
fail_count = 0
created_channels = []
for team_name, team_data in TEAMS.items():
if create_voice_channel(team_name, team_data["role_id"]):
success_count += 1
created_channels.append(team_name)
else:
fail_count += 1
# Small delay between requests
time.sleep(0.1)
print("-" * 50)
print(f"Complete! Success: {success_count}, Failed: {fail_count}")
if success_count == len(TEAMS):
print("\n✅ All team voice channels have been created!")
print("\nEach voice channel:")
print(" - Is named '[Team Name] Voice'")
print(" - Is only visible to members with that team's role")
print(" - Can only be joined by members with that team's role")
print(" - Has no user limit")
print(" - Uses 64 kbps bitrate")
if __name__ == "__main__":
main()