-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from stevebrownlee/develop
Phase 1 of Github Classroom obsolescence
- Loading branch information
Showing
14 changed files
with
921 additions
and
278 deletions.
There are no files selected for viewing
175 changes: 175 additions & 0 deletions
175
LearningAPI/migrations/0048_add_assessment_url_to_db_function.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
# Generated by Django 4.2.8 on 2024-01-10 18:42 | ||
|
||
from django.db import migrations | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("LearningAPI", "0047_add_capstone_status_id_to_db_function"), | ||
] | ||
|
||
operations = [ | ||
migrations.RunSQL( | ||
""" | ||
DROP FUNCTION IF EXISTS get_cohort_student_data(INT); | ||
CREATE FUNCTION get_cohort_student_data(selected_cohort_id INT) | ||
RETURNS TABLE ( | ||
user_id INT, | ||
student_name TEXT, | ||
score INT, | ||
github_handle TEXT, | ||
extra_data TEXT, | ||
current_cohort TEXT, | ||
current_cohort_id INT, | ||
assessment_status_id INT, | ||
assessment_url TEXT, | ||
current_project_id INT, | ||
current_project_index INT, | ||
current_project_name TEXT, | ||
current_book_id INT, | ||
current_book_index INT, | ||
current_book_name TEXT, | ||
student_notes TEXT, | ||
student_tags TEXT, | ||
capstone_proposals TEXT, | ||
project_duration DOUBLE PRECISION | ||
) AS $$ | ||
BEGIN | ||
RETURN QUERY | ||
SELECT | ||
nu.id::int AS user_id, | ||
au."first_name" || ' ' || au."last_name" AS student_name, | ||
COALESCE(lr.total_score, 0)::int AS score, | ||
nu.github_handle::text, | ||
social.extra_data::text, | ||
c.name::text AS current_cohort, | ||
c.id::int AS current_cohort_id, | ||
COALESCE(sa.status_id::int, 0) AS assessment_status_id, | ||
sa.url::text AS assessment_url, | ||
sp.project_id::int AS current_project_id, | ||
p.index::int AS current_project_index, | ||
p.name::text AS current_project_name, | ||
b.id::int AS current_book_id, | ||
b.index::int AS current_book_index, | ||
b.name::text AS current_book_name, | ||
COALESCE( | ||
json_agg( | ||
json_build_object( | ||
'note_id', sn.id, | ||
'note', sn.note, | ||
'created_on', sn.created_on | ||
) | ||
) | ||
)::text AS student_notes, | ||
COALESCE( | ||
( | ||
SELECT json_agg( | ||
json_build_object( | ||
'id', st."id", | ||
'tag', t."name" | ||
) | ||
) | ||
FROM "LearningAPI_studenttag" st | ||
LEFT JOIN "LearningAPI_tag" t ON t."id" = st."tag_id" | ||
WHERE st."student_id" = nu.id | ||
) | ||
, '[]')::text AS student_tags, | ||
COALESCE( | ||
( | ||
SELECT json_agg( | ||
json_build_object( | ||
'id', c."id", | ||
'status', ps.status, | ||
'current_status_id', ps.id, | ||
'proposal_url', c."proposal_url", | ||
'created_on', tl.date, | ||
'course_name', cr.name | ||
) | ||
) | ||
FROM "LearningAPI_capstone" c | ||
LEFT JOIN ( | ||
SELECT DISTINCT ON ( | ||
ct.capstone_id, c.course_id | ||
) * | ||
FROM "LearningAPI_capstonetimeline" ct | ||
JOIN "LearningAPI_capstone" c ON c.id = ct.capstone_id | ||
ORDER BY | ||
c.course_id, | ||
ct.capstone_id, | ||
date desc | ||
) tl ON tl.capstone_id = c.id | ||
LEFT JOIN "LearningAPI_proposalstatus" ps ON ps."id" = tl.status_id | ||
LEFT JOIN "LearningAPI_course" cr ON c.course_id = cr.id | ||
WHERE c."student_id" = nu.id | ||
), '[]' | ||
)::text AS capstone_proposals, | ||
CASE | ||
WHEN sa.id IS NOT NULL AND sa.assessment_id = la.id THEN | ||
( | ||
EXTRACT(YEAR FROM AGE(NOW(), sa.date_created)) * 365 + | ||
EXTRACT(MONTH FROM AGE(NOW(), sa.date_created)) * 30 + | ||
EXTRACT(DAY FROM AGE(NOW(), sa.date_created)) | ||
)::double precision | ||
ELSE | ||
( | ||
EXTRACT(YEAR FROM AGE(NOW(), sp.date_created)) * 365 + | ||
EXTRACT(MONTH FROM AGE(NOW(), sp.date_created)) * 30 + | ||
EXTRACT(DAY FROM AGE(NOW(), sp.date_created)) | ||
)::double precision | ||
END AS project_duration | ||
FROM "LearningAPI_nssuser" nu | ||
JOIN "auth_user" au ON au."id" = nu."user_id" | ||
LEFT JOIN "LearningAPI_nssusercohort" nc ON nc."nss_user_id" = nu."id" | ||
LEFT JOIN "LearningAPI_cohort" c ON c."id" = nc."cohort_id" | ||
LEFT JOIN "LearningAPI_studentnote" sn ON sn."student_id" = nu."id" | ||
LEFT JOIN "LearningAPI_studenttag" stg ON stg."student_id" = nu."id" | ||
LEFT JOIN "LearningAPI_tag" tag ON stg.tag_id = tag.id | ||
LEFT JOIN "socialaccount_socialaccount" social ON social.user_id = nu.user_id | ||
LEFT JOIN "LearningAPI_capstone" sc ON sc.student_id = nu."id" | ||
LEFT JOIN "LearningAPI_studentproject" sp | ||
ON sp."student_id" = nu."id" | ||
AND sp.id = ( | ||
SELECT id | ||
FROM "LearningAPI_studentproject" | ||
WHERE "student_id" = nu."id" | ||
ORDER BY id DESC | ||
LIMIT 1 | ||
) | ||
LEFT JOIN "LearningAPI_project" p ON p."id" = sp."project_id" | ||
LEFT JOIN "LearningAPI_book" b ON b."id" = p."book_id" | ||
LEFT JOIN "LearningAPI_assessment" la | ||
ON b.id = la.book_id | ||
LEFT JOIN "LearningAPI_studentassessment" sa | ||
ON sa."student_id" = nu."id" | ||
AND sa."assessment_id" = la."id" | ||
AND sa."date_created" = ( | ||
SELECT MAX("date_created") | ||
FROM "LearningAPI_studentassessment" | ||
WHERE "student_id" = nu."id" | ||
AND "assessment_id" = la."id" | ||
) | ||
AND sa.assessment_id = la.id | ||
LEFT JOIN ( | ||
SELECT lr."student_id", SUM(lw."weight") AS total_score | ||
FROM "LearningAPI_learningrecord" lr | ||
JOIN "LearningAPI_learningweight" lw ON lw."id" = lr."weight_id" | ||
WHERE lr."achieved" = true | ||
GROUP BY lr."student_id" | ||
) lr ON lr."student_id" = nu."id" | ||
WHERE nc."cohort_id" = selected_cohort_id | ||
AND au.is_active = TRUE | ||
AND au.is_staff = FALSE | ||
GROUP BY nu.id, nu.github_handle, social.extra_data, sa.url, | ||
student_name, current_cohort, current_cohort_id, assessment_status_id, | ||
current_project_id, current_project_index, current_project_name, | ||
project_duration, current_book_id, current_book_index, current_book_name, | ||
score | ||
ORDER BY b.index ASC, | ||
p.index ASC; | ||
END; | ||
$$ LANGUAGE plpgsql; | ||
""", | ||
"" | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import json | ||
import time | ||
import os | ||
import requests | ||
from requests.exceptions import ConnectionError | ||
|
||
|
||
class GithubRequest(object): | ||
def __init__(self): | ||
self.headers = { | ||
"Content-Type": "application/json", | ||
"Accept": "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 get(self, url): | ||
return self.request_with_retry( | ||
lambda: requests.get(url=url, headers=self.headers)) | ||
|
||
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)) | ||
|
||
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)) | ||
|
||
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): | ||
remaining = str(int(0.5 + count / 2)).rjust(2) | ||
spinner = ['-', '/', '|', '\\'][count % 4] | ||
|
||
progress = '=' * (ticks - count) | ||
if count: | ||
progress = progress[:-1] + '>' | ||
|
||
print( | ||
f'[bright_white] {spinner} [{progress.ljust(ticks)}] {remaining}[/bright_white]', end='\r') | ||
|
||
if count: | ||
time.sleep(0.5) | ||
|
||
print() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.