Skip to content

Commit e3676cd

Browse files
authored
Update slack_monitor_rotation.py
1 parent 61fa78f commit e3676cd

1 file changed

Lines changed: 161 additions & 0 deletions

File tree

scripts/slack_monitor_rotation.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,39 @@
1+
import os
2+
import json
3+
import requests
4+
from datetime import datetime
5+
6+
# Get configuration from environment variables
7+
SLACK_TOKEN = os.environ.get("SLACK_TOKEN")
8+
CHANNEL_ID = os.environ.get("CHANNEL_ID")
9+
ROTATION_FILE = "rotation_state.json"
10+
11+
def get_channel_members():
12+
"""Get all members in the channel, excluding specific users."""
13+
url = "https://slack.com/api/conversations.members"
14+
headers = {"Authorization": f"Bearer {SLACK_TOKEN}"}
15+
params = {"channel": CHANNEL_ID}
16+
17+
response = requests.get(url, headers=headers, params=params)
18+
data = response.json()
19+
20+
if not data.get("ok"):
21+
print(f"Error getting channel members: {data.get('error')}")
22+
return []
23+
24+
# Get all members
25+
all_members = data.get("members", [])
26+
27+
# Get excluded users from environment variable
28+
excluded_users_str = os.environ.get("EXCLUDED_USERS", "")
29+
excluded_users = [user.strip() for user in excluded_users_str.split(",") if user.strip()]
30+
31+
# Filter out excluded users
32+
eligible_members = [user for user in all_members if user not in excluded_users]
33+
34+
print(f"Found {len(eligible_members)} eligible members out of {len(all_members)} total members")
35+
return eligible_members
36+
137
def get_rotation_state():
238
"""Get current rotation state from file or initialize if not exists."""
339
try:
@@ -19,3 +55,128 @@ def save_rotation_state(state):
1955
os.system('git add rotation_state.json')
2056
os.system('git commit -m "Update rotation state [skip ci]"')
2157
os.system(f'git push https://{os.environ.get("GITHUB_TOKEN")}@github.com/{os.environ.get("GITHUB_REPOSITORY")}.git HEAD:main')
58+
59+
def get_user_info(user_id):
60+
"""Get user information from Slack."""
61+
url = "https://slack.com/api/users.info"
62+
headers = {"Authorization": f"Bearer {SLACK_TOKEN}"}
63+
params = {"user": user_id}
64+
65+
response = requests.get(url, headers=headers, params=params)
66+
data = response.json()
67+
68+
if not data.get("ok"):
69+
print(f"Error getting user info: {data.get('error')}")
70+
return {}
71+
72+
return data.get("user", {}).get("profile", {})
73+
74+
def send_message(channel, text):
75+
"""Send a message to a Slack channel."""
76+
url = "https://slack.com/api/chat.postMessage"
77+
headers = {
78+
"Authorization": f"Bearer {SLACK_TOKEN}",
79+
"Content-Type": "application/json"
80+
}
81+
payload = {
82+
"channel": channel,
83+
"text": text
84+
}
85+
86+
response = requests.post(url, headers=headers, json=payload)
87+
if not response.json().get("ok"):
88+
print(f"Error sending message: {response.json().get('error')}")
89+
90+
def update_user_status(user_id):
91+
"""Update user's status to indicate they're the monitor."""
92+
url = "https://slack.com/api/users.profile.set"
93+
headers = {
94+
"Authorization": f"Bearer {SLACK_TOKEN}",
95+
"Content-Type": "application/json"
96+
}
97+
98+
# Set an emoji and status text
99+
payload = {
100+
"user": user_id,
101+
"profile": {
102+
"status_text": "Slack Monitor This Week",
103+
"status_emoji": ":eyes:",
104+
"status_expiration": 0 # Won't expire automatically
105+
}
106+
}
107+
108+
response = requests.post(url, headers=headers, json=payload)
109+
if not response.json().get("ok"):
110+
print(f"Error updating status: {response.json().get('error')}")
111+
112+
def update_monitor_alias(new_monitor_id):
113+
"""Update the bot's profile to indicate current monitor."""
114+
user_info = get_user_info(new_monitor_id)
115+
user_name = user_info.get("real_name", "Unknown User")
116+
117+
# Set the bot's profile to reference the current monitor
118+
url = "https://slack.com/api/users.profile.set"
119+
headers = {
120+
"Authorization": f"Bearer {SLACK_TOKEN}",
121+
"Content-Type": "application/json"
122+
}
123+
124+
payload = {
125+
"profile": {
126+
"real_name": f"PatternFly Slack Monitor ({user_name})",
127+
"status_text": f"Currently: {user_name}",
128+
"status_emoji": ":eyes:",
129+
}
130+
}
131+
132+
response = requests.post(url, headers=headers, json=payload)
133+
if not response.json().get("ok"):
134+
print(f"Error updating bot profile: {response.json().get('error')}")
135+
136+
# Add message in channel about how to tag the current monitor
137+
message = f"<@{new_monitor_id}> is this week's slack-monitor! You can use @patternfly-slack-monitor to tag them."
138+
send_message(CHANNEL_ID, message)
139+
140+
def notify_new_monitor(user_id):
141+
"""Send notification to channel about new monitor."""
142+
message = (
143+
f"<@{user_id}> has been assigned as this week's slack-monitor! "
144+
f"They'll be responsible for monitoring the slack channels according to the document pinned to the top of this channel."
145+
)
146+
send_message(CHANNEL_ID, message)
147+
148+
def assign_slack_monitor():
149+
"""Main function to assign a new slack monitor."""
150+
print(f"Running slack monitor rotation on {datetime.now()}")
151+
152+
# Get all channel members
153+
members = get_channel_members()
154+
if not members:
155+
print("No eligible members found in channel")
156+
return
157+
158+
# Get current rotation state
159+
state = get_rotation_state()
160+
161+
# Select next member
162+
next_index = (state["last_index"] + 1) % len(members)
163+
next_user = members[next_index]
164+
165+
# Update rotation state
166+
state["last_index"] = next_index
167+
state["last_user"] = next_user
168+
save_rotation_state(state)
169+
170+
# Send message to channel
171+
notify_new_monitor(next_user)
172+
173+
# Update user status (optional)
174+
update_user_status(next_user)
175+
176+
# Update bot profile for alias functionality
177+
update_monitor_alias(next_user)
178+
179+
print(f"Successfully assigned {next_user} as the new slack monitor")
180+
181+
if __name__ == "__main__":
182+
assign_slack_monitor()

0 commit comments

Comments
 (0)