From e32dfcf0a0f20ed611d881959ef7c16da965bc9b Mon Sep 17 00:00:00 2001 From: Brian Wilson Date: Fri, 4 Jan 2013 01:39:40 -0500 Subject: [PATCH] get display of validation errors to work. --- common/djangoapps/student/models.py | 14 +++ common/djangoapps/student/views.py | 102 ++++------------ lms/templates/test_center_register.html | 147 +++++++++++++----------- 3 files changed, 119 insertions(+), 144 deletions(-) diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py index d55abbe760..9254dff551 100644 --- a/common/djangoapps/student/models.py +++ b/common/djangoapps/student/models.py @@ -303,6 +303,7 @@ class TestCenterRegistration(models.Model): eligibility_appointment_date_last = models.DateField(db_index=True) # this is really a list of codes, using an '*' as a delimiter. + # So it's not a choice list. accommodation_code = models.CharField(max_length=64, blank=True) # store the original text of the accommodation request. @@ -349,6 +350,19 @@ class TestCenterRegistration(models.Model): h.update(str(self.exam_series_code)) return h.hexdigest() + def is_accepted(self): + return self.upload_status == 'Accepted' + + def is_rejected(self): + return self.upload_status == 'Error' + + def is_pending_accommodation(self): + return len(self.accommodation_request) > 0 and self.accommodation_code == '' + + def is_pending_acknowledgement(self): + return self.upload_status == '' and not self.is_pending_accommodation() + + def get_testcenter_registrations_for_user_and_course(user, course_id, exam_series_code=None): try: tcu = TestCenterUser.objects.get(user=user) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 1ad464bbc6..de3dcde553 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -594,7 +594,7 @@ def create_account(request, post_override=None): @login_required @ensure_csrf_cookie -def begin_test_registration(request, course_id, form=None, message=''): +def begin_test_registration(request, course_id): user = request.user try: @@ -605,6 +605,8 @@ def begin_test_registration(request, course_id, form=None, message=''): # get the exam to be registered for: # (For now, we just assume there is one at most.) + # TODO: this should be an object, including the course_id and the + # exam info for a particular exam from the course. exam_info = course.testcenter_info # figure out if the user is already registered for this exam: @@ -624,16 +626,11 @@ def begin_test_registration(request, course_id, form=None, message=''): except TestCenterUser.DoesNotExist: testcenteruser = TestCenterUser() testcenteruser.user = user - - if form is None: - form = TestCenterUserForm(instance=testcenteruser) context = {'course': course, 'user': user, - 'message': message, 'testcenteruser': testcenteruser, 'registration': registration, - 'form': form, 'exam_info': exam_info, } @@ -669,32 +666,18 @@ def create_test_registration(request, post_override=None): # perform validation: if needs_updating: log.info("User {0} enrolled in course {1} updating demographic info for test registration".format(user.username, course_id)) - try: - # first perform validation on the user information - # using a Django Form. - form = TestCenterUserForm(instance=testcenter_user, data=post_vars) - if not form.is_valid(): -# return begin_test_registration(request, course_id, form, 'failed to validate') - response_data = {'success': False} - # return a list of errors... - response_data['field_errors'] = form.errors - response_data['non_field_errors'] = form.non_field_errors() - return HttpResponse(json.dumps(response_data), mimetype="application/json") + # first perform validation on the user information + # using a Django Form. + form = TestCenterUserForm(instance=testcenter_user, data=post_vars) + if form.is_valid(): form.update_and_save() - except IntegrityError, ie: - js = {'success': False} - error_msg = unicode(ie); - # attempt to find a field name to signal - for fieldname in TestCenterUser.user_provided_fields(): - if error_msg.find(fieldname) >= 0: - js['value'] = error_msg - js['field'] = fieldname - return HttpResponse(json.dumps(js), mimetype="application/json") - # otherwise just return the error message - js['value'] = error_msg - js['field'] = "General Error" - return HttpResponse(json.dumps(js), mimetype="application/json") - + else: + response_data = {'success': False} + # return a list of errors... + response_data['field_errors'] = form.errors + response_data['non_field_errors'] = form.non_field_errors() + return HttpResponse(json.dumps(response_data), mimetype="application/json") + # create and save the registration: needs_saving = False exam_info = course.testcenter_info @@ -712,53 +695,17 @@ def create_test_registration(request, post_override=None): accommodation_request = post_vars.get('accommodations','') registration = TestCenterRegistration.create(testcenter_user, course_id, exam_info, accommodation_request) needs_saving = True - - # "client_authorization_id" is the client's unique identifier for the authorization. - # This must be present for an update or delete to be sent to Pearson. - # Can we just use the id field of the registration? Lets... - + + # TODO: add validation of registration. (Mainly whether an accommodation request is too long.) if needs_saving: - try: - registration.save() - except IntegrityError, ie: - raise + registration.save() -# return (user, testcenter_user, registration) - - - # Confirm we have a properly formed request -# for a in ['first_name', 'last_name', 'address_1', 'city', 'country']: -# if a not in post_vars: -# js['value'] = "Error (401 {field}). E-mail us.".format(field=a) -# js['field'] = a -# return HttpResponse(json.dumps(js)) -# -# # Confirm appropriate fields are filled in with something for now -# for a in ['first_name', 'last_name', 'address_1', 'city', 'country']: -# if len(post_vars[a]) < 2: -# error_str = {'first_name': 'First name must be minimum of two characters long.', -# 'last_name': 'Last name must be minimum of two characters long.', -# 'address_1': 'Address must be minimum of two characters long.', -# 'city': 'City must be minimum of two characters long.', -# 'country': 'Country must be minimum of two characters long.', -# } -# js['value'] = error_str[a] -# js['field'] = a -# return HttpResponse(json.dumps(js)) - - # Once the test_center_user information has been validated, create the entries: -# ret = _do_create_or_update_test_center_user(post_vars) -# if isinstance(ret,HttpResponse): # if there was an error then return that -# return ret -# -# -# (user, testcenter_user, testcenter_registration) = ret # only do the following if there is accommodation text to send, - # and a destination to which to send it: - if 'accommodation' in post_vars and settings.MITX_FEATURES.get('ACCOMMODATION_EMAIL'): - d = {'accommodation': post_vars['accommodation'] - } + # and a destination to which to send it. + # TODO: still need to create the accommodation email templates + if 'accommodations' in post_vars and settings.MITX_FEATURES.get('ACCOMMODATION_EMAIL'): + d = {'accommodations': post_vars['accommodations'] } # composes accommodation email subject = render_to_string('emails/accommodation_email_subject.txt', d) @@ -772,8 +719,9 @@ def create_test_registration(request, post_override=None): send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False) except: log.exception(sys.exc_info()) - js['value'] = 'Could not send accommodation e-mail.' - return HttpResponse(json.dumps(js), mimetype="application/json") + response_data = {'success': False} + response_data['non_field_errors'] = [ 'Could not send accommodation e-mail.', ] + return HttpResponse(json.dumps(response_data), mimetype="application/json") # TODO: enable appropriate stat # statsd.increment("common.student.account_created") @@ -782,8 +730,6 @@ def create_test_registration(request, post_override=None): js = {'success': True} return HttpResponse(json.dumps(js), mimetype="application/json") -# return HttpResponseRedirect(reverse('dashboard')) - #return HttpResponse("Hello world") def get_random_post_override(): diff --git a/lms/templates/test_center_register.html b/lms/templates/test_center_register.html index b5080ab9b2..da5f9f1450 100644 --- a/lms/templates/test_center_register.html +++ b/lms/templates/test_center_register.html @@ -17,22 +17,48 @@ $(document).on('ajax:success', '#testcenter_register_form', function(data, json, xhr) { if(json.success) { + // when a form is successfully filled out, return back to the dashboard. location.href="${reverse('dashboard')}"; } else { - var field_errors = json.field_errors; - var non_field_errors = json.non_field_errors; - var fieldname; - var field_errorlist; - var field_error; - $(".field.error").removeClass('error'); - for (fieldname in field_errors) { - field_errorlist = field_errors[fieldname]; - for (i=0; i < field_errorlist.length; i+= 1) { - field_error = field_errorlist[i]; - } - $("[data-field='"+fieldname+"']").addClass('error') + // This is performed by the following code that parses the errors returned as json by the + // registration form validation. + var field_errors = json.field_errors; + var non_field_errors = json.non_field_errors; + var fieldname; + var field_errorlist; + var field_error; + var error_msg; + var num_errors = 0; + var error_html = ''; + // first get rid of any errors that are already present: + $(".field.error").removeClass('error'); + $("#submission-error-list").html(error_html); + // start to display new errors: + $(".submission-error").addClass("is-shown"); + for (fieldname in field_errors) { + // to inform a user of what field the error occurred on, add a class of .error to the .field element. + // for convenience, use the "data-field" attribute to identify the one matching the errant field's name. + $("[data-field='"+fieldname+"']").addClass('error') + field_errorlist = field_errors[fieldname]; + for (i=0; i < field_errorlist.length; i+= 1) { + field_error = field_errorlist[i]; + error_msg = fieldname + ": " + field_error; + error_html = error_html + '
  • ' + error_msg + '
  • '; + num_errors += 1; } - $('#register_error').html(json.value).stop().css("display", "block"); + } + for (i=0; i < non_field_errors.length; i+= 1) { + error_msg = non_field_errors[i]; + error_html = error_html + '
  • ' + error_msg + '
  • '; + num_errors += 1; + } + if (num_errors == 1) { + error_msg = 'was an error'; + } else { + error_msg = 'were ' + num_errors + ' errors'; + } + $('#submission-error-heading').text("We're sorry, but there " + error_msg + " in the information you provided below:") + $("#submission-error-list").html(error_html); } }); @@ -80,20 +106,12 @@

    Your registration data has been updated and saved.

    - - - % if message: -
    -

    ${message}

    -
    - % endif - + - % if form.errors and len(form.errors) > 0: -
    -

    We're Sorry, but there was an error with the information you provided below:

    +
    +

    +
    - % endif
    @@ -122,32 +140,23 @@
      -
    1. - - ${form['salutation']} -
    2. -
    3. - - ${form['first_name']} -
    4. - -
    5. +
    6. -
    7. +
    8. -
    9. +
    10. @@ -158,22 +167,22 @@
        -
      1. +
      2. -
        +
        -
        +
      3. -
        +
        @@ -198,30 +207,30 @@
        1. -
          +
          -
          +
          -
          +
        2. -
          +
          -
          +
        3. -
        4. +
        5. @@ -230,7 +239,7 @@
        - + % if registration:

        Fields below this point are not part of the demographics, and are not editable currently.

        % else: @@ -240,16 +249,22 @@
        +
          % if registration: + % if registration.accommodation_request and len(registration.accommodation_request) > 0:
        1. - +
        2. + % endif % else:
        3. - +
        4. % endif
        @@ -270,19 +285,8 @@ % if registration: - <% - if registration.upload_status == 'Accepted': - regstatus = "Registration approved by Pearson" - elif registration.upload_status == 'Error': - regstatus = "Registration rejected by Pearson: %s" % registration.upload_error_message - elif len(registration.accommodation_request) > 0 and registration.accommodation_code == '': - regstatus = "Registration pending approval of accommodation request" - else: - regstatus = "Registration pending acknowledgement by Pearson" - %> - - % if registration.upload_status == 'Accepted': + % if registration.is_accepted(): <% regstatus = "Registration approved by Pearson" %>

        Registration Status: ${regstatus}

        @@ -292,7 +296,7 @@
        % endif - % if registration.upload_status == 'Error': + % if registration.is_rejected(): <% regstatus = "Registration rejected by Pearson: %s" % registration.upload_error_message %>
        @@ -301,14 +305,25 @@
        % endif - % if len(registration.accommodation_request) > 0 and registration.accommodation_code == '': + % if registration.is_pending_accommodation(): <% regstatus = "Registration pending approval of accommodation request" %> +
        +

        Registration Status: ${regstatus}

        +

        Your registration for the Pearson exam is pending. Within a few days, you should see confirmation here of granted accommodations. + At that point, your registration will be forwarded to Pearson.

        +
        + % endif + + % if registration.is_pending_acknowledgement(): + <% regstatus = "Registration pending acknowledgement by Pearson" %> +

        Registration Status: ${regstatus}

        Your registration for the Pearson exam is pending. Within a few days, you should see a confirmation number here, which can be used to schedule your exam.

        % endif + % endif