Commit fa510469 by David Ormsbee

Merge pull request #253 from MITx/smooth_registration

Smooth registration
parents d798b4ac 9afb0f8b
......@@ -10,10 +10,10 @@
<hr>
</header>
<div id="enroll">
<div id="register">
<form id="enroll_form" method="post">
<div id="enroll_error" name="enroll_error"></div>
<form id="register_form" method="post">
<div id="register_error" name="register_error"></div>
<label>E-mail</label>
<input name="email" type="email" placeholder="E-mail">
<label>Password</label>
......@@ -64,17 +64,17 @@
});
}
$('form#enroll_form').submit(function(e) {
$('form#register_form').submit(function(e) {
e.preventDefault();
var submit_data = $('#enroll_form').serialize();
var submit_data = $('#register_form').serialize();
postJSON('/create_account',
submit_data,
function(json) {
if(json.success) {
$('#enroll').html(json.value);
$('#register').html(json.value);
} else {
$('#enroll_error').html(json.value).stop().css("background-color", "#933").animate({ backgroundColor: "#333"}, 2000);
$('#register_error').html(json.value).stop().css("background-color", "#933").animate({ backgroundColor: "#333"}, 2000);
}
}
);
......
......@@ -8,19 +8,22 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'CourseEnrollment', fields ['user']
db.delete_unique('student_courseenrollment', ['user_id'])
# Changing field 'CourseEnrollment.user'
db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User']))
# This table is dropped in a subsequent migration. This migration was causing problems when using InnoDB,
# so we are just dropping it.
pass
# # Removing unique constraint on 'CourseEnrollment', fields ['user']
# db.delete_unique('student_courseenrollment', ['user_id'])
#
#
# # Changing field 'CourseEnrollment.user'
# db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User']))
def backwards(self, orm):
# Changing field 'CourseEnrollment.user'
db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True))
# Adding unique constraint on 'CourseEnrollment', fields ['user']
db.create_unique('student_courseenrollment', ['user_id'])
pass
# # Changing field 'CourseEnrollment.user'
# db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True))
# # Adding unique constraint on 'CourseEnrollment', fields ['user']
# db.create_unique('student_courseenrollment', ['user_id'])
models = {
......
......@@ -79,18 +79,16 @@ def index(request):
return render_to_response('index.html', {'universities': universities, 'entries': entries})
def course_from_id(id):
course_loc = CourseDescriptor.id_to_location(id)
return modulestore().get_item(course_loc)
@login_required
@ensure_csrf_cookie
def dashboard(request):
csrf_token = csrf(request)['csrf_token']
user = request.user
enrollments = CourseEnrollment.objects.filter(user=user)
def course_from_id(id):
course_loc = CourseDescriptor.id_to_location(id)
return modulestore().get_item(course_loc)
# Build our courses list for the user, but ignore any courses that no longer
# exist (because the course IDs have changed). Still, we don't delete those
# enrollments, because it could have been a data push snafu.
......@@ -101,18 +99,80 @@ def dashboard(request):
except ItemNotFoundError:
log.error("User {0} enrolled in non-existant course {1}"
.format(user.username, enrollment.course_id))
message = ""
if not user.is_active:
message = render_to_string('registration/activate_account_notice.html', {'email': user.email})
context = {'csrf': csrf_token, 'courses': courses}
context = {'courses': courses, 'message' : message}
return render_to_response('dashboard.html', context)
def try_change_enrollment(request):
"""
This method calls change_enrollment if the necessary POST
parameters are present, but does not return anything. It
simply logs the result or exception. This is usually
called after a registration or login, as secondary action.
It should not interrupt a successful registration or login.
"""
if 'enrollment_action' in request.POST:
try:
enrollment_output = change_enrollment(request)
# There isn't really a way to display the results to the user, so we just log it
# We expect the enrollment to be a success, and will show up on the dashboard anyway
log.info("Attempted to automatically enroll after login. Results: {0}".format(enrollment_output))
except Exception, e:
log.exception("Exception automatically enrolling after login: {0}".format(str(e)))
@login_required
def change_enrollment_view(request):
return HttpResponse(json.dumps(change_enrollment(request)))
def change_enrollment(request):
if request.method != "POST":
raise Http404
action = request.POST.get("enrollment_action" , "")
user = request.user
course_id = request.POST.get("course_id", None)
if course_id == None:
return HttpResponse(json.dumps({'success': False, 'error': 'There was an error receiving the course id.'}))
if action == "enroll":
# Make sure the course exists
# We don't do this check on unenroll, or a bad course id can't be unenrolled from
try:
course = course_from_id(course_id)
except ItemNotFoundError:
log.error("User {0} tried to enroll in non-existant course {1}"
.format(user.username, enrollment.course_id))
return {'success': False, 'error': 'The course requested does not exist.'}
enrollment, created = CourseEnrollment.objects.get_or_create(user=user, course_id=course.id)
return {'success': True}
elif action == "unenroll":
try:
enrollment = CourseEnrollment.objects.get(user=user, course_id=course_id)
enrollment.delete()
return {'success': True}
except CourseEnrollment.DoesNotExist:
return {'success': False, 'error': 'You are not enrolled for this course.'}
else:
return {'success': False, 'error': 'Invalid enrollment_action.'}
return {'success': False, 'error': 'We weren\'t able to unenroll you. Please try again.'}
# Need different levels of logging
@ensure_csrf_cookie
def login_user(request, error=""):
''' AJAX request to log in the user. '''
if 'email' not in request.POST or 'password' not in request.POST:
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid login'})) # TODO: User error message
'value': 'There was an error receiving your login information. Please email us.'})) # TODO: User error message
email = request.POST['email']
password = request.POST['password']
......@@ -121,14 +181,14 @@ def login_user(request, error=""):
except User.DoesNotExist:
log.warning("Login failed - Unknown user email: {0}".format(email))
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid login'})) # TODO: User error message
'value': 'Email or password is incorrect.'})) # TODO: User error message
username = user.username
user = authenticate(username=username, password=password)
if user is None:
log.warning("Login failed - password for {0} is invalid".format(email))
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid login'}))
'value': 'Email or password is incorrect.'}))
if user is not None and user.is_active:
try:
......@@ -143,11 +203,14 @@ def login_user(request, error=""):
log.exception(e)
log.info("Login success - {0} ({1})".format(username, email))
try_change_enrollment(request)
return HttpResponse(json.dumps({'success':True}))
log.warning("Login failed - Account not active for user {0}".format(username))
return HttpResponse(json.dumps({'success':False,
'error': 'Account not active. Check your e-mail.'}))
'value': 'This account has not been activated. Please check your e-mail for the activation instructions.'}))
@ensure_csrf_cookie
def logout_user(request):
......@@ -275,10 +338,17 @@ def create_account(request, post_override=None):
log.exception(sys.exc_info())
js['value'] = 'Could not send activation e-mail.'
return HttpResponse(json.dumps(js))
js={'success': True,
'value': render_to_string('registration/reg_complete.html', {'email': post_vars['email'],
'csrf': csrf(request)['csrf_token']})}
# 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)
try_change_enrollment(request)
js={'success': True}
return HttpResponse(json.dumps(js), mimetype="application/json")
def create_random_account(create_account_function):
......@@ -308,14 +378,15 @@ def activate_account(request, key):
'''
r=Registration.objects.filter(activation_key=key)
if len(r)==1:
user_logged_in = request.user.is_authenticated()
already_active = True
if not r[0].user.is_active:
r[0].activate()
resp = render_to_response("activation_complete.html",{'csrf':csrf(request)['csrf_token']})
return resp
resp = render_to_response("activation_active.html",{'csrf':csrf(request)['csrf_token']})
already_active = False
resp = render_to_response("registration/activation_complete.html",{'user_logged_in':user_logged_in, 'already_active' : already_active})
return resp
if len(r)==0:
return render_to_response("activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
return render_to_response("registration/activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.")
@ensure_csrf_cookie
......
......@@ -38,7 +38,7 @@ def cache_if_anonymous(view_func):
@wraps(view_func)
def _decorated(request, *args, **kwargs):
if not request.user.is_authenticated():
if False and not request.user.is_authenticated():
#Use the cache
cache_key = "cache_if_anonymous." + request.path
response = cache.get(cache_key)
......
......@@ -269,39 +269,6 @@ def course_about(request, course_id):
course = check_course(course_id, course_must_be_open=False)
registered = registered_for_course(course, request.user)
return render_to_response('portal/course_about.html', {'course': course, 'registered': registered})
@login_required
def change_enrollment(request):
if request.method != "POST":
raise Http404
course_id = request.POST.get("course_id", None)
if course_id == None:
return HttpResponse(json.dumps({'success': False, 'error': 'There was an error receiving the course id.'}))
action = request.POST.get("enrollment_action" , "")
user = request.user
if action == "enroll":
# Make sure the course exists
# We don't do this check on unenroll, or a bad course id can't be unenrolled from
course = check_course(course_id, course_must_be_open=False)
enrollment, created = CourseEnrollment.objects.get_or_create(user=user, course_id=course.id)
return HttpResponse(json.dumps({'success': True}))
elif action == "unenroll":
try:
enrollment = CourseEnrollment.objects.get(user=user, course_id=course_id)
enrollment.delete()
return HttpResponse(json.dumps({'success': True}))
except CourseEnrollment.DoesNotExist:
return HttpResponse(json.dumps({'success': False, 'error': 'You are not enrolled for this course.'}))
else:
return HttpResponse(json.dumps({'success': False, 'error': 'Invalid enrollment_action.'}))
return HttpResponse(json.dumps({'success': False, 'error': 'We weren\'t able to unenroll you. Please try again.'}))
......
......@@ -7,9 +7,11 @@
closeButton: null,
position: 'fixed'
}
var overlay = $("<div id='lean_overlay'></div>");
$("body").append(overlay);
if ($("#lean_overlay").length == 0) {
var overlay = $("<div id='lean_overlay'></div>");
$("body").append(overlay);
}
options = $.extend(defaults, options);
......@@ -51,7 +53,11 @@
$(modal_id).find(".notice").hide().html("");
var notice = $(this).data('notice')
if(notice !== undefined) {
$(modal_id).find(".notice").show().html(notice);
$notice = $(modal_id).find(".notice");
$notice.show().html(notice);
// This is for activating leanModal links that were in the notice. We should have a cleaner way of
// allowing all dynamically added leanmodal links to work.
$notice.find("a[rel*=leanModal]").leanModal({ top : 120, overlay: 1, closeButton: ".close-modal", position: 'absolute' });
}
window.scrollTo(0, 0);
e.preventDefault();
......
......@@ -84,7 +84,7 @@ div.leanModal_box {
form {
text-align: left;
div#enroll_error, div#login_error, div#pwd_error {
div#register_error, div#login_error, div#pwd_error {
$error-color: #333;
background-color: $error-color;
border: darken($error-color, 20%);
......
<%! from django.core.urlresolvers import reverse %>
<%inherit file="main.html" />
<%namespace name='static' file='static_content.html'/>
<section class="container activation">
<section class="message">
<h1>Account already active!</h1>
<hr class="horizontal-divider">
<p> This account has already been activated. You can now <a href="#login-modal" rel="leanModal">login</a>.</p>
</section>
</section>
<%! from django.core.urlresolvers import reverse %>
<%inherit file="main.html" />
<%namespace name='static' file='static_content.html'/>
<section class="container activation">
<section class="message">
<h1 class="valid">Activation Complete!</h1>
<hr class="horizontal-divider">
<p>Thanks for activating your account. You can now <a href="#login-modal" rel="leanModal">login</a>.</p>
</section>
</section>
......@@ -9,6 +9,10 @@
<%block name="title"><title>Dashboard</title></%block>
<section class="container dashboard">
<section class="dashboard-banner">
${message}
</section>
<section class="profile-sidebar">
<header class="profile">
......
<!-- TODO: http://docs.jquery.com/Plugins/Validation -->
<div id="login_div">
<header>
<h1>Log in to <span class="edx">edX</span></h1>
<p class="no-account">If you don&rsquo;t have an account yet, <a href="#enroll" rel="leanModal">please enroll here</a></p>
</header>
<!--[if lte IE 9]>
<p class="ie-warning">You are using a browser that is not supported by <span class="edx">edX</span>, and you might not be able to complete pieces of the course. Please download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Firefox</a> or <a href="https://www.google.com/chrome">Chrome</a> to get the full experience.</p>
<![endif]-->
<form id="login_form" method="post">
<ol>
<li>
<label>E-mail*</label>
<input name="email" id="li_email" type="email" required>
</li>
<li>
<label>Password*</label>
<input name="password" id="li_password" type="password" required>
</li>
<li class="remember">
<label><input name="remember" id="remember" type="checkbox">Remember me</label>
</li>
</ol>
<input name="submit" id="login_button" type="submit" value="Log in">
</form>
<div class="lost-password">
<div id="lost_password"><a class="" rel="leanModal" href="#pwd_reset">Lost password?</a></div>
</div>
</div>
......@@ -44,9 +44,9 @@
location.href="${reverse('dashboard')}";
} else {
if($('#login_error').length == 0) {
$('#login_form').prepend('<div id="login_error" class="modal-form-error">Email or password is incorrect.</div>');
$('#login_form').prepend('<div id="login_error" class="modal-form-error"></div>');
}
$('#login_error').stop().css("display", "block");
$('#login_error').html(json.value).stop().css("display", "block");
}
});
})(this)
......
<%! from django.core.urlresolvers import reverse %>
<%namespace name='static' file='static_content.html'/>
<!DOCTYPE html>
<html>
<head>
<title><%block name="title">MITx: MIT's new online learning initiative</%block></title>
<meta name="description" content="<%block name="description">MITx will offer a portfolio of MIT courses for free to a virtual community of learners around the world</%block>" />
<meta name="keywords" content="<%block name="keywords">MITx, online learning, MIT, online laboratory, education, learners, undergraduate, certificate</%block>" />
<!--link rel="stylesheet" href="${ settings.LIB_URL }jquery.treeview.css" type="text/css" media="all" /-->
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<script type="text/javascript" src="${static.url('js/jquery.min.js')}"></script>
<script type="text/javascript" src="${static.url('js/jquery-ui.min.js')}"></script>
<script type="text/javascript" src="${static.url('js/jquery.leanModal.min.js')}"></script>
<!--script type="text/javascript" src="${static.url('js/swfobject/swfobject.js')}"></script-->
<!--script type="text/javascript" src="${static.url('js/jquery.treeview.js')}"></script-->
<!--script type="text/javascript" src="${static.url('js/video_player.js')}"></script-->
<!-- <script type="text/javascript" src="${static.url('js/schematic.js')}"></script> -->
<script src="${static.url('js/html5shiv.js')}"></script>
<%block name="headextra"/>
<script type="text/javascript">
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function postJSON(url, data, callback) {
$.ajax({type:'POST',
url: url,
dataType: 'json',
data: data,
success: callback,
headers : {'X-CSRFToken':getCookie('csrftoken')}
});
}
</script>
</head>
<body>
<%block name="header">
<header class="announcement <%block name="header_class"/>">
<div class="anouncement-wrapper">
<%block name="header_nav">
<nav>
<h1><a href="http://mitx.mit.edu/">MITx</a></h1>
% if settings.COURSEWARE_ENABLED:
<%block name="login_area">
<a rel="leanModal" class="login" href="#login">Log In</a>
</%block>
% endif
</nav>
</%block>
<%block name="header_text">
<section>
<h1><em>MITx</em></h1>
<h2>MIT&rsquo;s new online learning initiative</h2>
</section>
</%block>
</div>
</header>
</%block>
${self.body()}
<%block name="bodyextra"/>
<footer>
<div class="footer-wrapper">
<p> Copyright &copy; 2012. MIT. <a href="${reverse('copyright')}">Some rights reserved.</a></p>
<ul>
<li><a href="${reverse('tos')}">Terms of Service</a></li>
<li><a href="${reverse('privacy')}">Privacy Policy</a></li>
<li><a href="${reverse('honor')}">Honor Code</a></li>
<li><a href="${reverse('help_edx')}">Help</a></li>
</ul>
<ul aria-label="Social Links" class="social">
<li class="linkedin">
<a href="http://www.linkedin.com/groups/Friends-Alumni-MITx-4316538">Linked In</a>
</li>
<li class="twitter">
<a href="https://twitter.com/#!/MyMITx">Twitter</a>
</li>
<li class="facebook">
<a href="http://www.facebook.com/pages/MITx/378592442151504">Facebook</a>
</li>
</ul>
</div>
</footer>
% if settings.COURSEWARE_ENABLED:
<div id="login" class="leanModal_box"><%include file="login.html" /></div>
% endif
<div id="pwd_reset" class="leanModal_box"><%include file="password_reset_form.html" /></div>
<div id="reset_done" class="leanModal_box"></div>
<script>
$(document).ready(function(){
/* Handles when the user tries to log in. Grabs form data. Does AJAX.
Either shows error, or redirects. */
$('form#login_form').submit(function(e) {
e.preventDefault();
var submit_data={};
$.each($("[id^=li_]"), function(index,value){
submit_data[value.name]=value.value;
});
submit_data["remember"] = ($('#remember').attr("checked")? true : false);
postJSON('/login',
submit_data,
function(json) {
if(json.success) {
location.href="/info";
} else if($('#login_error').length == 0) {
$('#login_form').prepend('<div id="login_error">Email or password is incorrect.</div>');
} else {
$('#login_error').stop().css("background-color", "#933").animate({ backgroundColor: "#333"}, 2000);
}
}
);
});
$('form#pwd_reset_form').submit(function(e) {
e.preventDefault();
var submit_data = {};
submit_data['email'] = $('#id_email').val();
postJSON('/password_reset/',
submit_data,
function(json){
if (json.success) {
$('#pwd_reset').html(json.value);
} else {
$('#pwd_error').html(json.error).stop().css("background-color", "#933").animate({ backgroundColor: "#333"}, 2000);
}
}
);
});
});
$(function(){
$("a[rel*=leanModal]").leanModal();
$("a.login").click(function(){
$("#login_form #li_email").focus();
});
$("a.enroll").click(function(){
$("#enroll_form #ca_email").focus();
});
});
</script>
<%block name="js_extra"/>
</body>
</html>
......@@ -25,10 +25,10 @@
%if registered:
<span class="register disabled">You are registered for this course (${course.number}).</span>
%else:
<a href="#" class="register submit_registration">Register for ${course.number}</a>
<a href="#" class="register">Register for ${course.number}</a>
%endif
%else:
<a href="#signup-modal" class="register" rel="leanModal" data-notice="You must Sign Up in order to register">Register for ${course.number}</a>
<a href="#signup-modal" class="register" rel="leanModal" data-notice='You must Sign Up or <a href="#login-modal" rel="leanModal">Log In</a> to enroll.'>Register for ${course.number}</a>
%endif
</div>
......@@ -108,28 +108,49 @@
</section>
%if not registered:
<div display="hidden">
<form id="enroll_form" method="post" data-remote="true" action="${reverse('change_enrollment')}">
<input name="course_id" type="hidden" value="${course.id}">
<input name="enrollment_action" type="hidden" value="enroll">
<div style="display: none;">
<form id="class_enroll_form" method="post" data-remote="true" action="${reverse('change_enrollment')}">
<fieldset class="enroll_fieldset">
<input name="course_id" type="hidden" value="${course.id}">
<input name="enrollment_action" type="hidden" value="enroll">
</fieldset>
<div class="submit">
<input name="submit" type="submit" value="enroll">
</div>
</form>
</div>
<script type="text/javascript">
(function() {
$(".submit_registration").click(function() {
$("#enroll_form").submit();
});
%if user.is_authenticated():
## If the user is authenticated, clicking the enroll button just submits a form
<script type="text/javascript">
(function() {
$(".register").click(function() {
$("#class_enroll_form").submit();
});
$(document).delegate('#enroll_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
location.href="${reverse('dashboard')}";
}
});
})(this)
</script>
$(document).delegate('#class_enroll_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
location.href="${reverse('dashboard')}";
}
});
})(this)
</script>
%else:
## If the user is not authenticated, clicking the enroll button pops up the register
## field. We also slip in the registration fields into the login/register fields so
## the user is automatically registered after logging in / registering
<script type="text/javascript">
(function() {
$(".register").click(function() {
if ($("#login_form .enroll_fieldset").length === 0) {
$("#login_form").append( $(".enroll_fieldset").first().clone() );
}
if ($("#register_form .enroll_fieldset").length === 0) {
$("#register_form").append( $(".enroll_fieldset").first().clone() );
}
});
})(this)
</script>
%endif
%endif
......
<h2>Thanks For Registering!</h2>
<p class='activation-message'>Your account is not active yet. An activation link has been sent to <strong>${ email }</strong>, along with
instructions for activating your account.</p>
<%! from django.core.urlresolvers import reverse %>
<%inherit file="../main.html" />
<%namespace name='static' file='../static_content.html'/>
<section class="container activation">
<section class="message">
%if not already_active:
<h1 class="valid">Activation Complete!</h1>
%else:
<h1>Account already active!</h1>
%endif
<hr class="horizontal-divider">
<p>
%if not already_active:
Thanks for activating your account.
%else:
This account has already been activated.
%endif
%if user_logged_in:
Visit your <a href="${reverse('dashboard')}">dashboard</a> to see your courses.
%else:
You can now <a href="#login-modal" rel="leanModal">login</a>.
%endif
</p>
</section>
</section>
<%! from django.core.urlresolvers import reverse %>
<%inherit file="main.html" />
<%inherit file="../main.html" />
<%namespace name='static' file='static_content.html'/>
<%namespace name='static' file='../static_content.html'/>
<section class="container activation">
......
<header>
<h2>Thanks For Registering!</h2>
<hr>
</header>
<p class='activation-message'>Please check your email. An activation link has been sent to <strong>${ email }</strong>, along with
instructions for activating your account.</p>
......@@ -7,16 +7,16 @@
<section id="signup-modal" class="modal signup-modal">
<div class="inner-wrapper">
<div id="enroll">
<div id="register">
<header>
<h2>Sign Up for <span class="edx">edX</span></h2>
<hr>
</header>
<form id="enroll_form" method="post" data-remote="true" action="/create_account">
<form id="register_form" method="post" data-remote="true" action="/create_account">
<div class="notice"></div>
<div id="enroll_error" class="modal-form-error" name="enroll_error"></div>
<div id="enroll_error" name="enroll_error"></div>
<div id="register_error" class="modal-form-error" name="register_error"></div>
<div id="register_error" name="register_error"></div>
<div class="input-group">
<label>E-mail*</label>
......@@ -120,11 +120,11 @@
<script type="text/javascript">
(function() {
$(document).delegate('#enroll_form', 'ajax:success', function(data, json, xhr) {
$(document).delegate('#register_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
$('#enroll').html(json.value);
location.href="${reverse('dashboard')}";
} else {
$('#enroll_error').html(json.value).stop().css("display", "block");
$('#register_error').html(json.value).stop().css("display", "block");
}
});
})(this)
......
......@@ -101,7 +101,7 @@ if settings.COURSEWARE_ENABLED:
url(r'^courses/?$', 'courseware.views.courses', name="courses"),
url(r'^change_enrollment$',
'courseware.views.change_enrollment', name="change_enrollment"),
'student.views.change_enrollment_view', name="change_enrollment"),
#About the course
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/about$',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment