diff --git a/users.py b/users.py index 017b7cf..7c3c1a3 100644 --- a/users.py +++ b/users.py @@ -2040,7 +2040,19 @@ def nlp_sample2(): print(token.text,'->',token.pos_) ''' - +def section_enroll(): + user = input("user id> ") + sect = input("section id> ") + u = f"{url}/api/v1/sections/{sect}/enrollments" + + param = { + 'enrollment[user_id]':user, + 'enrollment[type]': 'StudentEnrollment', + 'enrollment[enrollment_state]': 'active', + } + + res = requests.post(u, headers = header, data=param) + print(res.text) def one_course_enrol(): @@ -2648,6 +2660,168 @@ def set_email_skip_confirm(): print(json.dumps(list_channels,indent=2)) print('\n\n') +from html.parser import HTMLParser + +class HTMLStripper(HTMLParser): + def __init__(self): + super().__init__() + self.reset() + self.fed = [] + + def handle_data(self, d): + self.fed.append(d) + + def get_text(self): + return ' '.join(self.fed) + +def strip_html_and_truncate(html, length=25): + if not html: + return "" + stripper = HTMLStripper() + stripper.feed(html) + text = stripper.get_text() + text = ' '.join(text.split()) # collapse all whitespace + text = re.sub(r'\n',' ', text) + return text[:length] +def summarize_submissions(submissions): + summary = [] + for sub in submissions: + assignment = sub.get("assignment", {}) + + summary.append({ + "submission": { + "id": sub.get("id"), + "excerpt": strip_html_and_truncate(sub.get("body", "")), + "grade": sub.get("grade"), + "submitted_at": sub.get("submitted_at"), + "workflow_state": sub.get("workflow_state"), + "missing": sub.get("missing", False), + "late": sub.get("late", False) + }, + "assignment": { + "id": assignment.get("id"), + "excerpt": strip_html_and_truncate(assignment.get("description", "")), + "due_at": assignment.get("due_at"), + "is_quiz": assignment.get("is_quiz_assignment", False), + "points_possible": assignment.get("points_possible") + } + }) + return summary + +def format_assingments_results_table(results): + def safe(val): + return str(val) if val is not None else "-" + + def clip(text): + return (text[:40] + "...") if text and len(text) > 43 else (text or "") + + header = ( + "| Assignment ID | Due Date | Points | Assignment Excerpt " + "| Submission ID | Grade | Submitted At | Late | Missing | Submission Excerpt |" + ) + sep = ( + "|---------------|---------------------|--------|-----------------------" + "|----------------|-----------|--------------------------|-------|---------|-----------------------|" + ) + + rows = [] + for item in results: + a = item['assignment'] + s = item['submission'] + row = ( + f"| {safe(a['id']):<13} | {safe(a['due_at']):<19} | {safe(a['points_possible']):<6} | {clip(a['excerpt']):<23} " + f"| {safe(s['id']):<14} | {safe(s['grade']):<9} | {safe(s['submitted_at']):<24} | {safe(s['late']):<5} | {safe(s['missing']):<7} | {clip(s['excerpt']):<23} |" + ) + rows.append(row) + + return '\n'.join([header, sep] + rows) + + +def user_course_enrollment(user_id, course_id): + user_url = f"{url}/api/v1/courses/{course_id}/enrollments" + myparams = {"user_id": user_id, "type[]": "StudentEnrollment", "state[]": ['active','invited','deleted','rejected','completed','inactive']} + return fetch(user_url, params=myparams) + +def get_student_course_assignments(student_id, course_id): + submission_params = { + "student_ids[]": f"{student_id}", + "include[]": ["assignment"] + } + submissions_url = f"{url}/api/v1/courses/{course_id}/students/submissions" + submissions = fetch(submissions_url, params=submission_params) + summary = summarize_submissions(submissions) + fmt = format_assingments_results_table(summary) + return fmt + +def testme(): + course_id = 21186 + student_id = 73180 + x = get_student_course_assignments(student_id, course_id) + print(x) + # print(json.dumps(x,indent=2)) + +testme() +exit() + +def get_student_course_grades(student_id, course_id): + results = {} + # Course details (final grade) + + submission_params = { + "student_ids[]": [f"user_{student_id}"], + "include[]": ["assignment"] + } + user_url = f"{url}/api/v1/courses/{course_id}/enrollments" + enrollments = user_course_enrollment(student_id, course_id) + if not enrollments or 'errors' in enrollments: + final_score = -1 + final_grade = -1 + else: + final_score = enrollments[0].get("grades", {}).get("current_score", -1) + final_grade = enrollments[0].get("grades", {}).get("current_grade", -1) + # Assignment group mapping + ag_url = f"{url}/api/v1/courses/{course_id}/assignment_groups" + ag_list = fetch(ag_url) + try: + group_lookup = {ag["id"]: ag["name"] for ag in ag_list} + except: + print("groups lookup failed") + # Submissions + submissions_url = f"{url}/api/v1/courses/{course_id}/students/submissions" + submissions = fetch(submissions_url, params=submission_params) + + assignments = [] + for sub in submissions: + try: + assignment = sub.get("assignment", {}) + group_id = assignment.get("assignment_group_id") + group = group_lookup.get(group_id, "Uncategorized") + + assignments.append({ + "assignment_name": assignment.get("name"), + "category": group, + "due_at": assignment.get("due_at"), + "points_possible": assignment.get("points_possible"), + "score": sub.get("score"), + "submitted": sub.get("submitted_at") is not None, + "graded": sub.get("graded_at") is not None or sub.get("score") is not None, + "late": sub.get("late", False), + "missing": sub.get("missing", False), + "excused": sub.get("excused", False) + }) + except: + print("failed to get assignment submissions") + assignments = [] + + results = { + "course_code": course_name, + "final_score": final_score, + "final_grade": final_grade, + "assignments": assignments + } + + return results + def summarize_student_logs(id=0): import pandas as pd @@ -2695,6 +2869,7 @@ def summarize_student_logs(id=0): course_data["participated_count"] = int(group["participated"].sum()) course_summaries[str(course_id)] = course_data + course_summaries[str(course_id)]['grades'] = get_student_course_grades(id, course_id) # App name tally app_name_counts = df["app_name"].fillna("None").value_counts().to_dict() @@ -2736,7 +2911,8 @@ if __name__ == "__main__": 18: ['Quiz submissions', quiz_submissions], 19: ['NLP Sample', nlp_sample], 20: ['Enroll a single user into a class', one_course_enrol], - 21: ['Teachers new this semester', find_new_teachers], + 21: ['Enroll a student into a section', section_enroll], + 22: ['Teachers new this semester', find_new_teachers], #22: ['Sync personnel and conference user databases', user_db_sync], 23: ['Find non-gnumbers', find_no_goo ], 24: ['compare user tables', compare_db_tables],