Skip to content

Instantly share code, notes, and snippets.

@jnm
Created February 18, 2016 20:19
Show Gist options
  • Save jnm/ea06626ab51ce61e044a to your computer and use it in GitHub Desktop.
Save jnm/ea06626ab51ce61e044a to your computer and use it in GitHub Desktop.
import requests
import sys
import xml
import hashlib
import getpass
import datetime
from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.models import User
from reporter.models import Rendering
LOCAL_USER_FIELDS = (
'first_name',
'last_name',
'username',
'date_joined',
'last_login',
'email'
)
KC_PROFILE_FIELDS = ('organization',)
RENDERING_FIELDS = ('created', 'submission_count()', 'template__name')
KC_PROFILE_ENDPOINT = '{}/api/v1/profiles'.format(settings.KC_URL)
KC_FORM_ENDPOINT = '{}/api/v1/forms'.format(settings.KC_URL)
def print_tabular(list_of_dicts):
# TODO: Handle data that includes tab characters
if not len(list_of_dicts):
return
print '\t'.join(list_of_dicts[0].keys())
for r in list_of_dicts:
print '\t'.join(r.values())
def render_field(obj, field_name):
if field_name.endswith('()'):
is_method = True
field_name = field_name[:-2]
else:
is_method = False
field = get_related_field(obj, field_name)
if is_method:
field = field()
if type(field) is datetime.datetime:
# Excel compatibility
return field.strftime('%Y-%m-%d %H:%M:%S')
else:
return str(field)
def get_related_field(obj, field_name):
# Is there really not a Django utility function for this?
path = field_name.split('__')
field = obj
for p in path:
field = getattr(field, p)
return field
def user_report():
sys.stderr.write('Loading profiles from KC...')
kc_response = requests.get(KC_PROFILE_ENDPOINT)
kc_profiles = {p['username']: p for p in kc_response.json()}
sys.stderr.write(' Done!\n')
user_report = []
for user in User.objects.all():
row = OrderedDict()
try:
profile = kc_profiles[user.username]
except KeyError:
sys.stdout.write(u'No profile for {}!\n'.format(user.username))
profile = None
for f in LOCAL_USER_FIELDS:
row[f] = render_field(user, f)
for f in KC_PROFILE_FIELDS:
if profile is not None:
row[f] = profile[f]
else:
row[f] = str(None)
user_report.append(row)
print_tabular(user_report)
def project_report():
print 'Please log in with a KC superuser.'
kc_super_username = raw_input('Username: ')
kc_super_password = getpass.getpass()
project_report = []
sys.stderr.write('Processing projects')
for rendering in Rendering.objects.all():
# Get a MD5 sum of the XML body of the KC form, hopefully to ease
# identification. Once `Rendering` is changed to include which `Form`
# was used, this won't be necessary
parsed_url = urlparse(rendering.url)
numeric_id = int(parsed_url.path.split('/')[-1])
xml_url = '{}/{}/form.xml'.format(KC_FORM_ENDPOINT, numeric_id)
kc_response = requests.get(
xml_url, auth=(kc_super_username, kc_super_password))
if kc_response.status_code != requests.codes.ok:
sys.stderr.write(
'\nHTTP {}: Failed to get XML for form {}!\n'.format(
kc_response.status_code, numeric_id)
)
form_md5 = str(None)
form_title = str(None)
else:
root_el = xml.etree.ElementTree.fromstring(kc_response.content)
# Yo dawg, I heard you liked XML...
root_el = xml.etree.ElementTree.fromstring(
root_el.text.encode('utf-8'))
body_el = root_el.find('{http://www.w3.org/1999/xhtml}body')
form_md5 = hashlib.md5(
''.join(body_el.itertext()).encode('utf-8')
).hexdigest()
# There are better ways to get the title, but since we already have
# the XML...
title_el = root_el.find('.//{http://www.w3.org/1999/xhtml}title')
form_title = title_el.text
sys.stderr.write('.')
#######################################################################
row = OrderedDict()
row['md5'] = form_md5
row['title'] = form_title
for f in RENDERING_FIELDS:
row[f] = render_field(rendering, f)
project_report.append(row)
sys.stderr.write('\n')
print_tabular(project_report)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment