from django_future.csrf import ensure_csrf_cookie from django.views.decorators.http import require_POST from django.contrib.auth.models import User from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.urlresolvers import reverse from django.http import HttpResponse import json import logging import re from courseware.courses import get_course_with_access from mitxmako.shortcuts import render_to_response from . import cohorts log = logging.getLogger(__name__) def json_http_response(data): """ Return an HttpResponse with the data json-serialized and the right content type header. """ return HttpResponse(json.dumps(data), content_type="application/json") def split_by_comma_and_whitespace(s): """ Split a string both by commas and whitespice. Returns a list. """ return re.split(r'[\s,]+', s) @ensure_csrf_cookie def list_cohorts(request, course_id): """ Return json dump of dict: {'success': True, 'cohorts': [{'name': name, 'id': id}, ...]} """ get_course_with_access(request.user, course_id, 'staff') all_cohorts = [{'name': c.name, 'id': c.id} for c in cohorts.get_course_cohorts(course_id)] return json_http_response({'success': True, 'cohorts': all_cohorts}) @ensure_csrf_cookie @require_POST def add_cohort(request, course_id): """ Return json of dict: {'success': True, 'cohort': {'id': id, 'name': name}} or {'success': False, 'msg': error_msg} if there's an error """ get_course_with_access(request.user, course_id, 'staff') name = request.POST.get("name") if not name: return json_http_response({'success': False, 'msg': "No name specified"}) try: cohort = cohorts.add_cohort(course_id, name) except ValueError as err: return json_http_response({'success': False, 'msg': str(err)}) return json_http_response({'success': 'True', 'cohort': { 'id': cohort.id, 'name': cohort.name }}) @ensure_csrf_cookie def users_in_cohort(request, course_id, cohort_id): """ Return users in the cohort. Show up to 100 per page, and page using the 'page' GET attribute in the call. Format: Returns: Json dump of dictionary in the following format: {'success': True, 'page': page, 'num_pages': paginator.num_pages, 'users': [{'username': ..., 'email': ..., 'name': ...}] } """ get_course_with_access(request.user, course_id, 'staff') # this will error if called with a non-int cohort_id. That's ok--it # shoudn't happen for valid clients. cohort = cohorts.get_cohort_by_id(course_id, int(cohort_id)) paginator = Paginator(cohort.users.all(), 100) page = request.GET.get('page') try: users = paginator.page(page) except PageNotAnInteger: # return the first page page = 1 users = paginator.page(page) except EmptyPage: # Page is out of range. Return last page page = paginator.num_pages contacts = paginator.page(page) user_info = [{'username': u.username, 'email': u.email, 'name': '{0} {1}'.format(u.first_name, u.last_name)} for u in users] return json_http_response({'success': True, 'page': page, 'num_pages': paginator.num_pages, 'users': user_info}) @ensure_csrf_cookie @require_POST def add_users_to_cohort(request, course_id, cohort_id): """ Return json dict of: {'success': True, 'added': [{'username': username, 'name': name, 'email': email}, ...], 'conflict': [{'username_or_email': ..., 'msg': ...}], # in another cohort 'present': [str1, str2, ...], # already there 'unknown': [str1, str2, ...]} """ get_course_with_access(request.user, course_id, 'staff') cohort = cohorts.get_cohort_by_id(course_id, cohort_id) users = request.POST.get('users', '') added = [] present = [] conflict = [] unknown = [] for username_or_email in split_by_comma_and_whitespace(users): try: user = cohorts.add_user_to_cohort(cohort, username_or_email) added.append({'username': user.username, 'name': "{0} {1}".format(user.first_name, user.last_name), 'email': user.email, }) except ValueError: present.append(username_or_email) except User.DoesNotExist: unknown.append(username_or_email) except cohorts.CohortConflict as err: conflict.append({'username_or_email': username_or_email, 'msg': str(err)}) return json_http_response({'success': True, 'added': added, 'present': present, 'conflict': conflict, 'unknown': unknown}) @ensure_csrf_cookie @require_POST def remove_user_from_cohort(request, course_id, cohort_id): """ Expects 'username': username in POST data. Return json dict of: {'success': True} or {'success': False, 'msg': error_msg} """ get_course_with_access(request.user, course_id, 'staff') username = request.POST.get('username') if username is None: return json_http_response({'success': False, 'msg': 'No username specified'}) cohort = cohorts.get_cohort_by_id(course_id, cohort_id) try: user = User.objects.get(username=username) cohort.users.remove(user) return json_http_response({'success': True}) except User.DoesNotExist: log.debug('no user') return json_http_response({'success': False, 'msg': "No user '{0}'".format(username)}) def debug_cohort_mgmt(request, course_id): """ Debugging view for dev. """ # add staff check to make sure it's safe if it's accidentally deployed. get_course_with_access(request.user, course_id, 'staff') context = {'cohorts_ajax_url': reverse('cohorts', kwargs={'course_id': course_id})} return render_to_response('/course_groups/debug.html', context)