Created
August 18, 2017 20:47
-
-
Save ryanlovett/ef7ce2611fa4ae8e16517ccc57a222b8 to your computer and use it in GitHub Desktop.
Get the official campus emails for students in a Berkeley course
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
#!/usr/bin/python | |
# Example usage: | |
# $0 -H headers.json -s compsci -c c8 | |
# $0 -H headers.json -s stat -c c100 | |
import sys | |
import os | |
import json | |
import requests | |
import argparse | |
def get_descriptors(uri, params, headers): | |
'''Get SIS descriptor IDs.''' | |
r = requests.get(uri, params=params, headers=headers) | |
data = r.json() | |
return data['apiResponse']['response']['fieldValues'] | |
def extract_lecture_codes(sections): | |
return list( | |
map(lambda x: x['code'], | |
filter(lambda x: ' LEC ' in x['description'], sections) | |
) | |
) | |
def get_enrollments(uri, params, headers): | |
if args.verbose: | |
print("get_enrollments: {} {}".format(uri, params)) | |
r = requests.get(uri, params=params, headers=headers) | |
if r.status_code == 404: | |
if args.debug: print('No more enrollments') | |
# there is no more data | |
return [] | |
data = r.json() | |
# Return if there is no response (e.g. 404) | |
if 'response' not in data['apiResponse']: | |
if args.debug: print('404 No response') | |
print('404 No response') | |
return[] | |
# Return if the UID has no enrollments | |
if 'classSectionEnrollments' not in data['apiResponse']['response']: | |
if args.debug: print('No enrollments') | |
print('No enrollments') | |
return [] | |
enrollments = \ | |
data['apiResponse']['response']['classSectionEnrollments'] | |
params['page-number'] += 1 | |
enrollments += get_enrollments(uri, params, headers) | |
if args.debug: print('enrollments batch: {}'.format(len(enrollments))) | |
return enrollments | |
def enrollment_emails(enrollments): | |
'''Extract unique student emails from enrollments.''' | |
emails = set() | |
for e in enrollments: | |
for identifier in e['student']['identifiers']: | |
for email in e['student']['emails']: | |
if email['type']['code'] == 'CAMP': | |
emails.add(email['emailAddress']) | |
break | |
return emails | |
## MAIN | |
# there's an api for this too | |
TERM_FALL_2016 = 2168 | |
TERM_SPRING_2017 = 2172 | |
TERM_SUMMER_2017 = 2178 | |
TERM_FALL_2017 = 2178 | |
SUBJECT_AREA = 'STAT' | |
# Headers file contains requests json. Example: | |
# { "Accept": "application/json", | |
# "app_id": "YOUR_SIS_APP_ID", | |
# "app_key": "YOUR_SIS_APP_KEY" } | |
HEADERS_FILE = 'fetch-enrollments.json' | |
parser = argparse.ArgumentParser(description="Print enrolled students' email addresses.") | |
parser.add_argument('-t', dest='term_id', type=int, default=TERM_FALL_2017, | |
help='SIS Term ID (default=%(default)s)') | |
parser.add_argument('-s', dest='sa_filter', default=SUBJECT_AREA, | |
help='subject area filter (default=%(default)s)') | |
parser.add_argument('-c', dest='course', default='', | |
help='Course number, e.g. c8, 133, 135') | |
parser.add_argument('-H', dest='headers_file', default=HEADERS_FILE, | |
help='JSON file containing requests headers') | |
parser.add_argument('-v', dest='verbose', action='store_true', help='Be verbose.') | |
parser.add_argument('-d', dest='debug', action='store_true', help='Debug.') | |
args = parser.parse_args() | |
## main | |
# api secrets | |
headers = json.loads(open(args.headers_file).read()) | |
enrollments_uri = "https://apis.berkeley.edu/sis/v2/enrollments" | |
descriptors_uri = enrollments_uri + '/terms/{}/classes/sections/descriptors' | |
sections_uri = enrollments_uri + "/terms/{}/classes/sections/{}" | |
params = { | |
"subject-area-code": args.sa_filter, | |
"catalog-number": args.course, | |
} | |
# Retrieve the "section IDs" associated with the course. | |
# This gets both lecture and sections. | |
uri = descriptors_uri.format(args.term_id) | |
sections = get_descriptors(uri, params, headers) | |
# We only care about the lecture. | |
lecture_codes = extract_lecture_codes(sections) | |
# Get the enrollments | |
params['page-number'] = 1 | |
params['page-size'] = 100 | |
enrollments = [] | |
for lecture_code in lecture_codes: | |
uri = sections_uri.format(args.term_id, lecture_code) | |
enrollments += get_enrollments(uri, params, headers) | |
# Get the emails | |
emails = enrollment_emails(enrollments) | |
print('\n'.join(e for e in emails)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment