diff --git a/courses.py b/courses.py index 4bd18dd..9763679 100644 --- a/courses.py +++ b/courses.py @@ -641,6 +641,12 @@ def do_manual_xlist(): print(para_list) xlist(host, para_list) +def ez_xlist(): + host = int(input('what is the host id? ')) + parasite = input('what are parasite ids? (separate with commas) ') + parasite = [ int(x) for x in parasite.split(',') ] + xlist(host,parasite) + # Crosslist given 2 ids, computing the new name and code def xlist(host_id, parasite_list): host_info = course_from_id(host_id) @@ -1540,11 +1546,12 @@ def teacher_to_many_shells(): import os, pickle def create_sandboxes(): - courses_to_sandbox = [ (20567, ' Sandbox GOTT1 SU24'), - (20575, ' Sandbox GOTT2 SU24'), - (20600, ' Sandbox GOTT4 SU24'), - (19223, ' Sandbox GOTT5 WI24'), + courses_to_sandbox = [ #(20567, ' Sandbox GOTT1 SU24'), + #(20575, ' Sandbox GOTT2 SU24'), + #(20600, ' Sandbox GOTT4 SU24'), + #(19223, ' Sandbox GOTT5 WI24'), #(19224, ' Sandbox GOTT6 WI24') + (20603, ' Sandbox GOTT1 AUG SU24') ] filepath = 'cache/sandbox_courses.pkl' @@ -1557,6 +1564,7 @@ def create_sandboxes(): sandbox_log = [] for crs_id, label in courses_to_sandbox: + # TODO check and skip "Test Student" crs_info = getCourses(crs_id) # print(json.dumps(crs_info,indent=2)) c_name = crs_info['name'] @@ -2106,7 +2114,7 @@ def bulk_unenroll(): def fetch_announcements(): - course_id = 18268 + course_id = 20603 announcements_url = f"{url}/api/v1/announcements?context_codes[]=course_{course_id}" announcements = fetch(announcements_url) @@ -2270,6 +2278,7 @@ if __name__ == "__main__": 31: ['Fine tune term dates and winter session', course_by_depts_terms], #32: ['Cross-list classes', xlist ], #33: ['Cross list helper', eslCrosslister], + 33: ['Cross list, ask for sections', ez_xlist], 34: ['Cross list a semester from argos export file', semester_cross_lister], 35: ['Cross list from manually created file', do_manual_xlist], 36: ['Quick course list', quick_sem_course_list ], diff --git a/flexday.py b/flexday.py index c440d51..0b6f8bc 100644 --- a/flexday.py +++ b/flexday.py @@ -1,4 +1,8 @@ -import funcy, codecs, json, sys, csv, re +import funcy, codecs, json, sys, csv, re, requests +from localcache2 import user_from_goo +from canvas_secrets import url +from pipelines import fetch +from users import getEmail def user_db_sync(): @@ -173,6 +177,7 @@ def correct_dup_user_rows(): print(f"UPDATE conf_signups SET user={preferred['id']} WHERE user={NP['id']};") print(f"UPDATE conf_answers SET user={preferred['id']} WHERE user={NP['id']};") print(f"UPDATE conf_hosts SET host={preferred['id']} WHERE host={NP['id']};") + print(f"DELETE FROM conf_users WHERE id={NP['id']};") # SELECT * FROM conf_answers where user=1142 # SELECT * FROM conf_hosts where host=1142 @@ -186,11 +191,80 @@ def sort_id(a): return int(a['id']) - +def search_user(searchterm=''): + if not searchterm: + searchterm = input('search term: ') + u = url + f"/api/v1/accounts/self/users?search_term={searchterm}" + response = fetch(u) + for R in response: + R['email'] = getEmail(R['id']) + #print(json.dumps(response, indent=2)) + return response + +def search_and_select_user(searchterm): + candidates = search_user(searchterm) + if len(candidates) == 1: return candidates[0] + + for i,c in enumerate(candidates): + print(f" {i+1}: {c['name']} \t {c['sis_user_id']} \t {c['email']} \t {c['created_at']}") + choice = int(input('which user (0 for none)? ')) + if choice == 0: return 0 + return candidates[choice-1] + +def find_unnamed_people(): + + if 0: + suffix = "_20220907" + ilearn_users = json.loads( codecs.open(f'cache/allusers{suffix}.json','r','utf-8').read() ) + ilu_by_goo = {} + for U in ilearn_users: + if 'sis_user_id' in U and U['sis_user_id']: + g = U['sis_user_id'] + g = g[3:] + ilu_by_goo[g] = U + #print(json.dumps(ilu_by_goo,indent=2)) + outfile = codecs.open(f'cache/allusers_by_goo{suffix}.json','w','utf-8') + outfile.write( json.dumps(ilu_by_goo,indent=2)) + + # get conf_users from flex day site + url = "http://hhh.gavilan.edu/phowell/dir/api2.php?query=users" + all_users = json.loads(requests.get(url, verify=False).content) + unfixed = [] + unfound_goos = [] + for A in all_users['data']: + if A['name'] == "": + found_name = "*" + record = user_from_goo(A['goo']) + if record and 'name' in record: + #print(record) + #if A['goo'] in ilu_by_goo: + #found_name = ilu_by_goo[A['goo']]['name'] + found_name = record['name'] + desc = f"Goo: {A['goo']}\t email: {A['email']} \t new name: {found_name}" + if found_name != '*': + print(f"UPDATE conf_users SET name='{found_name}' WHERE goo='{A['goo']}';") + else: + unfixed.append(desc) + unfound_goos.append(A['goo']) + print() + + queries = [] + for i,g in enumerate(unfound_goos): + print(g) + choice = search_and_select_user(g) + if choice != 0: + qry = f"UPDATE conf_users SET name='{choice['name']}' WHERE goo='{g}';" + queries.append(qry) + print() + for Q in queries: + print(Q) + if __name__ == "__main__": print ("") options = { 1: ['(old) sync conf_user and iLearn employee tables', user_db_sync2] , 2: ['generate sql to fix conf_user dups', correct_dup_user_rows] , + 3: ['add names to new accounts', find_unnamed_people], + 4: ['search for user', search_user], } diff --git a/localcache2.py b/localcache2.py index 202196a..b98e59b 100644 --- a/localcache2.py +++ b/localcache2.py @@ -124,6 +124,17 @@ def all_gav_employees(): ''' +def user_from_goo(goo): + goo = "G00" + goo + q = f"SELECT * FROM canvas.pseudonyms p JOIN canvas.users u ON p.user_id=u.id WHERE p.sis_user_id='{goo}';" + (connection,cursor) = db() + cursor.execute(q, None) # execute query with optional parameters + row = cursor.fetchone() # fetch a single row + if row: + # convert row to dict using column names as keys + return dict(zip([desc[0] for desc in cursor.description], row)) + + def course_from_id(id): q = f"SELECT * FROM canvas.courses c WHERE c.id={id}" (connection,cursor) = db() @@ -267,10 +278,11 @@ ORDER BY num DESC, u.sortable_name""" % (where1,where2) def all_sem_courses_teachers(SEM="202450"): - q = f"""SELECT c.id, c.name, c.course_code, u.name, u.sortable_name, u.id AS user_cid, p.sis_user_id FROM canvas.courses AS c + q = f"""SELECT c.id, c.name, c.course_code, u.name, u.sortable_name, u.id AS user_cid, p.sis_user_id, s.type, s.crn FROM canvas.courses AS c JOIN canvas.enrollments AS e ON e.course_id=c.id JOIN canvas.users AS u ON u.id=e.user_id JOIN canvas.pseudonyms AS p ON p.user_id=u.id +JOIN canvas.schedule as s on c.id=s.canvascourse WHERE c.sis_source_id LIKE '{SEM}-%' AND NOT c.workflow_state='deleted' AND e.type='TeacherEnrollment' diff --git a/users.py b/users.py index c192135..0f8c9f0 100644 --- a/users.py +++ b/users.py @@ -2230,14 +2230,15 @@ def cross_ref_training(): alldepts = set() - courses = all_2x_sem_courses_teachers('202450', '202470') # all_sem_courses_teachers() + # courses = all_2x_sem_courses_teachers('202450', '202470') # + courses = all_sem_courses_teachers('202470') for c in courses: print(c) - goo = c[8] - crn = c[4] - name = c[2] - teacher = c[5] - ctype = c[3] + goo = c[6] + crn = c[8] + name = c[1] # full course name + teacher = c[4] # last, first + ctype = c[7] dept1 = re.search(r'([A-Z]+)(\d+)',c[2].split(' ')[0]).group(1) alldepts.add(dept1) d = list(c) @@ -2276,12 +2277,13 @@ def cross_ref_training(): r += 1 for t in teachers_bydept[D]: - if t == 'STAFF STAFF': continue + if t == 'STAFF, STAFF': continue completed = 0 waived = 0 sects = teachers[t] print(f"Sections for {t}: {sects}") - goo = sects[0][8] + goo = sects[0][6] + course_mode = sects[0][7] print(t) sheet.cell(row=r, column=1).value = f"{t}" sheet.cell(row=r, column=2).value = f"{goo}" @@ -2321,7 +2323,7 @@ def cross_ref_training(): else: sheet.cell(row=r, column=2).value = f"- MISSING GOTT 1" sheet.cell(row=r-1,column=1).fill = flagfont - report.write(f"\tMISSING GOTT 1: {t}\n") + report.write(f"\tMISSING GOTT 1: {t} {goo}\n") r += 1 if goo in records['GOTT4']: sheet.cell(row=r, column=2).value = f"✓ GOTT 4 Trained" @@ -2357,7 +2359,7 @@ def cross_ref_training(): r += 1 if (not completed) and (not waived): - report.write(f"\t\t{s[3]}\t{s[1]}\n") + report.write(f"\t\t{s[3]}\t{s[1]}\t{s[7]}\n") if (not completed) and (not waived): report.write(f"\n") @@ -2537,7 +2539,7 @@ if __name__ == "__main__": 19: ['NLP Sample', nlp_sample], 20: ['Enroll a single user into a class', one_course_enrol], 21: ['Teachers new this semester', find_new_teachers], - 22: ['Sync personnel and conference user databases', user_db_sync], + #22: ['Sync personnel and conference user databases', user_db_sync], 23: ['Find non-gnumbers', find_no_goo ], 24: ['compare user tables', compare_db_tables], 25: ['cross ref training', cross_ref_training],