diff --git a/courses.py b/courses.py index 43ecd4f..0a8c87f 100644 --- a/courses.py +++ b/courses.py @@ -1254,9 +1254,11 @@ def enroll_gott_workshops(): #['2025-02-23 16:00:00', 'GOTT 6: Intro to Synchronous Teaching (Sync/Hyflex)', 21835], #['2025-03-14 17:00:00', 'GOTT 5: The Essentials of Blended Learning (Hybrid) ', '21886'], #['2025-02-23 16:00:00', 'GOTT 1: Intro to Teaching Online (2 week, async)', 21874] - ['2025-05-26 17:00:00', 'GOTT 2: Introduction to Asynchronous Teaching and Learning', 23015], - ['2025-06-01 17:00:00', 'GOTT 1: Intro to Teaching Online', 23083], - ['2025-06-01 17:00:00', 'GOTT 4: Assessments in Digital Learning', 21898], + #['2025-05-26 17:00:00', 'GOTT 2: Introduction to Asynchronous Teaching and Learning', 23015], + #['2025-06-01 17:00:00', 'GOTT 1: Intro to Teaching Online', 23083], + #['2025-06-01 17:00:00', 'GOTT 4: Assessments in Digital Learning', 21898], + + ['2025-08-11 13:00:00', 'GOTT 1: Introduction to Online Teaching with Canvas', 23232], ] #print(json.dumps(signups,indent=4)) #print(json.dumps(by_email,indent=4)) @@ -1466,15 +1468,17 @@ def set_custom_start_dates(): TERM = term['canvas_term_id'] SEM = term['code'] - term_start_month = term['begin'].split('/')[0] - term_start_day = term['begin'].split('/')[1] + term_start_month = int(term['begin'].split('/')[0]) + term_start_day = int(term['begin'].split('/')[1]) term_start_year = '20' + term['code'][2:4] print(f"term begins on {term_start_month}/{term_start_day}") - filepath = f"cache/overview_semester_shells_{SEM}.csv" - if not os.path.exists(filepath): - print(f"file does not exist: {filepath}") + output_path = f"cache/overview_semester_shells_annotated{SEM}.csv" + + input_path = f"cache/overview_semester_shells_{SEM}.csv" + if not os.path.exists(input_path): + print(f"file does not exist: {input_path}") print("Run overview_start_dates first") return @@ -1499,13 +1503,17 @@ def set_custom_start_dates(): except ValueError: return None - with open(filepath, newline='', encoding='utf-8') as csvfile: - reader = csv.DictReader(csvfile) - - for row in reader: - annotations = {} + with open(input_path, newline='', encoding='utf-8') as infile, \ + open(output_path, "w", newline='', encoding='utf-8') as outfile: - # Skip shells with no sections + reader = csv.DictReader(infile) + fieldnames = reader.fieldnames + [ + "ignore","is_early_start", "is_late_start", "shell_custom_start", "shell_warn_crosslist_sections" + ] + writer = csv.DictWriter(outfile, fieldnames=fieldnames) + writer.writeheader() + + for row in reader: if int(row["shell_numsections"]) == 0: continue @@ -1514,35 +1522,43 @@ def set_custom_start_dates(): shortname = row["shell_shortname"] num_sections = int(row["shell_numsections"]) - # Check early/late start - if sched_start: - if (sched_start.month, sched_start.day) != (int(term_start_month), int(term_start_day)): - if (sched_start.month, sched_start.day) < (int(term_start_month), int(term_start_day)): - annotations["is_early_start"] = sched_start.date().isoformat() - else: - annotations["is_late_start"] = sched_start.date().isoformat() + # Initialize new columns + row["ignore"] = "" + row["is_early_start"] = "" + row["is_late_start"] = "" + row["shell_custom_start"] = "" + row["shell_warn_crosslist_sections"] = "" - # Check if shell_start is manually set + # check for cops program + department = shortname.split()[0].rstrip("0123456789") # → "JLE" + if department in ("JLE", "JFT"): + row["ignore"] = department + + # Early/late start check + if sched_start: + sched_mmdd = (sched_start.month, sched_start.day) + term_mmdd = (term_start_month, term_start_day) + if sched_mmdd < term_mmdd: + row["is_early_start"] = sched_start.date().isoformat() + elif sched_mmdd > term_mmdd: + row["is_late_start"] = sched_start.date().isoformat() + + # shell_start override if shell_start: - annotations["shell_custom_start"] = shell_start.date().isoformat() + row["shell_custom_start"] = shell_start.date().isoformat() else: - if "is_early_start" in annotations or "is_late_start" in annotations: + if row["is_early_start"] or row["is_late_start"]: adjust_shell_startdate(row) - # Check section numbers in shortname vs shell_numsections + # Crosslist check if '/' in shortname: parts = shortname.split() - section_part = parts[-1] # last part assumed to be section numbers - section_groups = section_part.split('/') - if len(section_groups) != num_sections: - annotations["shell_warn_crosslist_sections"] = section_part - - # Print row and annotations if anything notable happened - if annotations: - print("Annotations:", annotations) - print("Row:", row) - print("-" * 80) + section_part = parts[-1] + section_count = len(section_part.split('/')) + if section_count != num_sections: + row["shell_warn_crosslist_sections"] = section_part + writer.writerow(row) return ''' # Do we adjust the start date? Only if it doesn't match term @@ -1867,9 +1883,10 @@ def create_sandboxes(): #(20761, ' Sandbox GOTT1 FA24'), #(21770, ' Sandbox GOTT1 WI25'), #(21772, ' Sandbox GOTT2 WI25'), - (23083, ' Sandbox GOTT1 SU25'), - (23015, ' Sandbox GOTT2 SU25'), - (21898, ' Sandbox GOTT4 SU25'), + #(23083, ' Sandbox GOTT1 SU25'), + #(23015, ' Sandbox GOTT2 SU25'), + #(21898, ' Sandbox GOTT4 SU25'), + (23232, ' Sandbox GOTT1 FA25'), ] filepath = 'cache/sandbox_courses.pkl' @@ -2537,16 +2554,17 @@ def bulk_unenroll(): print(f"Failed to unenroll student with id {enrollment_id} from course {course_id}. Error: {response.text}") -def fetch_announcements(): - course_id = 20603 - announcements_url = f"{url}/api/v1/announcements?context_codes[]=course_{course_id}" +def fetch_announcements(course_id=0): + if not course_id: + course_id = input("course id> ") + announcements_url = f"{url}/api/v1/announcements?context_codes[]=course_{course_id}&start_date=2025-01-01&end_date=2025-12-31" announcements = fetch(announcements_url) print(json.dumps(announcements,indent=2)) - filename = f"cache/announcements{course_id}.json" + filename = f"cache/announcements_{course_id}.json" with open(filename, "w") as file: - json.dump(announcements, file) + json.dump(announcements, file,indent=2) print("Announcements saved to ", filename) diff --git a/users.py b/users.py index 12e9e6e..b634ddc 100644 --- a/users.py +++ b/users.py @@ -2242,7 +2242,9 @@ def cross_ref_training(): term = "202570" # Fetch from Canvas DB. Make sure its recently updated. - # Also relies on schedule being in database. Run localcache2.courses_to_sched() + # Also relies on schedule being in database. Run localcache2.courses_to_sched() + # OR localcache2.refresh_semester_schedule_db() + #courses = all_2x_sem_courses_teachers('202550', '202570') # courses = all_sem_courses_teachers(term) @@ -2456,7 +2458,7 @@ def cross_ref_training(): sheet.column_dimensions['A'].width = 20 sheet.column_dimensions['B'].width = 30 sheet.column_dimensions['C'].width = 75 - formatted_date = datetime.datetime.now().strftime('%Y%m%d') + formatted_date = dt.now().strftime('%Y%m%d') wb.save(f"C:/Users/phowell/Downloads/GOTT_Completion_masterlist_{formatted_date}_summarized.xlsx") def cross_ref_training_withcsv(): @@ -2709,7 +2711,6 @@ def summarize_submissions(submissions): }) return summary -from datetime import datetime import pytz def format_assignments_results_table(results): @@ -2722,14 +2723,14 @@ def format_assignments_results_table(results): def to_pacific(iso): if not iso: return "-" - utc = datetime.strptime(iso, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=pytz.utc) + utc = dt.strptime(iso, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=pytz.utc) pacific = utc.astimezone(pytz.timezone("US/Pacific")) return pacific.strftime("%Y-%m-%d %I:%M%p") # Sort by assignment due date (missing dates go last) def get_due_at(item): dt = item["assignment"].get("due_at") - return datetime.max if not dt else datetime.strptime(dt, "%Y-%m-%dT%H:%M:%SZ") + return dt.max if not dt else dt.strptime(dt, "%Y-%m-%dT%H:%M:%SZ") results = sorted(results, key=get_due_at) @@ -2856,7 +2857,6 @@ def summarize_student_logs(id=0): import re import json from collections import defaultdict - from datetime import datetime from localcache2 import course_from_id if id==0: