-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathutils.py
209 lines (161 loc) · 6.83 KB
/
utils.py
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import json, time, os, logging, requests
from requests.exceptions import ConnectionError
from LearningAPI.models.people import NssUser
class SlackAPI(object):
""" This class is used to create a Slack channel for a student team """
def __init__(self):
self.headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
def send_message(self, channel, text):
# Configure the config for the Slack message
channel_payload = {
"text": text,
"token": os.getenv("SLACK_BOT_TOKEN"),
"channel": channel
}
response = requests.post(
url="https://slack.com/api/chat.postMessage",
data=channel_payload,
headers=self.headers,
timeout=10
)
return response.json()
def delete_channel(self, channel_id):
channel_payload = {
"channel": channel_id,
"token": os.getenv("SLACK_BOT_TOKEN")
}
# Create a Slack channel with the given name
res = requests.post(
"https://slack.com/api/conversations.archive",
timeout=10,
data=channel_payload,
headers=self.headers
)
channel_res = res.json()
return channel_res['ok']
def create_channel(self, name, members):
"""Create a Slack channel for a student team"""
channel_payload = {
"name": name,
"token": os.getenv("SLACK_BOT_TOKEN")
}
# Create a Slack channel with the given name
res = requests.post(
"https://slack.com/api/conversations.create",
timeout=10,
data=channel_payload,
headers=self.headers
)
channel_res = res.json()
logging.info("Channel created: %s", channel_res)
if not channel_res["ok"]:
raise Exception(json.dumps(channel_res))
# Create a set of Slack IDs for the members to be added to the channel
member_slack_ids = set()
for member_id in members:
member = NssUser.objects.get(pk=member_id)
if member.slack_handle is not None:
member_slack_ids.add(member.slack_handle)
# Create a payload to invite students and instructors to the channel
invitation_payload = {
"channel": channel_res["channel"]["id"],
"users": ",".join(list(member_slack_ids)),
"token": os.getenv("SLACK_BOT_TOKEN")
}
# Invite students and instructors to the channel
requests.post(
"https://slack.com/api/conversations.invite",
timeout=10,
data=invitation_payload,
headers=self.headers
)
# Return the channel ID for the team
return channel_res["channel"]["id"]
class GithubRequest(object):
def __init__(self):
self.headers = {
"Content-Type": "application/json",
"Accept": "application/vnd.github+json",
"User-Agent": "nss/ticket-migrator",
"X-GitHub-Api-Version": "2022-11-28",
"Authorization": f'Bearer {os.getenv("GITHUB_TOKEN")}'
}
def create_repository(self, source_url: str, student_org_url: str, repo_name: str, project_name: str) -> requests.Response:
"""Create a repository for a student team
Args:
source_url (str): The URL of the source repository
student_org_url (str): The URL of the student organization
repo_name (str): The name of the repository
project_name (str): The name of the project
Returns:
requests.Response: The response from the GitHub API
"""
# Split the full URL on '/' and get the last two items
( org, repo, ) = source_url.split('/')[-2:]
student_org_name = student_org_url.split("/")[-1]
# Construct request body for creating the repository
request_body = {
"owner": student_org_name,
"name": repo_name,
"description": f"This is your client-side repository for the {project_name} sprint(s).",
"include_all_branches": False,
"private": False
}
# Create the repository
response = self.post(url=f'https://api.github.com/repos/{org}/{repo}/generate', data=request_body)
return response
def assign_student_permissions(self, student_org_name: str, repo_name: str, student: NssUser, permission: str = "write") -> requests.Response:
"""Assign write permissions to a student for a repository
Args:
student_org_name (str): The name of the student organization
repo_name (str): The name of the repository
student (NSSUser): The student to assign permissions to
Returns:
requests.Response: The response from the GitHub API
"""
# Construct request body for assigning permissions to the student
request_body = { "permission":permission }
# Assign the student write permissions to the repository
response = self.put(
url=f'https://api.github.com/repos/{student_org_name}/{repo_name}/collaborators/{student.github_handle}',
data=request_body
)
if response.status_code != 204:
logger = logging.getLogger("LearningPlatform")
logger.exception(
"Error: %s was not added as a collaborator to the assessment repository.",
student.full_name
)
return response
def get(self, url):
return self.request_with_retry(lambda: requests.get(url=url, headers=self.headers, timeout=10))
def put(self, url, data):
json_data = json.dumps(data)
return self.request_with_retry(lambda: requests.put(url=url, data=json_data, headers=self.headers, timeout=10))
def post(self, url, data):
json_data = json.dumps(data)
try:
result = self.request_with_retry(lambda: requests.post(url=url, data=json_data, headers=self.headers, timeout=10))
return result
except TimeoutError:
print("Request timed out. Trying next...")
except ConnectionError:
print("Request timed out. Trying next...")
return None
def request_with_retry(self, request):
retry_after_seconds = 1800
number_of_retries = 0
response = request()
while response.status_code == 403 and number_of_retries <= 10:
number_of_retries += 1
os.system('cls' if os.name == 'nt' else 'clear')
self.sleep_with_countdown(retry_after_seconds)
response = request()
return response
def sleep_with_countdown(self, countdown_seconds):
ticks = countdown_seconds * 2
for count in range(ticks, -1, -1):
if count:
time.sleep(0.5)