<commit_before>"""
CME Registration methods
"""

import json
import logging
from statsd import statsd

from django_future.csrf import ensure_csrf_cookie
from django.conf import settings
from django.core.validators import validate_email, validate_slug, ValidationError
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.contrib.auth import authenticate, login
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
from django.db import IntegrityError
from django.core.mail import send_mail

from student.models import Registration
from cme_registration.models import CmeUserProfile
from mitxmako.shortcuts import render_to_response, render_to_string


log = logging.getLogger("mitx.student")


@ensure_csrf_cookie
def cme_register_user(request, extra_context=None):
    """
    This view will display the non-modal registration form which has been customised
    from the standard registration form for CME.
    """
    if request.user.is_authenticated():
        return redirect(reverse('dashboard'))

    context = {
        'course_id': request.GET.get('course_id'),
        'enrollment_action': request.GET.get('enrollment_action'),
        'patient_population_choices': PATIENT_POPULATION_CHOICES,
        'specialty_choices': SPECIALTY_CHOICES,
        'sub_specialty_choices': SUB_SPECIALTY_CHOICES
    }
    if extra_context is not None:
        context.update(extra_context)

    return render_to_response('cme_register.html', context)


@ensure_csrf_cookie
def cme_create_account(request, post_override=None):
    '''
    JSON call to create new edX account; modified for the CME registration form.
    Used by form in signup_modal.html, which is included into navigation.html
    '''
    json_string = {'success': False}

    post_vars = post_override if post_override else request.POST

    # Confirm we have a properly formed request
    for var in ['username', 'email', 'password', 'name']:
        if var not in post_vars:
            json_string['value'] = "Error (401 {field}). E-mail us.".format(field=var)
            json_string['field'] = var
            return HttpResponse(json.dumps(json_string))

    #Validate required felds
    error = validate_required_fields(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate required check boxes
    error = validate_required_boxes(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate required radio buttons
    error = validate_required_radios(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate required secondary fields
    error = validate_required_secondaries(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate email address
    try:
        validate_email(post_vars['email'])
    except ValidationError:
        json_string['value'] = "Valid e-mail is required."
        json_string['field'] = 'email'
        return HttpResponse(json.dumps(json_string))

    #Validate username conforms
    try:
        validate_slug(post_vars['username'])
    except ValidationError:
        json_string['value'] = "Username should only consist of A-Z and 0-9, with no spaces."
        json_string['field'] = 'username'
        return HttpResponse(json.dumps(json_string))

    # Ok, looks like everything is legit.  Create the account.
    ret = _do_cme_create_account(post_vars)
    if isinstance(ret, HttpResponse):  # if there was an error then return that
        return ret
    (user, cme_user_profile, registration) = ret

    email_dict = {
        'name': post_vars['name'],
        'key': registration.activation_key,
    }

    # composes activation email
    subject = render_to_string('emails/activation_email_subject.txt', email_dict)
    # Email subject *must not* contain newlines
    subject = ''.join(subject.splitlines())
    message = render_to_string('emails/activation_email.txt', email_dict)

    try:
        if settings.MITX_FEATURES.get('REROUTE_ACTIVATION_EMAIL'):
            dest_addr = settings.MITX_FEATURES['REROUTE_ACTIVATION_EMAIL']
            message = ("Activation for %s (%s): %s\n" % (user, user.email, cme_user_profile.name) +
                       '-' * 80 + '\n\n' + message)
            send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False)
        else:
            user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
    except:
        log.warning('Unable to send activation email to user', exc_info=True)
        json_string['value'] = 'Could not send activation e-mail.'
        return HttpResponse(json.dumps(json_string))

    # Immediately after a user creates an account, we log them in. They are only
    # logged in until they close the browser. They can't log in again until they click
    # the activation link from the email.
    login_user = authenticate(username=post_vars['username'], password=post_vars['password'])
    login(request, login_user)
    request.session.set_expiry(0)

    statsd.increment("common.student.account_created")

    json_string = {'success': True}
    HttpResponse(json.dumps(json_string), mimetype="application/json")

    response = HttpResponse(json.dumps({'success': True}))
    return response


def _do_cme_create_account(post_vars):
    """
    Given cleaned post variables, create the User, UserProfile and CmeUserProfile objects, as well as the
    registration for this user.

    Returns a tuple (User, CmeUserProfile, Registration).
    Since CmeUserProfile is implemented using multi-table inheritence of UserProfile, the CmeUserProfile object
    will also contain all the UserProfile fields.
    """
    user = User(username=post_vars['username'],
                email=post_vars['email'],
                is_active=False)
    user.set_password(post_vars['password'])
    registration = Registration()
    # @todo: Rearrange so that if part of the process fails, the whole process fails.
    # Right now, we can have e.g. no registration e-mail sent out and a zombie account
    try:
        user.save()
    except IntegrityError:
        json_string = {'success': False}
        # Figure out the cause of the integrity error
        if len(User.objects.filter(username=post_vars['username'])) > 0:
            json_string['value'] = "An account with the Public Username  '" + post_vars['username'] + "' already exists."
            json_string['field'] = 'username'
            return HttpResponse(json.dumps(json_string))

        if len(User.objects.filter(email=post_vars['email'])) > 0:
            json_string['value'] = "An account with the Email '" + post_vars['email'] + "' already exists."
            json_string['field'] = 'email'
            return HttpResponse(json.dumps(json_string))

    registration.register(user)

    cme_user_profile = CmeUserProfile(user=user)

    #UserProfile fields
    cme_user_profile.name = post_vars['name']

    #CmeUserProfile fields
    cme_user_profile.profession = post_vars.get('profession')
    cme_user_profile.professional_designation = post_vars.get('professional_designation')
    cme_user_profile.license_number = post_vars.get('license_number')
    cme_user_profile.organization = post_vars.get('organization')
    cme_user_profile.stanford_affiliated = True if post_vars.get('stanford_affiliated') == '1' else False

    if post_vars.get('how_stanford_affiliated') == 'Other':
        cme_user_profile.how_stanford_affiliated = post_vars.get('how_stanford_affiliated_free')
    else:
        cme_user_profile.how_stanford_affiliated = post_vars.get('how_stanford_affiliated')

    cme_user_profile.patient_population = post_vars.get('patient_population')

    if post_vars.get('specialty') == 'Other':
        cme_user_profile.specialty = post_vars.get('specialty_free')
    else:
        cme_user_profile.specialty = post_vars.get('specialty')

    if post_vars.get('sub_specialty') == 'Other':
        cme_user_profile.sub_specialty = post_vars.get('sub_specialty_free')
    else:
        cme_user_profile.sub_specialty = post_vars.get('sub_specialty')

    cme_user_profile.address_1 = post_vars.get('address_1')
    cme_user_profile.address_2 = post_vars.get('address_2')
    cme_user_profile.city = post_vars.get('city')
    cme_user_profile.state_province = post_vars.get('state_province')
    cme_user_profile.postal_code = post_vars.get('postal_code')
    cme_user_profile.country = post_vars.get('country')
    cme_user_profile.phone_number = post_vars.get('phone_number')
    cme_user_profile.extension = post_vars.get('extension')
    cme_user_profile.fax = post_vars.get('fax')

    if post_vars.get('hear_about_us') == 'Other':
        cme_user_profile.hear_about_us = post_vars.get('hear_about_us_free')
    else:
        cme_user_profile.hear_about_us = post_vars.get('hear_about_us')

    cme_user_profile.mailing_list = 1 if post_vars.get('mailing_list') == 'true' else 0

    try:
        cme_user_profile.save()

    except Exception:
        log.exception("UserProfile creation failed for user {0}.".format(user.email))
    return (user, cme_user_profile, registration)


def validate_required_fields(post_vars):
    """
    Checks that required free text fields contain at least 2 chars
    `post_vars` is dict of post parameters (a `dict`)
    Returns a dict indicating failure, field and message on empty field else None
    """

    #Add additional required fields here
    required_fields_dict = {'username': 'Username must be minimum of two characters long.',
                            'email': 'A properly formatted e-mail is required.',
                            'name': 'Your legal name must be a minimum of two characters long.',
                            'password': '<PASSWORD>.',
                            'profession': 'Choose your profession.',
                            'license_number': 'Enter your license number.',
                            'patient_population': 'Choose your patient population',
                            'specialty': 'Choose your specialty',
                            'address_1': 'Enter your Address 01',
                            'city': 'Enter your city',
                            'state_province': 'Choose your state/Province',
                            'postal_code': 'Enter your postal code',
                            'country': 'Choose your country',
                            'phone_number': 'Enter your phone number',
                            'hear_about_us': 'Choose how you heard about us'
                            }

    error = {}
    for k, val in required_fields_dict.items():
        if len(post_vars.get(k)) < 2:
            error['success'] = False
            error['value'] = val
            error['field'] = k
            return error


def validate_required_boxes(post_vars):
    """
    Checks that required check boxes are checked
    `post_vars is dict of post parameters (a `dict)
    Returns a dict indicating failure, field and message on empty field else None
    """

    #Add additional required boxes here
    required_boxes_dict = {'terms_of_service': 'You must accept the terms of service.',
                           'honor_code': 'To enroll, you must follow the honor code.',
                           }
<commit_msg>Fixed ordering of required fields on registration page to be more user friendly.<commit_after>"""
CME Registration methods
"""

import json
import logging
from statsd import statsd

from django_future.csrf import ensure_csrf_cookie
from django.conf import settings
from django.core.validators import validate_email, validate_slug, ValidationError
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.contrib.auth import authenticate, login
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
from django.db import IntegrityError
from django.core.mail import send_mail

from student.models import Registration
from cme_registration.models import CmeUserProfile
from mitxmako.shortcuts import render_to_response, render_to_string


log = logging.getLogger("mitx.student")


@ensure_csrf_cookie
def cme_register_user(request, extra_context=None):
    """
    This view will display the non-modal registration form which has been customised
    from the standard registration form for CME.
    """
    if request.user.is_authenticated():
        return redirect(reverse('dashboard'))

    context = {
        'course_id': request.GET.get('course_id'),
        'enrollment_action': request.GET.get('enrollment_action'),
        'patient_population_choices': PATIENT_POPULATION_CHOICES,
        'specialty_choices': SPECIALTY_CHOICES,
        'sub_specialty_choices': SUB_SPECIALTY_CHOICES
    }
    if extra_context is not None:
        context.update(extra_context)

    return render_to_response('cme_register.html', context)


@ensure_csrf_cookie
def cme_create_account(request, post_override=None):
    '''
    JSON call to create new edX account; modified for the CME registration form.
    Used by form in signup_modal.html, which is included into navigation.html
    '''
    json_string = {'success': False}

    post_vars = post_override if post_override else request.POST

    # Confirm we have a properly formed request
    for var in ['username', 'email', 'password', 'name']:
        if var not in post_vars:
            json_string['value'] = "Error (401 {field}). E-mail us.".format(field=var)
            json_string['field'] = var
            return HttpResponse(json.dumps(json_string))

    #Validate required felds
    error = validate_required_fields(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate required check boxes
    error = validate_required_boxes(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate required radio buttons
    error = validate_required_radios(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate required secondary fields
    error = validate_required_secondaries(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    #Validate email address
    try:
        validate_email(post_vars['email'])
    except ValidationError:
        json_string['value'] = "Valid e-mail is required."
        json_string['field'] = 'email'
        return HttpResponse(json.dumps(json_string))

    #Validate username conforms
    try:
        validate_slug(post_vars['username'])
    except ValidationError:
        json_string['value'] = "Username should only consist of A-Z and 0-9, with no spaces."
        json_string['field'] = 'username'
        return HttpResponse(json.dumps(json_string))

    # Ok, looks like everything is legit.  Create the account.
    ret = _do_cme_create_account(post_vars)
    if isinstance(ret, HttpResponse):  # if there was an error then return that
        return ret
    (user, cme_user_profile, registration) = ret

    email_dict = {
        'name': post_vars['name'],
        'key': registration.activation_key,
    }

    # composes activation email
    subject = render_to_string('emails/activation_email_subject.txt', email_dict)
    # Email subject *must not* contain newlines
    subject = ''.join(subject.splitlines())
    message = render_to_string('emails/activation_email.txt', email_dict)

    try:
        if settings.MITX_FEATURES.get('REROUTE_ACTIVATION_EMAIL'):
            dest_addr = settings.MITX_FEATURES['REROUTE_ACTIVATION_EMAIL']
            message = ("Activation for %s (%s): %s\n" % (user, user.email, cme_user_profile.name) +
                       '-' * 80 + '\n\n' + message)
            send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False)
        else:
            user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
    except:
        log.warning('Unable to send activation email to user', exc_info=True)
        json_string['value'] = 'Could not send activation e-mail.'
        return HttpResponse(json.dumps(json_string))

    # Immediately after a user creates an account, we log them in. They are only
    # logged in until they close the browser. They can't log in again until they click
    # the activation link from the email.
    login_user = authenticate(username=post_vars['username'], password=post_vars['password'])
    login(request, login_user)
    request.session.set_expiry(0)

    statsd.increment("common.student.account_created")

    json_string = {'success': True}
    HttpResponse(json.dumps(json_string), mimetype="application/json")

    response = HttpResponse(json.dumps({'success': True}))
    return response


def _do_cme_create_account(post_vars):
    """
    Given cleaned post variables, create the User, UserProfile and CmeUserProfile objects, as well as the
    registration for this user.

    Returns a tuple (User, CmeUserProfile, Registration).
    Since CmeUserProfile is implemented using multi-table inheritence of UserProfile, the CmeUserProfile object
    will also contain all the UserProfile fields.
    """
    user = User(username=post_vars['username'],
                email=post_vars['email'],
                is_active=False)
    user.set_password(post_vars['password'])
    registration = Registration()
    # @todo: Rearrange so that if part of the process fails, the whole process fails.
    # Right now, we can have e.g. no registration e-mail sent out and a zombie account
    try:
        user.save()
    except IntegrityError:
        json_string = {'success': False}
        # Figure out the cause of the integrity error
        if len(User.objects.filter(username=post_vars['username'])) > 0:
            json_string['value'] = "An account with the Public Username  '" + post_vars['username'] + "' already exists."
            json_string['field'] = 'username'
            return HttpResponse(json.dumps(json_string))

        if len(User.objects.filter(email=post_vars['email'])) > 0:
            json_string['value'] = "An account with the Email '" + post_vars['email'] + "' already exists."
            json_string['field'] = 'email'
            return HttpResponse(json.dumps(json_string))

    registration.register(user)

    cme_user_profile = CmeUserProfile(user=user)

    #UserProfile fields
    cme_user_profile.name = post_vars['name']

    #CmeUserProfile fields
    cme_user_profile.profession = post_vars.get('profession')
    cme_user_profile.professional_designation = post_vars.get('professional_designation')
    cme_user_profile.license_number = post_vars.get('license_number')
    cme_user_profile.organization = post_vars.get('organization')
    cme_user_profile.stanford_affiliated = True if post_vars.get('stanford_affiliated') == '1' else False

    if post_vars.get('how_stanford_affiliated') == 'Other':
        cme_user_profile.how_stanford_affiliated = post_vars.get('how_stanford_affiliated_free')
    else:
        cme_user_profile.how_stanford_affiliated = post_vars.get('how_stanford_affiliated')

    cme_user_profile.patient_population = post_vars.get('patient_population')

    if post_vars.get('specialty') == 'Other':
        cme_user_profile.specialty = post_vars.get('specialty_free')
    else:
        cme_user_profile.specialty = post_vars.get('specialty')

    if post_vars.get('sub_specialty') == 'Other':
        cme_user_profile.sub_specialty = post_vars.get('sub_specialty_free')
    else:
        cme_user_profile.sub_specialty = post_vars.get('sub_specialty')

    cme_user_profile.address_1 = post_vars.get('address_1')
    cme_user_profile.address_2 = post_vars.get('address_2')
    cme_user_profile.city = post_vars.get('city')
    cme_user_profile.state_province = post_vars.get('state_province')
    cme_user_profile.postal_code = post_vars.get('postal_code')
    cme_user_profile.country = post_vars.get('country')
    cme_user_profile.phone_number = post_vars.get('phone_number')
    cme_user_profile.extension = post_vars.get('extension')
    cme_user_profile.fax = post_vars.get('fax')

    if post_vars.get('hear_about_us') == 'Other':
        cme_user_profile.hear_about_us = post_vars.get('hear_about_us_free')
    else:
        cme_user_profile.hear_about_us = post_vars.get('hear_about_us')

    cme_user_profile.mailing_list = 1 if post_vars.get('mailing_list') == 'true' else 0

    try:
        cme_user_profile.save()

    except Exception:
        log.exception("UserProfile creation failed for user {0}.".format(user.email))
    return (user, cme_user_profile, registration)


def validate_required_fields(post_vars):
    """
    Checks that required free text fields contain at least 2 chars
    `post_vars` is dict of post parameters (a `dict`)
    Returns a dict indicating failure, field and message on empty field else None
    """

    #Add additional required fields here
    required_fields_list = [{'email': 'A properly formatted e-mail is required.'},
                            {'password': '<PASSWORD>.'},
                            {'username': 'Username must be minimum of two characters long.'},
                            {'name': 'Your legal name must be a minimum of two characters long.'},
                            {'profession': 'Choose your profession.'},
                            {'license_number': 'Enter your license number.'},
                            {'patient_population': 'Choose your patient population'},
                            {'specialty': 'Choose your specialty'},
                            {'address_1': 'Enter your Address 01'},
                            {'city': 'Enter your city'},
                            {'state_province': 'Choose your state/Province'},
                            {'postal_code': 'Enter your postal code'},
                            {'country': 'Choose your country'},
                            {'phone_number': 'Enter your phone number'},
                            {'hear_about_us': 'Choose how you heard about us'}
                           ]

    error = {}
    for required_field in required_fields_list:
        for key, val in required_field.iteritems():   
            if len(post_vars.get(key)) < 2:
                error['success'] = False
                error['value'] = val
                error['field'] = key
                return error


def validate_required_boxes(post_vars):
    """
    Checks that required check boxes are checked
    `post_vars is dict of post parameters (a `dict)
    Returns a dict indicating failure, field and message on empty field else None
    """

    #Add additional required boxes here
    required_boxes_dict = {'terms_of_service': 'You must accept the terms of service.',
                           'honor_code': 'To enroll, you must follow the honor code.',
                           }

{'fraction_non_alphanumeric': 0.09564117108076269, 'fraction_numerical': 0.002007068371220385, 'mean_word_length': 3.128242074927954, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1448829', 'n_tokens_mistral': 6639, 'n_tokens_neox': 6432, 'n_words': 1688}