Commit 863071c9 by Bridger Maxwell

Merge remote-tracking branch 'origin/release/1.0' into uc_berkeley_press

Conflicts:
	lms/urls.py
parents 126ff06f b7a389df
...@@ -6,11 +6,7 @@ ...@@ -6,11 +6,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:css group='base-style'/> <%static:css group='base-style'/>
% else:
<link rel="stylesheet" href="${static.url('css/base-style.css')}">
% endif
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/markitup/skins/simple/style.css')}" /> <link rel="stylesheet" type="text/css" href="${static.url('js/vendor/markitup/skins/simple/style.css')}" />
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/markitup/sets/wiki/style.css')}" /> <link rel="stylesheet" type="text/css" href="${static.url('js/vendor/markitup/sets/wiki/style.css')}" />
<title><%block name="title"></%block></title> <title><%block name="title"></%block></title>
...@@ -27,12 +23,7 @@ ...@@ -27,12 +23,7 @@
<script type="text/javascript" src="${static.url('js/vendor/backbone-min.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/backbone-min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/markitup/jquery.markitup.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/markitup/jquery.markitup.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/markitup/sets/wiki/set.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/markitup/sets/wiki/set.js')}"></script>
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:js group='main'/> <%static:js group='main'/>
% else:
<script src="${ STATIC_URL }/js/main.js"></script>
% endif
<%static:js group='module-js'/> <%static:js group='module-js'/>
<script src="${static.url('js/vendor/jquery.inlineedit.js')}"></script> <script src="${static.url('js/vendor/jquery.inlineedit.js')}"></script>
<script src="${static.url('js/vendor/jquery.cookie.js')}"></script> <script src="${static.url('js/vendor/jquery.cookie.js')}"></script>
......
...@@ -10,10 +10,10 @@ ...@@ -10,10 +10,10 @@
<hr> <hr>
</header> </header>
<div id="enroll"> <div id="register">
<form id="enroll_form" method="post"> <form id="register_form" method="post">
<div id="enroll_error" name="enroll_error"></div> <div id="register_error" name="register_error"></div>
<label>E-mail</label> <label>E-mail</label>
<input name="email" type="email" placeholder="E-mail"> <input name="email" type="email" placeholder="E-mail">
<label>Password</label> <label>Password</label>
...@@ -64,17 +64,17 @@ ...@@ -64,17 +64,17 @@
}); });
} }
$('form#enroll_form').submit(function(e) { $('form#register_form').submit(function(e) {
e.preventDefault(); e.preventDefault();
var submit_data = $('#enroll_form').serialize(); var submit_data = $('#register_form').serialize();
postJSON('/create_account', postJSON('/create_account',
submit_data, submit_data,
function(json) { function(json) {
if(json.success) { if(json.success) {
$('#enroll').html(json.value); $('#register').html(json.value);
} else { } 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);
} }
} }
); );
......
...@@ -5,6 +5,24 @@ from static_replace import replace_urls ...@@ -5,6 +5,24 @@ from static_replace import replace_urls
%> %>
<%def name='url(file)'>${staticfiles_storage.url(file)}</%def> <%def name='url(file)'>${staticfiles_storage.url(file)}</%def>
<%def name='css(group)'>${compressed_css(group)}</%def>
<%def name='js(group)'>${compressed_js(group)}</%def> <%def name='css(group)'>
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
${compressed_css(group)}
% else:
% for filename in settings.PIPELINE_CSS[group]['source_filenames']:
<link rel="stylesheet" href="${staticfiles_storage.url(filename.replace('.scss', '.css'))}" type="text/css" media="all" / >
% endfor
%endif
</%def>
<%def name='js(group)'>
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
${compressed_js(group)}
% else:
% for filename in settings.PIPELINE_JS[group]['source_filenames']:
<script type="text/javascript" src="${staticfiles_storage.url(filename.replace('.coffee', '.js'))}"></script>
% endfor
%endif
</%def>
<%def name='replace_urls(text)'>${replace_urls(text)}</%def> <%def name='replace_urls(text)'>${replace_urls(text)}</%def>
...@@ -8,19 +8,22 @@ from django.db import models ...@@ -8,19 +8,22 @@ from django.db import models
class Migration(SchemaMigration): class Migration(SchemaMigration):
def forwards(self, orm): def forwards(self, orm):
# Removing unique constraint on 'CourseEnrollment', fields ['user'] # This table is dropped in a subsequent migration. This migration was causing problems when using InnoDB,
db.delete_unique('student_courseenrollment', ['user_id']) # so we are just dropping it.
pass
# # Removing unique constraint on 'CourseEnrollment', fields ['user']
# Changing field 'CourseEnrollment.user' # db.delete_unique('student_courseenrollment', ['user_id'])
db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])) #
#
# # 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): def backwards(self, orm):
pass
# Changing field 'CourseEnrollment.user' # # 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)) # 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'] # # Adding unique constraint on 'CourseEnrollment', fields ['user']
db.create_unique('student_courseenrollment', ['user_id']) # db.create_unique('student_courseenrollment', ['user_id'])
models = { models = {
......
...@@ -8,14 +8,70 @@ from django.db import models ...@@ -8,14 +8,70 @@ from django.db import models
class Migration(SchemaMigration): class Migration(SchemaMigration):
def forwards(self, orm): def forwards(self, orm):
# Deleting field 'UserProfile.occupation'
db.delete_column('auth_userprofile', 'occupation')
# Deleting field 'UserProfile.telephone_number'
db.delete_column('auth_userprofile', 'telephone_number')
# Deleting field 'UserProfile.date_of_birth'
db.delete_column('auth_userprofile', 'date_of_birth')
# Deleting field 'UserProfile.country'
db.delete_column('auth_userprofile', 'country')
# Adding field 'UserProfile.year_of_birth'
db.add_column('auth_userprofile', 'year_of_birth',
self.gf('django.db.models.fields.IntegerField')(db_index=True, null=True, blank=True),
keep_default=False)
# Adding field 'UserProfile.level_of_education'
db.add_column('auth_userprofile', 'level_of_education',
self.gf('django.db.models.fields.CharField')(db_index=True, max_length=6, null=True, blank=True),
keep_default=False)
# Adding field 'UserProfile.goals'
db.add_column('auth_userprofile', 'goals',
self.gf('django.db.models.fields.TextField')(null=True, blank=True),
keep_default=False)
# Adding index on 'UserProfile', fields ['gender']
db.create_index('auth_userprofile', ['gender'])
# Changing field 'UserProfile.country'
db.alter_column('auth_userprofile', 'country', self.gf('django_countries.fields.CountryField')(max_length=2, null=True))
def backwards(self, orm): def backwards(self, orm):
# Removing index on 'UserProfile', fields ['gender']
db.delete_index('auth_userprofile', ['gender'])
# Adding field 'UserProfile.occupation'
db.add_column('auth_userprofile', 'occupation',
self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
keep_default=False)
# Adding field 'UserProfile.telephone_number'
db.add_column('auth_userprofile', 'telephone_number',
self.gf('django.db.models.fields.CharField')(max_length=25, null=True, blank=True),
keep_default=False)
# Adding field 'UserProfile.date_of_birth'
db.add_column('auth_userprofile', 'date_of_birth',
self.gf('django.db.models.fields.DateField')(null=True, blank=True),
keep_default=False)
# Adding field 'UserProfile.country'
db.add_column('auth_userprofile', 'country',
self.gf('django_countries.fields.CountryField')(max_length=2, null=True, blank=True),
keep_default=False)
# Deleting field 'UserProfile.year_of_birth'
db.delete_column('auth_userprofile', 'year_of_birth')
# Deleting field 'UserProfile.level_of_education'
db.delete_column('auth_userprofile', 'level_of_education')
# Deleting field 'UserProfile.goals'
db.delete_column('auth_userprofile', 'goals')
# Changing field 'UserProfile.country'
db.alter_column('auth_userprofile', 'country', self.gf('django.db.models.fields.CharField')(max_length=255, null=True))
models = { models = {
'auth.group': { 'auth.group': {
...@@ -80,8 +136,9 @@ class Migration(SchemaMigration): ...@@ -80,8 +136,9 @@ class Migration(SchemaMigration):
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}, },
'student.courseenrollment': { 'student.courseenrollment': {
'Meta': {'object_name': 'CourseEnrollment'}, 'Meta': {'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
}, },
...@@ -107,19 +164,18 @@ class Migration(SchemaMigration): ...@@ -107,19 +164,18 @@ class Migration(SchemaMigration):
}, },
'student.userprofile': { 'student.userprofile': {
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"}, 'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}), 'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), 'gender': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
'gender': ('django.db.models.fields.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}), 'goals': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}), 'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'level_of_education': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '6', 'null': 'True', 'blank': 'True'}),
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}), 'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), 'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'meta': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), 'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}), 'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
'telephone_number': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}), 'year_of_birth': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
}, },
'student.usertestgroup': { 'student.usertestgroup': {
'Meta': {'object_name': 'UserTestGroup'}, 'Meta': {'object_name': 'UserTestGroup'},
......
...@@ -5,14 +5,15 @@ If you make changes to this model, be sure to create an appropriate migration ...@@ -5,14 +5,15 @@ If you make changes to this model, be sure to create an appropriate migration
file and check it in at the same time as your model changes. To do that, file and check it in at the same time as your model changes. To do that,
1. Go to the mitx dir 1. Go to the mitx dir
2. ./manage.py schemamigration user --auto description_of_your_change 2. django-admin.py schemamigration student --auto --settings=lms.envs.dev --pythonpath=. description_of_your_change
3. Add the migration file created in mitx/courseware/migrations/ 3. Add the migration file created in mitx/common/djangoapps/student/migrations/
""" """
from datetime import datetime
import json
import uuid import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
import json
from django_countries import CountryField from django_countries import CountryField
#from cache_toolbox import cache_model, cache_relation #from cache_toolbox import cache_model, cache_relation
...@@ -21,23 +22,43 @@ class UserProfile(models.Model): ...@@ -21,23 +22,43 @@ class UserProfile(models.Model):
class Meta: class Meta:
db_table = "auth_userprofile" db_table = "auth_userprofile"
GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'), ('o', 'Other'))
## CRITICAL TODO/SECURITY ## CRITICAL TODO/SECURITY
# Sanitize all fields. # Sanitize all fields.
# This is not visible to other users, but could introduce holes later # This is not visible to other users, but could introduce holes later
user = models.OneToOneField(User, unique=True, db_index=True, related_name='profile') user = models.OneToOneField(User, unique=True, db_index=True, related_name='profile')
name = models.CharField(blank=True, max_length=255, db_index=True) name = models.CharField(blank=True, max_length=255, db_index=True)
language = models.CharField(blank=True, max_length=255, db_index=True)
location = models.CharField(blank=True, max_length=255, db_index=True) # TODO: What are we doing with this?
meta = models.TextField(blank=True) # JSON dictionary for future expansion meta = models.TextField(blank=True) # JSON dictionary for future expansion
courseware = models.CharField(blank=True, max_length=255, default='course.xml') courseware = models.CharField(blank=True, max_length=255, default='course.xml')
gender = models.CharField(blank=True, null=True, max_length=6, choices=GENDER_CHOICES)
date_of_birth = models.DateField(blank=True, null=True) # Location is no longer used, but is held here for backwards compatibility
# for users imported from our first class.
language = models.CharField(blank=True, max_length=255, db_index=True)
location = models.CharField(blank=True, max_length=255, db_index=True)
# Optional demographic data we started capturing from Fall 2012
this_year = datetime.now().year
VALID_YEARS = range(this_year, this_year - 120, -1)
year_of_birth = models.IntegerField(blank=True, null=True, db_index=True)
GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'), ('o', 'Other'))
gender = models.CharField(blank=True, null=True, max_length=6, db_index=True,
choices=GENDER_CHOICES)
LEVEL_OF_EDUCATION_CHOICES = (('p_se', 'Doctorate in science or engineering'),
('p_oth', 'Doctorate in another field'),
('m', "Master's or professional degree"),
('b', "Bachelor's degree"),
('hs', "Secondary/high school"),
('jhs', "Junior secondary/junior high/middle school"),
('el', "Elementary/primary school"),
('none', "None"),
('other', "Other"))
level_of_education = models.CharField(
blank=True, null=True, max_length=6, db_index=True,
choices=LEVEL_OF_EDUCATION_CHOICES
)
mailing_address = models.TextField(blank=True, null=True) mailing_address = models.TextField(blank=True, null=True)
country = CountryField(blank=True, null=True) goals = models.TextField(blank=True, null=True)
telephone_number = models.CharField(blank=True, null=True, max_length=25)
occupation = models.CharField(blank=True, null=True, max_length=255)
def get_meta(self): def get_meta(self):
js_str = self.meta js_str = self.meta
......
...@@ -71,26 +71,25 @@ def index(request): ...@@ -71,26 +71,25 @@ def index(request):
for entry in entries: for entry in entries:
soup = BeautifulSoup(entry.description) soup = BeautifulSoup(entry.description)
entry.image = soup.img['src'] if soup.img else None entry.image = soup.img['src'] if soup.img else None
entry.summary = soup.getText()
courses = modulestore().get_courses()
universities = defaultdict(list) universities = defaultdict(list)
for university, group in itertools.groupby(courses, lambda course: course.org): courses = sorted(modulestore().get_courses(), key=lambda course: course.number)
[universities[university].append(course) for course in group] for course in courses:
universities[course.org].append(course)
return render_to_response('index.html', {'universities': universities, 'entries': entries}) 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 @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def dashboard(request): def dashboard(request):
csrf_token = csrf(request)['csrf_token']
user = request.user user = request.user
enrollments = CourseEnrollment.objects.filter(user=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 # 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 # exist (because the course IDs have changed). Still, we don't delete those
# enrollments, because it could have been a data push snafu. # enrollments, because it could have been a data push snafu.
...@@ -102,17 +101,79 @@ def dashboard(request): ...@@ -102,17 +101,79 @@ def dashboard(request):
log.error("User {0} enrolled in non-existant course {1}" log.error("User {0} enrolled in non-existant course {1}"
.format(user.username, enrollment.course_id)) .format(user.username, enrollment.course_id))
context = {'csrf': csrf_token, 'courses': courses}
message = ""
if not user.is_active:
message = render_to_string('registration/activate_account_notice.html', {'email': user.email})
context = {'courses': courses, 'message' : message}
return render_to_response('dashboard.html', context) 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 # Need different levels of logging
@ensure_csrf_cookie @ensure_csrf_cookie
def login_user(request, error=""): def login_user(request, error=""):
''' AJAX request to log in the user. ''' ''' AJAX request to log in the user. '''
if 'email' not in request.POST or 'password' not in request.POST: if 'email' not in request.POST or 'password' not in request.POST:
return HttpResponse(json.dumps({'success': False, 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'] email = request.POST['email']
password = request.POST['password'] password = request.POST['password']
...@@ -121,14 +182,14 @@ def login_user(request, error=""): ...@@ -121,14 +182,14 @@ def login_user(request, error=""):
except User.DoesNotExist: except User.DoesNotExist:
log.warning("Login failed - Unknown user email: {0}".format(email)) log.warning("Login failed - Unknown user email: {0}".format(email))
return HttpResponse(json.dumps({'success': False, 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 username = user.username
user = authenticate(username=username, password=password) user = authenticate(username=username, password=password)
if user is None: if user is None:
log.warning("Login failed - password for {0} is invalid".format(email)) log.warning("Login failed - password for {0} is invalid".format(email))
return HttpResponse(json.dumps({'success': False, return HttpResponse(json.dumps({'success': False,
'error': 'Invalid login'})) 'value': 'Email or password is incorrect.'}))
if user is not None and user.is_active: if user is not None and user.is_active:
try: try:
...@@ -143,11 +204,14 @@ def login_user(request, error=""): ...@@ -143,11 +204,14 @@ def login_user(request, error=""):
log.exception(e) log.exception(e)
log.info("Login success - {0} ({1})".format(username, email)) log.info("Login success - {0} ({1})".format(username, email))
try_change_enrollment(request)
return HttpResponse(json.dumps({'success':True})) return HttpResponse(json.dumps({'success':True}))
log.warning("Login failed - Account not active for user {0}".format(username)) log.warning("Login failed - Account not active for user {0}".format(username))
return HttpResponse(json.dumps({'success':False, 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 @ensure_csrf_cookie
def logout_user(request): def logout_user(request):
...@@ -243,17 +307,20 @@ def create_account(request, post_override=None): ...@@ -243,17 +307,20 @@ def create_account(request, post_override=None):
up = UserProfile(user=u) up = UserProfile(user=u)
up.name = post_vars['name'] up.name = post_vars['name']
up.country = post_vars['country'] up.level_of_education = post_vars['level_of_education']
up.gender = post_vars['gender'] up.gender = post_vars['gender']
up.mailing_address = post_vars['mailing_address'] up.mailing_address = post_vars['mailing_address']
up.goals = post_vars['goals']
date_fields = ['date_of_birth__year', 'date_of_birth__month', 'date_of_birth__day'] try:
if all(len(post_vars[field]) > 0 for field in date_fields): up.year_of_birth = int(post_vars['year_of_birth'])
up.date_of_birth = date(int(post_vars['date_of_birth__year']), except ValueError:
int(post_vars['date_of_birth__month']), up.year_of_birth = None # If they give us garbage, just ignore it instead
int(post_vars['date_of_birth__day'])) # of asking them to put an integer.
try:
up.save() up.save()
except Exception:
log.exception("UserProfile creation failed for user {0}.".format(u.id))
d = {'name': post_vars['name'], d = {'name': post_vars['name'],
'key': r.activation_key, 'key': r.activation_key,
...@@ -276,9 +343,16 @@ def create_account(request, post_override=None): ...@@ -276,9 +343,16 @@ def create_account(request, post_override=None):
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, # Immediately after a user creates an account, we log them in. They are only
'value': render_to_string('registration/reg_complete.html', {'email': post_vars['email'], # logged in until they close the browser. They can't log in again until they click
'csrf': csrf(request)['csrf_token']})} # 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") return HttpResponse(json.dumps(js), mimetype="application/json")
def create_random_account(create_account_function): def create_random_account(create_account_function):
...@@ -308,14 +382,15 @@ def activate_account(request, key): ...@@ -308,14 +382,15 @@ def activate_account(request, key):
''' '''
r=Registration.objects.filter(activation_key=key) r=Registration.objects.filter(activation_key=key)
if len(r)==1: if len(r)==1:
user_logged_in = request.user.is_authenticated()
already_active = True
if not r[0].user.is_active: if not r[0].user.is_active:
r[0].activate() r[0].activate()
resp = render_to_response("activation_complete.html",{'csrf':csrf(request)['csrf_token']}) already_active = False
return resp resp = render_to_response("registration/activation_complete.html",{'user_logged_in':user_logged_in, 'already_active' : already_active})
resp = render_to_response("activation_active.html",{'csrf':csrf(request)['csrf_token']})
return resp return resp
if len(r)==0: 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.") return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.")
@ensure_csrf_cookie @ensure_csrf_cookie
......
...@@ -57,10 +57,10 @@ def format_url_params(params): ...@@ -57,10 +57,10 @@ def format_url_params(params):
@cache_if_anonymous @cache_if_anonymous
def courses(request): def courses(request):
# TODO: Clean up how 'error' is done. # TODO: Clean up how 'error' is done.
courses = modulestore().get_courses() courses = sorted(modulestore().get_courses(), key=lambda course: course.number)
universities = defaultdict(list) universities = defaultdict(list)
for university, group in itertools.groupby(courses, lambda course: course.org): for course in courses:
[universities[university].append(course) for course in group] universities[course.org].append(course)
return render_to_response("courses.html", { 'universities': universities }) return render_to_response("courses.html", { 'universities': universities })
...@@ -271,44 +271,11 @@ def course_about(request, course_id): ...@@ -271,44 +271,11 @@ def course_about(request, course_id):
return render_to_response('portal/course_about.html', {'course': course, 'registered': registered}) 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.'}))
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_if_anonymous @cache_if_anonymous
def university_profile(request, org_id): def university_profile(request, org_id):
all_courses = modulestore().get_courses() all_courses = sorted(modulestore().get_courses(), key=lambda course: course.number)
valid_org_ids = set(c.org for c in all_courses) valid_org_ids = set(c.org for c in all_courses)
if org_id not in valid_org_ids: if org_id not in valid_org_ids:
raise Http404("University Profile not found for {0}".format(org_id)) raise Http404("University Profile not found for {0}".format(org_id))
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'UserProfile.location'
db.alter_column('auth_userprofile', 'location', self.gf('django.db.models.fields.CharField')(max_length=255, null=True))
def backwards(self, orm):
# Changing field 'UserProfile.location'
db.alter_column('auth_userprofile', 'location', self.gf('django.db.models.fields.CharField')(default='', max_length=255))
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'student.courseenrollment': {
'Meta': {'object_name': 'CourseEnrollment'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'student.pendingemailchange': {
'Meta': {'object_name': 'PendingEmailChange'},
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'new_email': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'student.pendingnamechange': {
'Meta': {'object_name': 'PendingNameChange'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'new_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'rationale': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'student.registration': {
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'student.userprofile': {
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'gender': ('django.db.models.fields.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'mailing_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'meta': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'telephone_number': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
},
'student.usertestgroup': {
'Meta': {'object_name': 'UserTestGroup'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
}
}
complete_apps = ['student']
\ No newline at end of file
...@@ -293,6 +293,10 @@ PIPELINE_CSS = { ...@@ -293,6 +293,10 @@ PIPELINE_CSS = {
'source_filenames': ['sass/application.scss'], 'source_filenames': ['sass/application.scss'],
'output_filename': 'css/application.css', 'output_filename': 'css/application.css',
}, },
'course': {
'source_filenames': ['sass/application.scss', 'css/vendor/codemirror.css', 'css/vendor/jquery.treeview.css'],
'output_filename': 'css/course.css',
},
'ie-fixes': { 'ie-fixes': {
'source_filenames': ['sass/ie.scss'], 'source_filenames': ['sass/ie.scss'],
'output_filename': 'css/ie.css', 'output_filename': 'css/ie.css',
...@@ -301,11 +305,47 @@ PIPELINE_CSS = { ...@@ -301,11 +305,47 @@ PIPELINE_CSS = {
PIPELINE_ALWAYS_RECOMPILE = ['sass/application.scss', 'sass/ie.scss'] PIPELINE_ALWAYS_RECOMPILE = ['sass/application.scss', 'sass/ie.scss']
courseware_only_js = [
PROJECT_ROOT / 'static/coffee/src/' + pth + '.coffee'
for pth
in ['courseware', 'histogram', 'navigation', 'time', ]
]
courseware_only_js += [
pth for pth
in glob2.glob(PROJECT_ROOT / 'static/coffee/src/modules/**/*.coffee')
]
main_vendor_js = [
'js/vendor/jquery.min.js',
'js/vendor/jquery-ui.min.js',
'js/vendor/swfobject/swfobject.js',
'js/vendor/jquery.cookie.js',
'js/vendor/jquery.qtip.min.js',
]
PIPELINE_JS = { PIPELINE_JS = {
'application': { 'application': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee')], # Application will contain all paths not in courseware_only_js
'source_filenames': [
pth.replace(PROJECT_ROOT / 'static/', '')
for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee')\
if pth not in courseware_only_js
] + [
'js/form.ext.js',
'js/my_courses_dropdown.js',
'js/toggle_login_modal.js',
'js/sticky_filter.js',
],
'output_filename': 'js/application.js' 'output_filename': 'js/application.js'
}, },
'courseware': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in courseware_only_js],
'output_filename': 'js/courseware.js'
},
'main_vendor': {
'source_filenames': main_vendor_js,
'output_filename': 'js/main_vendor.js',
},
'spec': { 'spec': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')], 'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
'output_filename': 'js/spec.js' 'output_filename': 'js/spec.js'
......
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
position: 'fixed' position: 'fixed'
} }
if ($("#lean_overlay").length == 0) {
var overlay = $("<div id='lean_overlay'></div>"); var overlay = $("<div id='lean_overlay'></div>");
$("body").append(overlay); $("body").append(overlay);
}
options = $.extend(defaults, options); options = $.extend(defaults, options);
...@@ -51,7 +53,11 @@ ...@@ -51,7 +53,11 @@
$(modal_id).find(".notice").hide().html(""); $(modal_id).find(".notice").hide().html("");
var notice = $(this).data('notice') var notice = $(this).data('notice')
if(notice !== undefined) { 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); window.scrollTo(0, 0);
e.preventDefault(); e.preventDefault();
...@@ -71,8 +77,13 @@ ...@@ -71,8 +77,13 @@
$(this).leanModal({ top : 120, overlay: 1, closeButton: ".close-modal", position: 'absolute' }); $(this).leanModal({ top : 120, overlay: 1, closeButton: ".close-modal", position: 'absolute' });
embed = $($(this).attr('href')).find('iframe') embed = $($(this).attr('href')).find('iframe')
if(embed.length > 0) { if(embed.length > 0) {
embed.data('src', embed.attr('src') + '?autoplay=1'); if(embed.attr('src').indexOf("?") > 0) {
embed.data('src', embed.attr('src') + '&autoplay=1&rel=0');
embed.attr('src', '');
} else {
embed.data('src', embed.attr('src') + '?autoplay=1&rel=0');
embed.attr('src', ''); embed.attr('src', '');
} }
}
}); });
})(jQuery); })(jQuery);
...@@ -8,13 +8,6 @@ ...@@ -8,13 +8,6 @@
@import 'base/extends'; @import 'base/extends';
@import 'base/animations'; @import 'base/animations';
// Courseware styles
@import 'sass_old/base/variables';
@import 'sass_old/base/extends';
@import 'sass_old/base/functions';
// Multicourse styles // Multicourse styles
@import 'shared/forms'; @import 'shared/forms';
@import 'shared/footer'; @import 'shared/footer';
...@@ -24,22 +17,12 @@ ...@@ -24,22 +17,12 @@
@import 'shared/modal'; @import 'shared/modal';
@import 'shared/activation_messages'; @import 'shared/activation_messages';
@import 'home'; @import 'multicourse/home';
@import 'dashboard'; @import 'multicourse/dashboard';
@import 'courseware_subnav'; @import 'multicourse/courses';
@import 'courses'; @import 'multicourse/course_about';
@import 'course_about'; @import 'multicourse/jobs';
@import 'jobs'; @import 'multicourse/about_pages';
@import 'about_pages'; @import 'multicourse/press_release';
@import 'press_release'; @import 'multicourse/password_reset';
@import 'password_reset'; @import 'multicourse/error-pages';
@import 'error-pages';
// Courseware styles
@import 'sass_old/courseware/courseware';
@import 'sass_old/courseware/sequence-nav';
@import 'sass_old/courseware/sidebar';
@import 'sass_old/courseware/video';
@import 'sass_old/courseware/amplifier';
@import 'sass_old/courseware/problems';
/* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 25, 2012 05:06:34 PM America/New_York */ /* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 25, 2012 05:06:34 PM America/New_York */
@font-face { @font-face {
font-family: 'Open Sans'; font-family: 'Open Sans';
src: url('../fonts/OpenSans-Light-webfont.eot'); src: url('../fonts/OpenSans-Light-webfont.eot');
...@@ -32,7 +31,7 @@ ...@@ -32,7 +31,7 @@
url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), url('../fonts/OpenSans-Regular-webfont.woff') format('woff'),
url('../fonts/OpenSans-Regular-webfont.ttf') format('truetype'), url('../fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
url('../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg'); url('../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
font-weight: 600; font-weight: 400;
font-style: normal; font-style: normal;
} }
...@@ -49,31 +48,6 @@ ...@@ -49,31 +48,6 @@
} }
// Not used in UI
// @font-face {
// font-family: 'Open Sans';
// src: url('../fonts/OpenSans-Semibold-webfont.eot');
// src: url('../fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'),
// url('../fonts/OpenSans-Semibold-webfont.woff') format('woff'),
// url('../fonts/OpenSans-Semibold-webfont.ttf') format('truetype'),
// url('../fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg');
// font-weight: 600;
// font-style: normal;
// }
// @font-face {
// font-family: 'Open Sans';
// src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot');
// src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'),
// url('../fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'),
// url('../fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'),
// url('../fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
// font-weight: 600;
// font-style: italic;
// }
@font-face { @font-face {
font-family: 'Open Sans'; font-family: 'Open Sans';
src: url('../fonts/OpenSans-Bold-webfont.eot'); src: url('../fonts/OpenSans-Bold-webfont.eot');
......
@import 'bourbon/bourbon';
@import 'base/reset';
@import 'base/font_face';
@import 'base/variables';
@import 'base/base';
@import 'base/mixins';
@import 'base/extends';
@import 'base/animations';
// Course styles
@import 'course/courseware_subnav';
// Courseware styles
@import 'course/old/base/variables';
@import 'course/old/base/extends';
@import 'course/old/base/functions';
@import 'course/old/courseware/courseware';
@import 'course/old/courseware/sequence-nav';
@import 'course/old/courseware/sidebar';
@import 'course/old/courseware/video';
@import 'course/old/courseware/amplifier';
@import 'course/old/courseware/problems';
...@@ -84,7 +84,7 @@ div.leanModal_box { ...@@ -84,7 +84,7 @@ div.leanModal_box {
form { form {
text-align: left; text-align: left;
div#enroll_error, div#login_error, div#pwd_error { div#register_error, div#login_error, div#pwd_error {
$error-color: #333; $error-color: #333;
background-color: $error-color; background-color: $error-color;
border: darken($error-color, 20%); border: darken($error-color, 20%);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
border-bottom: 1px solid rgb(80,80,80); border-bottom: 1px solid rgb(80,80,80);
@include box-shadow(0 1px 0 0 rgba(255,255,255, 0.9), inset 0 -1px 5px 0 rgba(0,0,0, 0.1)); @include box-shadow(0 1px 0 0 rgba(255,255,255, 0.9), inset 0 -1px 5px 0 rgba(0,0,0, 0.1));
@include clearfix; @include clearfix;
height: 430px; height: 460px;
margin-top: -69px; margin-top: -69px;
overflow: hidden; overflow: hidden;
padding: 0px; padding: 0px;
...@@ -17,10 +17,11 @@ ...@@ -17,10 +17,11 @@
.outer-wrapper { .outer-wrapper {
@extend .animation-home-header-pop-up; @extend .animation-home-header-pop-up;
margin: 0 auto; margin: 0 auto;
padding: 200px 10px 0px; padding: 240px 10px 0px;
position: relative; position: relative;
max-width: 1200px; max-width: 1200px;
min-width: 760px; min-width: 760px;
@include clearfix;
} }
.title { .title {
...@@ -30,29 +31,16 @@ ...@@ -30,29 +31,16 @@
@include box-shadow(0 4px 25px 0 rgba(0,0,0, 0.5)); @include box-shadow(0 4px 25px 0 rgba(0,0,0, 0.5));
@include box-sizing(border-box); @include box-sizing(border-box);
height: 120px; height: 120px;
@include inline-block; margin-left: grid-width(2) + $gw-gutter;
margin-left: grid-width(1) + $gw-gutter; float: left;
margin-right: $gw-gutter;
position: relative; position: relative;
text-align: center; text-align: center;
@include transition(all, 0.2s, linear); @include transition(all, 0.2s, linear);
vertical-align: top; vertical-align: top;
&:hover { &:hover {
height: 165px;
> hgroup {
h1 {
border-bottom: 1px solid rgb(200,200,200);
padding-bottom: 10px;
}
h2 {
opacity: 0;
}
}
.actions { .actions {
opacity: 1; display: none;
} }
} }
...@@ -80,123 +68,21 @@ ...@@ -80,123 +68,21 @@
text-transform: lowercase; text-transform: lowercase;
} }
} }
.actions {
@include clearfix;
@include box-sizing(border-box);
left: 0px;
opacity: 0;
padding: 20px 30px 0px;
position: absolute;
@include transition(opacity, 0.2s, linear);
top: 75px;
width: flex-grid(12);
.main-cta {
float: left;
margin-right: flex-gutter();
width: flex-grid(6);
> a.find-courses {
@include button(shiny, $blue);
@include box-sizing(border-box);
@include border-radius(3px);
display: block;
font: normal 1.2rem/1.6rem $sans-serif;
letter-spacing: 1px;
padding: 10px 0px;
text-transform: uppercase;
text-align: center;
width: flex-grid(12);
&:hover {
color: rgb(255,255,255);
}
} }
}
.secondary-actions {
@include box-sizing(border-box);
@include clearfix;
float: left;
width: flex-grid(6);
.social-sharing { .actions {
@include box-sizing(border-box); display: none;
float: left;
height: 44px;
margin-right: flex-gutter();
position: relative;
text-align: center;
width: flex-grid(12);
&:hover {
.sharing-message {
opacity: 1;
top: 50px;
}
}
.sharing-message {
@include background-image(linear-gradient(-90deg, rgba(0,0,0, 0.9) 0%,
rgba(0,0,0, 0.7) 100%));
border: 1px solid rgba(0,0,0, 0.5);
@include border-radius(4px);
@include box-shadow(0 4px 25px 0 rgba(0,0,0, 0.5));
@include box-sizing(border-box);
color: rgb(255,255,255);
float: right;
font-family: $serif;
font-size: 0.9em;
font-style: italic;
left: 50%;
margin-left: -110px;
opacity: 0;
padding: 6px 10px;
position: absolute;
text-align: center;
@include transition(all, 0.15s, ease-out);
top: 25px;
width: 220px;
&:hover {
opacity: 0;
}
}
.share {
height: 44px;
@include inline-block;
margin-right: 10px;
opacity: 0.5;
@include transition(all, 0.15s, linear);
width: 44px;
&:hover {
opacity: 1;
}
img {
width: 100%;
}
&:last-child {
margin-right: 0px;
}
}
}
}
}
} }
.media { .media {
background: #FFF; background: #FFF;
background: rgba(255,255,255, 0.93); background: rgba(255,255,255, 0.93);
border: 1px solid rgb(100,100,100); border: 1px solid rgb(100,100,100);
border-left: 0;
@include box-sizing(border-box); @include box-sizing(border-box);
@include box-shadow(0 4px 25px 0 rgba(0,0,0, 0.5)); // @include box-shadow(0 4px 25px 0 rgba(0,0,0, 0.5));
height: 120px; height: 120px;
@include inline-block; float: left;
padding: 4px; padding: 4px;
position: relative; position: relative;
vertical-align: top; vertical-align: top;
...@@ -249,8 +135,6 @@ ...@@ -249,8 +135,6 @@
} }
&:hover { &:hover {
cursor: pointer;
.play-intro { .play-intro {
@include background-image(linear-gradient(-90deg, rgba(0,0,0, 0.75), rgba(0,0,0, 0.8))); @include background-image(linear-gradient(-90deg, rgba(0,0,0, 0.75), rgba(0,0,0, 0.8)));
@include box-shadow(0 1px 12px 0 rgba(0,0,0, 0.5)); @include box-shadow(0 1px 12px 0 rgba(0,0,0, 0.5));
......
...@@ -210,7 +210,7 @@ ...@@ -210,7 +210,7 @@
.citizenship, .gender { .citizenship, .gender {
float: left; float: left;
width: flex-grid(6); width: flex-grid(4);
} }
.citizenship { .citizenship {
......
<%! 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>
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<p>We are always seeking feedback to improve our courses. If you are an enrolled student and have any questions, feedback, suggestions, or any other issues specific to a particular class, please post on the discussion forums of that class.</p> <p>We are always seeking feedback to improve our courses. If you are an enrolled student and have any questions, feedback, suggestions, or any other issues specific to a particular class, please post on the discussion forums of that class.</p>
<h2>General Inquiries and Feedback</h2> <h2>General Inquiries and Feedback</h2>
<p>"If you have a general question about edX please email <a href="mailto:info@edx.org">info@edx.org</a>. To see if your question has already been answered, visit our<a href="${reverse('faq_edx')}">FAQ page</a>. You can also join the discussion on our <a href="http://www.facebook.com/EdxOnline">facebook page</a>. Though we may not have a chance to respond to every email, we take all feedback into consideration.</p> <p>"If you have a general question about edX please email <a href="mailto:info@edx.org">info@edx.org</a>. To see if your question has already been answered, visit our <a href="${reverse('faq_edx')}">FAQ page</a>. You can also join the discussion on our <a href="http://www.facebook.com/EdxOnline">facebook page</a>. Though we may not have a chance to respond to every email, we take all feedback into consideration.</p>
<h2>Technical Inquiries and Feedback</h2> <h2>Technical Inquiries and Feedback</h2>
<p>If you have suggestions/feedback about the overall edX platform, or are facing general technical issues with the platform (e.g., issues with email addresses and passwords), you can reach us at <a href="mailto:technical@edx.org">technical@edx.org</a>. For technical questions, please make sure you are using a current version of Firefox or Chrome, and include browser and version in your e-mail, as well as screenshots or other pertinent details. If you find a bug or other issues, you can reach us at the following: <a href="mailto:bugs@edx.org">bugs@edx.org</a>.</p> <p>If you have suggestions/feedback about the overall edX platform, or are facing general technical issues with the platform (e.g., issues with email addresses and passwords), you can reach us at <a href="mailto:technical@edx.org">technical@edx.org</a>. For technical questions, please make sure you are using a current version of Firefox or Chrome, and include browser and version in your e-mail, as well as screenshots or other pertinent details. If you find a bug or other issues, you can reach us at the following: <a href="mailto:bugs@edx.org">bugs@edx.org</a>.</p>
......
...@@ -3,16 +3,35 @@ ...@@ -3,16 +3,35 @@
<%block name="bodyclass">courseware</%block> <%block name="bodyclass">courseware</%block>
<%block name="title"><title>Courseware – MITx 6.002x</title></%block> <%block name="title"><title>Courseware – MITx 6.002x</title></%block>
<%block name="headextra">
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
</%block>
<%block name="js_extra"> <%block name="js_extra">
<!-- TODO: http://docs.jquery.com/Plugins/Validation --> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
<script type="text/javascript">
## codemirror
<script type="text/javascript" src="${static.url('js/vendor/codemirror-compressed.js')}"></script>
## alternate codemirror
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/lib/codemirror.js')}"></script>
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/mode/xml/xml.js')}"></script>
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/mode/python/python.js')}"></script>
## image input: for clicking on images (see imageinput.html)
<script type="text/javascript" src="${static.url('js/vendor/imageinput.js')}"></script>
## TODO (cpennington): Remove this when we have a good way for modules to specify js to load on the page
## and in the wiki
<script type="text/javascript" src="${static.url('js/schematic.js')}"></script>
<%static:js group='courseware'/>
<%static:css group='course'/>
<%include file="mathjax_include.html" />
<!-- TODO: http://docs.jquery.com/Plugins/Validation -->
<script type="text/javascript">
document.write('\x3Cscript type="text/javascript" src="' + document.write('\x3Cscript type="text/javascript" src="' +
document.location.protocol + '//www.youtube.com/player_api">\x3C/script>'); document.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
</script> </script>
</%block> </%block>
<%include file="course_navigation.html" args="active_page='courseware'" /> <%include file="course_navigation.html" args="active_page='courseware'" />
......
...@@ -8,8 +8,37 @@ ...@@ -8,8 +8,37 @@
<%block name="title"><title>Dashboard</title></%block> <%block name="title"><title>Dashboard</title></%block>
<%block name="js_extra">
<script type="text/javascript">
(function() {
$(".unenroll").click(function(event) {
$("#unenroll_course_id").val( $(event.target).data("course-id") );
$("#unenroll_course_number").text( $(event.target).data("course-number") );
});
$(document).delegate('#unenroll_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
location.href="${reverse('dashboard')}";
} else {
if($('#unenroll_error').length == 0) {
$('#unenroll_form').prepend('<div id="unenroll_error" class="modal-form-error"></div>');
}
$('#unenroll_error').text(json.error).stop().css("display", "block");
}
});
})(this)
</script>
</%block>
<section class="container dashboard"> <section class="container dashboard">
<section class="dashboard-banner">
${message}
<br/>
</section>
<section class="profile-sidebar"> <section class="profile-sidebar">
<header class="profile"> <header class="profile">
<h1 class="user-name">${ user.username }</h1> <h1 class="user-name">${ user.username }</h1>
...@@ -48,10 +77,10 @@ ...@@ -48,10 +77,10 @@
<section class="info"> <section class="info">
<hgroup> <hgroup>
<a href="${reverse('university_profile', args=[course.org])}" class="university">${get_course_about_section(course, 'university')}</a> <a href="${reverse('university_profile', args=[course.org])}" class="university">${get_course_about_section(course, 'university')}</a>
<h3><a href="${course_target}">${get_course_about_section(course, "title")}</a></h3> <h3><a href="${course_target}">${course.number} ${course.title}</a></h3>
</hgroup> </hgroup>
<section class="course-status"> <section class="course-status">
<p>Class Starts - <span>9/2/2012</span></div> <p>Class Starts - <span>${course.start_date_text}</span></div>
</section> </section>
<section class="meta"> <section class="meta">
<div class="course-work-icon"></div> <div class="course-work-icon"></div>
...@@ -61,7 +90,7 @@ ...@@ -61,7 +90,7 @@
</div> </div>
</div> </div>
<div class="complete"> <div class="complete">
<p><span class="completeness">60%</span> complete</p> ##<p><span class="completeness">60%</span> complete</p>
</div> </div>
</section> </section>
</section> </section>
...@@ -105,25 +134,3 @@ ...@@ -105,25 +134,3 @@
</section> </section>
<script type="text/javascript">
(function() {
$(".unenroll").click(function(event) {
$("#unenroll_course_id").val( $(event.target).data("course-id") );
$("#unenroll_course_number").text( $(event.target).data("course-number") );
});
$(document).delegate('#unenroll_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
location.href="${reverse('dashboard')}";
} else {
if($('#unenroll_error').length == 0) {
$('#unenroll_form').prepend('<div id="unenroll_error" class="modal-form-error"></div>');
}
$('#unenroll_error').text(json.error).stop().css("display", "block");
}
});
})(this)
</script>
<%inherit file="main.html" /> <%inherit file="main.html" />
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
<%block name="headextra"> <%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.stack.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.stack.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script>
</%block>
<%block name="headextra">
<style type="text/css"> <style type="text/css">
.grade_a {color:green;} .grade_a {color:green;}
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
<%namespace name="profile_graphs" file="profile_graphs.js"/> <%namespace name="profile_graphs" file="profile_graphs.js"/>
<%block name="headextra"> <%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.stack.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.stack.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script>
......
...@@ -112,6 +112,9 @@ ...@@ -112,6 +112,9 @@
%endif %endif
<div class="post-name"> <div class="post-name">
<a href="${entry.link}" target="_blank">${entry.title}</a> <a href="${entry.link}" target="_blank">${entry.title}</a>
%if entry.summary:
<p>${entry.summary}</p>
%endif
<p class="post-date">${strftime("%m/%d/%y", entry.published_parsed)}</p> <p class="post-date">${strftime("%m/%d/%y", entry.published_parsed)}</p>
</div> </div>
</article> </article>
......
<!-- 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 @@ ...@@ -44,9 +44,9 @@
location.href="${reverse('dashboard')}"; location.href="${reverse('dashboard')}";
} else { } else {
if($('#login_error').length == 0) { 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) })(this)
......
...@@ -4,67 +4,15 @@ ...@@ -4,67 +4,15 @@
<head> <head>
<%block name="title"><title>edX</title></%block> <%block name="title"><title>edX</title></%block>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:800italic,400,800' rel='stylesheet' type='text/css'> <link rel="icon" type="image/image/x-icon" href="${static.url('images/favicon.ico')}" />
<link rel="stylesheet" href="${static.url('css/vendor/jquery.treeview.css')}" type="text/css" media="all" />
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:css group='application'/> <%static:css group='application'/>
<!--[if lt IE 9]> <!--[if lt IE 9]>
<%static:css group='ie-fixes'/> <%static:css group='ie-fixes'/>
<![endif]--> <![endif]-->
% endif <%static:js group='main_vendor'/>
% if not settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<link rel="stylesheet" href="/static/sass/application.css" type="text/css" media="all" / >
<!--[if lt IE 9]>
<link rel="stylesheet" href="/static/sass/ie.css" type="text/css" media="all" / >
<![endif]-->
% endif
<script type="text/javascript" src="${static.url('js/vendor/jquery.min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/jquery-ui.min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/swfobject/swfobject.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/jquery.cookie.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/jquery.qtip.min.js')}"></script>
<script type="text/javascript" src="${static.url('js/form.ext.js')}"></script>
## TODO (cpennington): Remove this when we have a good way for modules to specify js to load on the page
## and in the wiki
<script type="text/javascript" src="${static.url('js/schematic.js')}"></script>
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:js group='application'/>
% endif
% if not settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
% for jsfn in [ '/static/%s' % x.replace('.coffee','.js') for x in settings.PIPELINE_JS['application']['source_filenames'] ]:
<script type="text/javascript" src="${jsfn}"></script>
% endfor
% endif
## codemirror
<link rel="stylesheet" href="/static/css/codemirror.css" type="text/css" media="all" />
<script type="text/javascript" src="${static.url('js/vendor/codemirror-compressed.js')}"></script>
## alternate codemirror
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/lib/codemirror.js')}"></script>
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/mode/xml/xml.js')}"></script>
## <script type="text/javascript" src="${static.url('js/vendor/CodeMirror-2.25/mode/python/python.js')}"></script>
## image input: for clicking on images (see imageinput.html)
<script type="text/javascript" src="${static.url('js/vendor/imageinput.js')}"></script>
## <script type="text/javascript">
## var codemirror_set = {}; // track all codemirror textareas, so they can be refreshed on page changes
## </script>
<!--[if lt IE 9]>
<script src="${static.url('js/html5shiv.js')}"></script>
<![endif]-->
<%block name="headextra"/> <%block name="headextra"/>
<%include file="mathjax_include.html" />
<meta name="path_prefix" content="${MITX_ROOT_URL}"> <meta name="path_prefix" content="${MITX_ROOT_URL}">
</head> </head>
...@@ -76,10 +24,13 @@ ...@@ -76,10 +24,13 @@
<%block name="bodyextra"/> <%block name="bodyextra"/>
<%include file="footer.html" /> <%include file="footer.html" />
<%block name="js_extra"/>
<script src="${static.url('js/my_courses_dropdown.js')}"></script>
<script src="${static.url('js/toggle_login_modal.js')}"></script>
<script src="${static.url('js/sticky_filter.js')}"></script>
<%static:js group='application'/>
<!--[if lt IE 9]>
<script src="${static.url('js/html5shiv.js')}"></script>
<![endif]-->
<%block name="js_extra"/>
</body> </body>
</html> </html>
<%! 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>
...@@ -3,12 +3,48 @@ ...@@ -3,12 +3,48 @@
from courseware.courses import course_image_url, get_course_about_section from courseware.courses import course_image_url, get_course_about_section
%> %>
<%namespace name='static' file='../static_content.html'/> <%namespace name='static' file='../static_content.html'/>
<%inherit file="../main.html" />
<%block name="js_extra"> <%block name="js_extra">
% if not registered:
%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('#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
<script src="${static.url('js/course_info.js')}"></script> <script src="${static.url('js/course_info.js')}"></script>
</%block> </%block>
<%inherit file="../main.html" />
<%block name="title"><title>About ${course.number}</title></%block> <%block name="title"><title>About ${course.number}</title></%block>
...@@ -25,10 +61,10 @@ ...@@ -25,10 +61,10 @@
%if registered: %if registered:
<span class="register disabled">You are registered for this course (${course.number}).</span> <span class="register disabled">You are registered for this course (${course.number}).</span>
%else: %else:
<a href="#" class="register submit_registration">Register for ${course.number}</a> <a href="#" class="register">Register for ${course.number}</a>
%endif %endif
%else: %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 %endif
</div> </div>
...@@ -108,28 +144,17 @@ ...@@ -108,28 +144,17 @@
</section> </section>
%if not registered: %if not registered:
<div display="hidden"> <div style="display: none;">
<form id="enroll_form" method="post" data-remote="true" action="${reverse('change_enrollment')}"> <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="course_id" type="hidden" value="${course.id}">
<input name="enrollment_action" type="hidden" value="enroll"> <input name="enrollment_action" type="hidden" value="enroll">
</fieldset>
<div class="submit"> <div class="submit">
<input name="submit" type="submit" value="enroll"> <input name="submit" type="submit" value="enroll">
</div> </div>
</form> </form>
</div> </div>
<script type="text/javascript">
(function() {
$(".submit_registration").click(function() {
$("#enroll_form").submit();
});
$(document).delegate('#enroll_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
location.href="${reverse('dashboard')}";
}
});
})(this)
</script>
%endif %endif
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
%> %>
<%block name="headextra"> <%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.stack.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.stack.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script>
......
<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 %> <%! 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"> <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 @@ ...@@ -7,16 +7,16 @@
<section id="signup-modal" class="modal signup-modal"> <section id="signup-modal" class="modal signup-modal">
<div class="inner-wrapper"> <div class="inner-wrapper">
<div id="enroll"> <div id="register">
<header> <header>
<h2>Sign Up for <span class="edx">edX</span></h2> <h2>Sign Up for <span class="edx">edX</span></h2>
<hr> <hr>
</header> </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 class="notice"></div>
<div id="enroll_error" class="modal-form-error" name="enroll_error"></div> <div id="register_error" class="modal-form-error" name="register_error"></div>
<div id="enroll_error" name="enroll_error"></div> <div id="register_error" name="register_error"></div>
<div class="input-group"> <div class="input-group">
<label>E-mail*</label> <label>E-mail*</label>
...@@ -27,18 +27,16 @@ ...@@ -27,18 +27,16 @@
<input name="username" type="text" placeholder="Public Username*"> <input name="username" type="text" placeholder="Public Username*">
<label>Full Name</label> <label>Full Name</label>
<input name="name" type="text" placeholder="Full Name*"> <input name="name" type="text" placeholder="Full Name*">
<label>Mailing address</label>
<textarea name="mailing_address" placeholder="Mailing address"></textarea>
</div> </div>
<div class="input-group"> <div class="input-group">
<section class="citizenship"> <section class="citizenship">
<label>Country</label> <label>Ed. completed</label>
<div class="input-wrapper"> <div class="input-wrapper">
<select name="country"> <select name="level_of_education">
<option value="">--</option> <option value="">--</option>
%for country_code, country_name in COUNTRIES: %for code, ed_level in UserProfile.LEVEL_OF_EDUCATION_CHOICES:
<option value="${country_code}">${country_name}</option> <option value="${code}">${ed_level}</option>
%endfor %endfor
</select> </select>
</div> </div>
...@@ -56,31 +54,24 @@ ...@@ -56,31 +54,24 @@
</div> </div>
</section> </section>
<section class="date-of-birth"> <section class="gender">
<label>Date of birth</label> <label>Year of birth</label>
<div class="input-wrapper"> <div class="input-wrapper">
<select name='date_of_birth__month'> <select name="year_of_birth">
<option value="">month</option> <option value="">--</option>
%for month in range(1,13): %for year in UserProfile.VALID_YEARS:
<option value="${month}">${month} - ${calendar.month_name[month]}</option>
%endfor
</select>
<select name='date_of_birth__day'>
<option value="">day</option>
%for day in range(1,32):
<option value="${day}">${day}</option>
%endfor
</select>
<select name='date_of_birth__year'>
<option value="">year</option>
%for year in range(date.today().year,1899,-1):
<option value="${year}">${year}</option> <option value="${year}">${year}</option>
%endfor %endfor
</select> </select>
##<input name="year_of_birth" type="text" placeholder="Year of birth">
</div> </div>
</section> </section>
<label>Mailing address</label>
<textarea name="mailing_address" placeholder="Mailing address"></textarea>
<label>Goals in signing up for edX</label>
<textarea name="goals" placeholder="Goals in signing up for edX"></textarea>
</div> </div>
<div class="input-group"> <div class="input-group">
...@@ -120,11 +111,11 @@ ...@@ -120,11 +111,11 @@
<script type="text/javascript"> <script type="text/javascript">
(function() { (function() {
$(document).delegate('#enroll_form', 'ajax:success', function(data, json, xhr) { $(document).delegate('#register_form', 'ajax:success', function(data, json, xhr) {
if(json.success) { if(json.success) {
$('#enroll').html(json.value); location.href="${reverse('dashboard')}";
} else { } else {
$('#enroll_error').html(json.value).stop().css("display", "block"); $('#register_error').html(json.value).stop().css("display", "block");
} }
}); });
})(this) })(this)
......
...@@ -8,9 +8,13 @@ ...@@ -8,9 +8,13 @@
from simplewiki.views import wiki_reverse from simplewiki.views import wiki_reverse
%> %>
<%block name="headextra"> <%block name="js_extra">
<script type="text/javascript" src="${static.url('js/simplewiki-AutoSuggest_c_2.0.js')}"></script> <script type="text/javascript" src="${static.url('js/simplewiki-AutoSuggest_c_2.0.js')}"></script>
## TODO (cpennington): Remove this when we have a good way for modules to specify js to load on the page
## and in the wiki
<script type="text/javascript" src="${static.url('js/schematic.js')}"></script>
<script type="text/javascript"> <script type="text/javascript">
function set_related_article_id(s) { function set_related_article_id(s) {
document.getElementById('wiki_related_input_id').value = s.id; document.getElementById('wiki_related_input_id').value = s.id;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<p>We are always seeking feedback to improve our courses. If you are an enrolled student and have any questions, feedback, suggestions, or any other issues specific to a particular class, please post on the discussion forums of that class.</p> <p>We are always seeking feedback to improve our courses. If you are an enrolled student and have any questions, feedback, suggestions, or any other issues specific to a particular class, please post on the discussion forums of that class.</p>
<h2>General Inquiries and Feedback</h2> <h2>General Inquiries and Feedback</h2>
<p>"If you have a general question about edX please email <a href="mailto:info@edx.org">info@edx.org</a>. To see if your question has already been answered, visit our<a href="${reverse('faq_edx')}">FAQ page</a>. You can also join the discussion on our <a href="http://www.facebook.com/EdxOnline">facebook page</a>. Though we may not have a chance to respond to every email, we take all feedback into consideration.</p> <p>"If you have a general question about edX please email <a href="mailto:info@edx.org">info@edx.org</a>. To see if your question has already been answered, visit our <a href="${reverse('faq_edx')}">FAQ page</a>. You can also join the discussion on our <a href="http://www.facebook.com/EdxOnline">facebook page</a>. Though we may not have a chance to respond to every email, we take all feedback into consideration.</p>
<h2>Technical Inquiries and Feedback</h2> <h2>Technical Inquiries and Feedback</h2>
<p>If you have suggestions/feedback about the overall edX platform, or are facing general technical issues with the platform (e.g., issues with email addresses and passwords), you can reach us at <a href="mailto:technical@edx.org">technical@edx.org</a>. For technical questions, please make sure you are using a current version of Firefox or Chrome, and include browser and version in your e-mail, as well as screenshots or other pertinent details. If you find a bug or other issues, you can reach us at the following: <a href="mailto:bugs@edx.org">bugs@edx.org</a>.</p> <p>If you have suggestions/feedback about the overall edX platform, or are facing general technical issues with the platform (e.g., issues with email addresses and passwords), you can reach us at <a href="mailto:technical@edx.org">technical@edx.org</a>. For technical questions, please make sure you are using a current version of Firefox or Chrome, and include browser and version in your e-mail, as well as screenshots or other pertinent details. If you find a bug or other issues, you can reach us at the following: <a href="mailto:bugs@edx.org">bugs@edx.org</a>.</p>
......
...@@ -81,6 +81,8 @@ urlpatterns = ('', ...@@ -81,6 +81,8 @@ urlpatterns = ('',
{'template': 'press_releases/UC_Berkeley_joins_edX.html'}, name="press/uc-berkeley-joins-edx"), {'template': 'press_releases/UC_Berkeley_joins_edX.html'}, name="press/uc-berkeley-joins-edx"),
(r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}),
# TODO: These urls no longer work. They need to be updated before they are re-enabled # TODO: These urls no longer work. They need to be updated before they are re-enabled
# url(r'^send_feedback$', 'util.views.send_feedback'), # url(r'^send_feedback$', 'util.views.send_feedback'),
# url(r'^reactivate/(?P<key>[^/]*)$', 'student.views.reactivation_email'), # url(r'^reactivate/(?P<key>[^/]*)$', 'student.views.reactivation_email'),
...@@ -106,7 +108,7 @@ if settings.COURSEWARE_ENABLED: ...@@ -106,7 +108,7 @@ if settings.COURSEWARE_ENABLED:
url(r'^courses/?$', 'courseware.views.courses', name="courses"), url(r'^courses/?$', 'courseware.views.courses', name="courses"),
url(r'^change_enrollment$', url(r'^change_enrollment$',
'courseware.views.change_enrollment', name="change_enrollment"), 'student.views.change_enrollment_view', name="change_enrollment"),
#About the course #About the course
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/about$', 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