Commit ff59c9bf by Victor Shnayder

Initial connection of student module with cms.

* Enable account creation
* Some code cleanups
* Fix access to nonexistent fields in the account creation view
* Formatting fixes
parent 924a9111
...@@ -2,9 +2,11 @@ from util.json_request import expect_json ...@@ -2,9 +2,11 @@ from util.json_request import expect_json
import json import json
from django.http import HttpResponse from django.http import HttpResponse
from django.core.context_processors import csrf
from django_future.csrf import ensure_csrf_cookie from django_future.csrf import ensure_csrf_cookie
from fs.osfs import OSFS
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from fs.osfs import OSFS
from xmodule.modulestore import Location from xmodule.modulestore import Location
from github_sync import export_to_github from github_sync import export_to_github
...@@ -26,6 +28,14 @@ def index(request): ...@@ -26,6 +28,14 @@ def index(request):
@ensure_csrf_cookie @ensure_csrf_cookie
def signup(request):
"""
Display the signup form.
"""
csrf_token = csrf(request)['csrf_token']
return render_to_response('signup.html', {'csrf': csrf_token })
@ensure_csrf_cookie
def course_index(request, org, course, name): def course_index(request, org, course, name):
# TODO (cpennington): These need to be read in from the active user # TODO (cpennington): These need to be read in from the active user
course = modulestore().get_item(['i4x', org, course, 'course', name]) course = modulestore().get_item(['i4x', org, course, 'course', name])
......
...@@ -34,6 +34,10 @@ MITX_FEATURES = { ...@@ -34,6 +34,10 @@ MITX_FEATURES = {
'GITHUB_PUSH': False, 'GITHUB_PUSH': False,
} }
# needed to use lms student app
GENERATE_RANDOM_USER_CREDENTIALS = False
############################# SET PATH INFORMATION ############################# ############################# SET PATH INFORMATION #############################
PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /mitx/cms PROJECT_ROOT = path(__file__).abspath().dirname().dirname() # /mitx/cms
REPO_ROOT = PROJECT_ROOT.dirname() REPO_ROOT = PROJECT_ROOT.dirname()
...@@ -97,7 +101,7 @@ MIDDLEWARE_CLASSES = ( ...@@ -97,7 +101,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
# Instead of AuthenticationMiddleware, we use a cached backed version # Instead of AuthenticationMiddleware, we use a cache-backed version
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware', 'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
...@@ -239,9 +243,11 @@ INSTALLED_APPS = ( ...@@ -239,9 +243,11 @@ INSTALLED_APPS = (
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', 'django.contrib.sites',
'django.contrib.messages', 'django.contrib.messages',
'south',
# For CMS # For CMS
'contentstore', 'contentstore',
'student', # misleading name due to sharing with lms
# For asset pipelining # For asset pipelining
'pipeline', 'pipeline',
......
...@@ -25,7 +25,7 @@ MODULESTORE = { ...@@ -25,7 +25,7 @@ MODULESTORE = {
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': ENV_ROOT / "db" / "mitx.db", 'NAME': ENV_ROOT / "db" / "cms.db",
} }
} }
......
...@@ -80,6 +80,6 @@ $(document).ready(function(){ ...@@ -80,6 +80,6 @@ $(document).ready(function(){
$('section.problem-edit').show(); $('section.problem-edit').show();
return false; return false;
}); });
}); });
<%inherit file="marketing.html" />
<%block name="content">
<section class="tos">
<div>
<section class="activation">
<h1>Account already active!</h1>
<p> This account has already been activated. You can log in at
the <a href="/">home page</a>.</p>
</div>
</section>
</%block>
\ No newline at end of file
<%inherit file="marketing.html" />
<%block name="content">
<section class="tos">
<div>
<h1>Activation Complete!</h1>
<p>Thanks for activating your account. You can log in at the <a href="/">home page</a>.</p>
</div>
</section>
</%block>
\ No newline at end of file
<%inherit file="marketing.html" />
<%block name="content">
<section class="tos">
<div>
<h1>Activation Invalid</h1>
<p>Something went wrong. Check to make sure the URL you went to was
correct -- e-mail programs will sometimes split it into two
lines. If you still have issues, e-mail us to let us know what happened
at <a href="mailto:bugs@mitx.mit.edu">bugs@mitx.mit.edu</a>.</p>
<p>Or you can go back to the <a href="/">home page</a>.</p>
</div>
</section>
</%block>
\ No newline at end of file
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
<%include file="widgets/header.html"/> <%include file="widgets/header.html"/>
<%block name="content"></%block>
<script type="text/javascript" src="${static.url('js/vendor/jquery.min.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/jquery.min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/json2.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/json2.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/underscore-min.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/underscore-min.js')}"></script>
...@@ -40,6 +38,9 @@ ...@@ -40,6 +38,9 @@
<script src="${static.url('js/vendor/jquery.cookie.js')}"></script> <script src="${static.url('js/vendor/jquery.cookie.js')}"></script>
<script src="${static.url('js/vendor/jquery.leanModal.min.js')}"></script> <script src="${static.url('js/vendor/jquery.leanModal.min.js')}"></script>
<script src="${static.url('js/vendor/jquery.tablednd.js')}"></script> <script src="${static.url('js/vendor/jquery.tablednd.js')}"></script>
<%block name="content"></%block>
</body> </body>
</html> </html>
......
Someone, hopefully you, signed up for an account for edX's on-line
offering of "${ course_title}" using this email address. If it was
you, and you'd like to activate and use your account, copy and paste
this address into your web browser's address bar:
% if is_secure:
https://${ site }/activate/${ key }
% else:
http://edx4edx.mitx.mit.edu/activate/${ key }
% endif
If you didn't request this, you don't need to do anything; you won't
receive any more email from us. Please do not reply to this e-mail; if
you require assistance, check the help section of the edX web site.
Your account for edX's on-line ${course_title} course
<%inherit file="base.html" />
\ No newline at end of file
<%inherit file="base.html" />
<%block name="title">Sign up</%block>
<%block name="content">
<section class="main-container">
<section class="main-content">
<header>
<h3>Sign Up for edX</h3>
<hr>
</header>
<div id="enroll">
<form id="enroll_form" method="post">
<div id="enroll_error" name="enroll_error"></div>
<label>E-mail</label>
<input name="email" type="email" placeholder="E-mail">
<label>Password</label>
<input name="password" type="password" placeholder="Password">
<label>Public Username</label>
<input name="username" type="text" placeholder="Public Username">
<label>Full Name</label>
<input name="name" type="text" placeholder="Full Name">
<label>Your Location</label>
<input name="location" type="text" placeholder="Your Location">
<label>Preferred Language</label>
<input name="language" type="text" placeholder="Preferred Language">
<label class="terms-of-service">
<input name="terms_of_service" type="checkbox" value="true">
I agree to the
<a href="#">Terms of Service</a>
</label>
<!-- no honor code for CMS, but need it because we're using the lms student object -->
<input name="honor_code" type="checkbox" value="true" checked="true" hidden="true">
<div class="submit">
<input name="submit" type="submit" value="Create My Account">
</div>
</form>
<section class="login-extra">
<p>
<span>Already have an account? <a href="#">Login.</a></span>
</p>
</section>
</div>
<script type="text/javascript">
(function() {
function getCookie(name) {
return $.cookie(name);
}
function postJSON(url, data, callback) {
$.ajax({type:'POST',
url: url,
dataType: 'json',
data: data,
success: callback,
headers : {'X-CSRFToken':getCookie('csrftoken')}
});
}
$('form#enroll_form').submit(function(e) {
e.preventDefault();
var submit_data = $('#enroll_form').serialize();
postJSON('/create_account',
submit_data,
function(json) {
if(json.success) {
$('#enroll').html(json.value);
} else {
$('#enroll_error').html(json.value).stop().css("background-color", "#933").animate({ backgroundColor: "#333"}, 2000);
}
}
);
});
})(this)
</script>
</section>
</section>
</%block>
from django.conf import settings from django.conf import settings
from django.conf.urls.defaults import patterns, include, url from django.conf.urls.defaults import patterns, include, url
import django.contrib.auth.views
# Uncomment the next two lines to enable the admin: # Uncomment the next two lines to enable the admin:
# from django.contrib import admin # from django.contrib import admin
# admin.autodiscover() # admin.autodiscover()
...@@ -13,6 +15,14 @@ urlpatterns = ('', ...@@ -13,6 +15,14 @@ urlpatterns = ('',
url(r'^github_service_hook$', 'github_sync.views.github_post_receive'), url(r'^github_service_hook$', 'github_sync.views.github_post_receive'),
) )
# User creation and updating views
urlpatterns += (
url(r'^signup$', 'contentstore.views.signup'),
url(r'^create_account$', 'student.views.create_account'),
url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account'),
)
if settings.DEBUG: if settings.DEBUG:
## Jasmine ## Jasmine
urlpatterns=urlpatterns + (url(r'^_jasmine/', include('django_jasmine.urls')),) urlpatterns=urlpatterns + (url(r'^_jasmine/', include('django_jasmine.urls')),)
......
...@@ -143,15 +143,15 @@ def create_account(request, post_override=None): ...@@ -143,15 +143,15 @@ def create_account(request, post_override=None):
# Confirm we have a properly formed request # Confirm we have a properly formed request
for a in ['username', 'email', 'password', 'location', 'language', 'name']: for a in ['username', 'email', 'password', 'location', 'language', 'name']:
if a not in post_vars: if a not in post_vars:
js['value']="Error (401 {field}). E-mail us.".format(field=a) js['value'] = "Error (401 {field}). E-mail us.".format(field=a)
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
if post_vars['honor_code']!=u'true': if 'honor_code' not in post_vars or post_vars['honor_code'] != u'true':
js['value']="To enroll, you must follow the honor code.".format(field=a) js['value']="To enroll, you must follow the honor code.".format(field=a)
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
if post_vars['terms_of_service']!=u'true': if 'terms_of_service' not in post_vars or post_vars['terms_of_service'] != u'true':
js['value']="You must accept the terms of service.".format(field=a) js['value']="You must accept the terms of service.".format(field=a)
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
...@@ -161,7 +161,7 @@ def create_account(request, post_override=None): ...@@ -161,7 +161,7 @@ def create_account(request, post_override=None):
# this is a good idea # this is a good idea
# TODO: Check password is sane # TODO: Check password is sane
for a in ['username', 'email', 'name', 'password', 'terms_of_service', 'honor_code']: for a in ['username', 'email', 'name', 'password', 'terms_of_service', 'honor_code']:
if len(post_vars[a])<2: if len(post_vars[a]) < 2:
error_str = {'username' : 'Username of length 2 or greater', error_str = {'username' : 'Username of length 2 or greater',
'email' : 'Properly formatted e-mail', 'email' : 'Properly formatted e-mail',
'name' : 'Your legal name ', 'name' : 'Your legal name ',
...@@ -183,25 +183,23 @@ def create_account(request, post_override=None): ...@@ -183,25 +183,23 @@ def create_account(request, post_override=None):
js['value']="Username should only consist of A-Z and 0-9.".format(field=a) js['value']="Username should only consist of A-Z and 0-9.".format(field=a)
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
u = User(username=post_vars['username'],
email=post_vars['email'],
u=User(username=post_vars['username'], is_active=False)
email=post_vars['email'],
is_active=False)
u.set_password(post_vars['password']) u.set_password(post_vars['password'])
r=Registration() r = Registration()
# TODO: Rearrange so that if part of the process fails, the whole process fails. # 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 # Right now, we can have e.g. no registration e-mail sent out and a zombie account
try: try:
u.save() u.save()
except IntegrityError: except IntegrityError:
# Figure out the cause of the integrity error # Figure out the cause of the integrity error
if len(User.objects.filter(username=post_vars['username']))>0: if len(User.objects.filter(username=post_vars['username'])) > 0:
js['value']="An account with this username already exists." js['value'] = "An account with this username already exists."
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
if len(User.objects.filter(email=post_vars['email']))>0: if len(User.objects.filter(email=post_vars['email'])) > 0:
js['value']="An account with this e-mail already exists." js['value'] = "An account with this e-mail already exists."
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
raise raise
...@@ -209,36 +207,37 @@ def create_account(request, post_override=None): ...@@ -209,36 +207,37 @@ def create_account(request, post_override=None):
r.register(u) r.register(u)
up = UserProfile(user=u) up = UserProfile(user=u)
up.name=post_vars['name'] up.name = post_vars['name']
up.language=post_vars['language'] up.language = post_vars['language']
up.location=post_vars['location'] up.location = post_vars['location']
up.save() up.save()
d={'name':post_vars['name'], # TODO (vshnayder): the LMS should probably allow signups without a particular course too
'key':r.activation_key, d = {'name': post_vars['name'],
'course_title' : settings.COURSE_TITLE, 'key': r.activation_key,
} 'course_title': getattr(settings, 'COURSE_TITLE', ''),
}
subject = render_to_string('emails/activation_email_subject.txt',d) subject = render_to_string('emails/activation_email_subject.txt', d)
# Email subject *must not* contain newlines # Email subject *must not* contain newlines
subject = ''.join(subject.splitlines()) subject = ''.join(subject.splitlines())
message = render_to_string('emails/activation_email.txt',d) message = render_to_string('emails/activation_email.txt', d)
try: try:
if settings.MITX_FEATURES.get('REROUTE_ACTIVATION_EMAIL'): if settings.MITX_FEATURES.get('REROUTE_ACTIVATION_EMAIL'):
dest_addr = settings.MITX_FEATURES['REROUTE_ACTIVATION_EMAIL'] dest_addr = settings.MITX_FEATURES['REROUTE_ACTIVATION_EMAIL']
message = "Activation for %s (%s): %s\n" % (u,u.email,up.name) + '-'*80 + '\n\n' + message message = "Activation for %s (%s): %s\n" % (u,u.email,up.name) + '-' * 80 + '\n\n' + message
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False)
elif not settings.GENERATE_RANDOM_USER_CREDENTIALS: elif not settings.GENERATE_RANDOM_USER_CREDENTIALS:
res=u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) res = u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
except: except:
log.exception(sys.exc_info()) log.exception(sys.exc_info())
js['value']='Could not send activation e-mail.' js['value'] = 'Could not send activation e-mail.'
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
js={'success':True, js={'success': True,
'value':render_to_string('registration/reg_complete.html', {'email':post_vars['email'], 'value': render_to_string('registration/reg_complete.html', {'email': post_vars['email'],
'csrf':csrf(request)['csrf_token']})} 'csrf': csrf(request)['csrf_token']})}
return HttpResponse(json.dumps(js), mimetype="application/json") return HttpResponse(json.dumps(js), mimetype="application/json")
def create_random_account(create_account_function): def create_random_account(create_account_function):
......
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