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 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%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/sets/wiki/style.css')}" />
<title><%block name="title"></%block></title>
......@@ -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/markitup/jquery.markitup.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'/>
% else:
<script src="${ STATIC_URL }/js/main.js"></script>
% endif
<%static:js group='module-js'/>
<script src="${static.url('js/vendor/jquery.inlineedit.js')}"></script>
<script src="${static.url('js/vendor/jquery.cookie.js')}"></script>
......
......@@ -10,10 +10,10 @@
<hr>
</header>
<div id="enroll">
<div id="register">
<form id="enroll_form" method="post">
<div id="enroll_error" name="enroll_error"></div>
<form id="register_form" method="post">
<div id="register_error" name="register_error"></div>
<label>E-mail</label>
<input name="email" type="email" placeholder="E-mail">
<label>Password</label>
......@@ -64,17 +64,17 @@
});
}
$('form#enroll_form').submit(function(e) {
$('form#register_form').submit(function(e) {
e.preventDefault();
var submit_data = $('#enroll_form').serialize();
var submit_data = $('#register_form').serialize();
postJSON('/create_account',
submit_data,
function(json) {
if(json.success) {
$('#enroll').html(json.value);
$('#register').html(json.value);
} else {
$('#enroll_error').html(json.value).stop().css("background-color", "#933").animate({ backgroundColor: "#333"}, 2000);
$('#register_error').html(json.value).stop().css("background-color", "#933").animate({ backgroundColor: "#333"}, 2000);
}
}
);
......
......@@ -5,6 +5,24 @@ from static_replace import replace_urls
%>
<%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>
......@@ -8,19 +8,22 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'CourseEnrollment', fields ['user']
db.delete_unique('student_courseenrollment', ['user_id'])
# Changing field 'CourseEnrollment.user'
db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User']))
# This table is dropped in a subsequent migration. This migration was causing problems when using InnoDB,
# so we are just dropping it.
pass
# # Removing unique constraint on 'CourseEnrollment', fields ['user']
# db.delete_unique('student_courseenrollment', ['user_id'])
#
#
# # Changing field 'CourseEnrollment.user'
# db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User']))
def backwards(self, orm):
# Changing field 'CourseEnrollment.user'
db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True))
# Adding unique constraint on 'CourseEnrollment', fields ['user']
db.create_unique('student_courseenrollment', ['user_id'])
pass
# # Changing field 'CourseEnrollment.user'
# db.alter_column('student_courseenrollment', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True))
# # Adding unique constraint on 'CourseEnrollment', fields ['user']
# db.create_unique('student_courseenrollment', ['user_id'])
models = {
......
......@@ -8,14 +8,70 @@ from django.db import models
class Migration(SchemaMigration):
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):
# 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 = {
'auth.group': {
......@@ -80,8 +136,9 @@ class Migration(SchemaMigration):
'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'}),
'Meta': {'unique_together': "(('user', 'course_id'),)", 'object_name': 'CourseEnrollment'},
'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'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
......@@ -107,19 +164,18 @@ class Migration(SchemaMigration):
},
'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'}),
'gender': ('django.db.models.fields.CharField', [], {'db_index': 'True', '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'}),
'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'}),
'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'}),
'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']"})
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
'year_of_birth': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'})
},
'student.usertestgroup': {
'Meta': {'object_name': 'UserTestGroup'},
......
......@@ -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,
1. Go to the mitx dir
2. ./manage.py schemamigration user --auto description_of_your_change
3. Add the migration file created in mitx/courseware/migrations/
2. django-admin.py schemamigration student --auto --settings=lms.envs.dev --pythonpath=. description_of_your_change
3. Add the migration file created in mitx/common/djangoapps/student/migrations/
"""
from datetime import datetime
import json
import uuid
from django.db import models
from django.contrib.auth.models import User
import json
from django_countries import CountryField
#from cache_toolbox import cache_model, cache_relation
......@@ -21,23 +22,43 @@ class UserProfile(models.Model):
class Meta:
db_table = "auth_userprofile"
GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'), ('o', 'Other'))
## CRITICAL TODO/SECURITY
# Sanitize all fields.
# This is not visible to other users, but could introduce holes later
user = models.OneToOneField(User, unique=True, db_index=True, related_name='profile')
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
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)
country = CountryField(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)
goals = models.TextField(blank=True, null=True)
def get_meta(self):
js_str = self.meta
......
......@@ -71,26 +71,25 @@ def index(request):
for entry in entries:
soup = BeautifulSoup(entry.description)
entry.image = soup.img['src'] if soup.img else None
entry.summary = soup.getText()
courses = modulestore().get_courses()
universities = defaultdict(list)
for university, group in itertools.groupby(courses, lambda course: course.org):
[universities[university].append(course) for course in group]
courses = sorted(modulestore().get_courses(), key=lambda course: course.number)
for course in courses:
universities[course.org].append(course)
return render_to_response('index.html', {'universities': universities, 'entries': entries})
def course_from_id(id):
course_loc = CourseDescriptor.id_to_location(id)
return modulestore().get_item(course_loc)
@login_required
@ensure_csrf_cookie
def dashboard(request):
csrf_token = csrf(request)['csrf_token']
user = request.user
enrollments = CourseEnrollment.objects.filter(user=user)
def course_from_id(id):
course_loc = CourseDescriptor.id_to_location(id)
return modulestore().get_item(course_loc)
# Build our courses list for the user, but ignore any courses that no longer
# exist (because the course IDs have changed). Still, we don't delete those
# enrollments, because it could have been a data push snafu.
......@@ -102,17 +101,79 @@ def dashboard(request):
log.error("User {0} enrolled in non-existant course {1}"
.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)
def try_change_enrollment(request):
"""
This method calls change_enrollment if the necessary POST
parameters are present, but does not return anything. It
simply logs the result or exception. This is usually
called after a registration or login, as secondary action.
It should not interrupt a successful registration or login.
"""
if 'enrollment_action' in request.POST:
try:
enrollment_output = change_enrollment(request)
# There isn't really a way to display the results to the user, so we just log it
# We expect the enrollment to be a success, and will show up on the dashboard anyway
log.info("Attempted to automatically enroll after login. Results: {0}".format(enrollment_output))
except Exception, e:
log.exception("Exception automatically enrolling after login: {0}".format(str(e)))
@login_required
def change_enrollment_view(request):
return HttpResponse(json.dumps(change_enrollment(request)))
def change_enrollment(request):
if request.method != "POST":
raise Http404
action = request.POST.get("enrollment_action" , "")
user = request.user
course_id = request.POST.get("course_id", None)
if course_id == None:
return HttpResponse(json.dumps({'success': False, 'error': 'There was an error receiving the course id.'}))
if action == "enroll":
# Make sure the course exists
# We don't do this check on unenroll, or a bad course id can't be unenrolled from
try:
course = course_from_id(course_id)
except ItemNotFoundError:
log.error("User {0} tried to enroll in non-existant course {1}"
.format(user.username, enrollment.course_id))
return {'success': False, 'error': 'The course requested does not exist.'}
enrollment, created = CourseEnrollment.objects.get_or_create(user=user, course_id=course.id)
return {'success': True}
elif action == "unenroll":
try:
enrollment = CourseEnrollment.objects.get(user=user, course_id=course_id)
enrollment.delete()
return {'success': True}
except CourseEnrollment.DoesNotExist:
return {'success': False, 'error': 'You are not enrolled for this course.'}
else:
return {'success': False, 'error': 'Invalid enrollment_action.'}
return {'success': False, 'error': 'We weren\'t able to unenroll you. Please try again.'}
# Need different levels of logging
@ensure_csrf_cookie
def login_user(request, error=""):
''' AJAX request to log in the user. '''
if 'email' not in request.POST or 'password' not in request.POST:
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid login'})) # TODO: User error message
'value': 'There was an error receiving your login information. Please email us.'})) # TODO: User error message
email = request.POST['email']
password = request.POST['password']
......@@ -121,14 +182,14 @@ def login_user(request, error=""):
except User.DoesNotExist:
log.warning("Login failed - Unknown user email: {0}".format(email))
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid login'})) # TODO: User error message
'value': 'Email or password is incorrect.'})) # TODO: User error message
username = user.username
user = authenticate(username=username, password=password)
if user is None:
log.warning("Login failed - password for {0} is invalid".format(email))
return HttpResponse(json.dumps({'success': False,
'error': 'Invalid login'}))
'value': 'Email or password is incorrect.'}))
if user is not None and user.is_active:
try:
......@@ -143,11 +204,14 @@ def login_user(request, error=""):
log.exception(e)
log.info("Login success - {0} ({1})".format(username, email))
try_change_enrollment(request)
return HttpResponse(json.dumps({'success':True}))
log.warning("Login failed - Account not active for user {0}".format(username))
return HttpResponse(json.dumps({'success':False,
'error': 'Account not active. Check your e-mail.'}))
'value': 'This account has not been activated. Please check your e-mail for the activation instructions.'}))
@ensure_csrf_cookie
def logout_user(request):
......@@ -243,17 +307,20 @@ def create_account(request, post_override=None):
up = UserProfile(user=u)
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.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']
if all(len(post_vars[field]) > 0 for field in date_fields):
up.date_of_birth = date(int(post_vars['date_of_birth__year']),
int(post_vars['date_of_birth__month']),
int(post_vars['date_of_birth__day']))
try:
up.year_of_birth = int(post_vars['year_of_birth'])
except ValueError:
up.year_of_birth = None # If they give us garbage, just ignore it instead
# of asking them to put an integer.
try:
up.save()
except Exception:
log.exception("UserProfile creation failed for user {0}.".format(u.id))
d = {'name': post_vars['name'],
'key': r.activation_key,
......@@ -276,9 +343,16 @@ def create_account(request, post_override=None):
js['value'] = 'Could not send activation e-mail.'
return HttpResponse(json.dumps(js))
js={'success': True,
'value': render_to_string('registration/reg_complete.html', {'email': post_vars['email'],
'csrf': csrf(request)['csrf_token']})}
# Immediately after a user creates an account, we log them in. They are only
# logged in until they close the browser. They can't log in again until they click
# the activation link from the email.
login_user = authenticate(username=post_vars['username'], password = post_vars['password'] )
login(request, login_user)
request.session.set_expiry(0)
try_change_enrollment(request)
js={'success': True}
return HttpResponse(json.dumps(js), mimetype="application/json")
def create_random_account(create_account_function):
......@@ -308,14 +382,15 @@ def activate_account(request, key):
'''
r=Registration.objects.filter(activation_key=key)
if len(r)==1:
user_logged_in = request.user.is_authenticated()
already_active = True
if not r[0].user.is_active:
r[0].activate()
resp = render_to_response("activation_complete.html",{'csrf':csrf(request)['csrf_token']})
return resp
resp = render_to_response("activation_active.html",{'csrf':csrf(request)['csrf_token']})
already_active = False
resp = render_to_response("registration/activation_complete.html",{'user_logged_in':user_logged_in, 'already_active' : already_active})
return resp
if len(r)==0:
return render_to_response("activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
return render_to_response("registration/activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.")
@ensure_csrf_cookie
......
......@@ -57,10 +57,10 @@ def format_url_params(params):
@cache_if_anonymous
def courses(request):
# TODO: Clean up how 'error' is done.
courses = modulestore().get_courses()
courses = sorted(modulestore().get_courses(), key=lambda course: course.number)
universities = defaultdict(list)
for university, group in itertools.groupby(courses, lambda course: course.org):
[universities[university].append(course) for course in group]
for course in courses:
universities[course.org].append(course)
return render_to_response("courses.html", { 'universities': universities })
......@@ -271,44 +271,11 @@ def course_about(request, course_id):
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
@cache_if_anonymous
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)
if org_id not in valid_org_ids:
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 = {
'source_filenames': ['sass/application.scss'],
'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': {
'source_filenames': ['sass/ie.scss'],
'output_filename': 'css/ie.css',
......@@ -301,11 +305,47 @@ PIPELINE_CSS = {
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 = {
'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'
},
'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': {
'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
'output_filename': 'js/spec.js'
......
......@@ -8,8 +8,10 @@
position: 'fixed'
}
if ($("#lean_overlay").length == 0) {
var overlay = $("<div id='lean_overlay'></div>");
$("body").append(overlay);
}
options = $.extend(defaults, options);
......@@ -51,7 +53,11 @@
$(modal_id).find(".notice").hide().html("");
var notice = $(this).data('notice')
if(notice !== undefined) {
$(modal_id).find(".notice").show().html(notice);
$notice = $(modal_id).find(".notice");
$notice.show().html(notice);
// This is for activating leanModal links that were in the notice. We should have a cleaner way of
// allowing all dynamically added leanmodal links to work.
$notice.find("a[rel*=leanModal]").leanModal({ top : 120, overlay: 1, closeButton: ".close-modal", position: 'absolute' });
}
window.scrollTo(0, 0);
e.preventDefault();
......@@ -71,8 +77,13 @@
$(this).leanModal({ top : 120, overlay: 1, closeButton: ".close-modal", position: 'absolute' });
embed = $($(this).attr('href')).find('iframe')
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', '');
}
}
});
})(jQuery);
......@@ -8,13 +8,6 @@
@import 'base/extends';
@import 'base/animations';
// Courseware styles
@import 'sass_old/base/variables';
@import 'sass_old/base/extends';
@import 'sass_old/base/functions';
// Multicourse styles
@import 'shared/forms';
@import 'shared/footer';
......@@ -24,22 +17,12 @@
@import 'shared/modal';
@import 'shared/activation_messages';
@import 'home';
@import 'dashboard';
@import 'courseware_subnav';
@import 'courses';
@import 'course_about';
@import 'jobs';
@import 'about_pages';
@import 'press_release';
@import 'password_reset';
@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';
@import 'multicourse/home';
@import 'multicourse/dashboard';
@import 'multicourse/courses';
@import 'multicourse/course_about';
@import 'multicourse/jobs';
@import 'multicourse/about_pages';
@import 'multicourse/press_release';
@import 'multicourse/password_reset';
@import 'multicourse/error-pages';
/* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 25, 2012 05:06:34 PM America/New_York */
@font-face {
font-family: 'Open Sans';
src: url('../fonts/OpenSans-Light-webfont.eot');
......@@ -32,7 +31,7 @@
url('../fonts/OpenSans-Regular-webfont.woff') format('woff'),
url('../fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
url('../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
font-weight: 600;
font-weight: 400;
font-style: normal;
}
......@@ -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-family: 'Open Sans';
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 {
form {
text-align: left;
div#enroll_error, div#login_error, div#pwd_error {
div#register_error, div#login_error, div#pwd_error {
$error-color: #333;
background-color: $error-color;
border: darken($error-color, 20%);
......
......@@ -8,7 +8,7 @@
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 clearfix;
height: 430px;
height: 460px;
margin-top: -69px;
overflow: hidden;
padding: 0px;
......@@ -17,10 +17,11 @@
.outer-wrapper {
@extend .animation-home-header-pop-up;
margin: 0 auto;
padding: 200px 10px 0px;
padding: 240px 10px 0px;
position: relative;
max-width: 1200px;
min-width: 760px;
@include clearfix;
}
.title {
......@@ -30,29 +31,16 @@
@include box-shadow(0 4px 25px 0 rgba(0,0,0, 0.5));
@include box-sizing(border-box);
height: 120px;
@include inline-block;
margin-left: grid-width(1) + $gw-gutter;
margin-right: $gw-gutter;
margin-left: grid-width(2) + $gw-gutter;
float: left;
position: relative;
text-align: center;
@include transition(all, 0.2s, linear);
vertical-align: top;
&:hover {
height: 165px;
> hgroup {
h1 {
border-bottom: 1px solid rgb(200,200,200);
padding-bottom: 10px;
}
h2 {
opacity: 0;
}
}
.actions {
opacity: 1;
display: none;
}
}
......@@ -80,123 +68,21 @@
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 {
@include box-sizing(border-box);
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;
}
}
}
}
}
.actions {
display: none;
}
.media {
background: #FFF;
background: rgba(255,255,255, 0.93);
border: 1px solid rgb(100,100,100);
border-left: 0;
@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;
@include inline-block;
float: left;
padding: 4px;
position: relative;
vertical-align: top;
......@@ -249,8 +135,6 @@
}
&:hover {
cursor: pointer;
.play-intro {
@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));
......
......@@ -210,7 +210,7 @@
.citizenship, .gender {
float: left;
width: flex-grid(6);
width: flex-grid(4);
}
.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 @@
<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>
<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>
<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 @@
<%block name="bodyclass">courseware</%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">
<!-- TODO: http://docs.jquery.com/Plugins/Validation -->
<script type="text/javascript">
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
## 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.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
</script>
</script>
</%block>
<%include file="course_navigation.html" args="active_page='courseware'" />
......
......@@ -8,8 +8,37 @@
<%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="dashboard-banner">
${message}
<br/>
</section>
<section class="profile-sidebar">
<header class="profile">
<h1 class="user-name">${ user.username }</h1>
......@@ -48,10 +77,10 @@
<section class="info">
<hgroup>
<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>
<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 class="meta">
<div class="course-work-icon"></div>
......@@ -61,7 +90,7 @@
</div>
</div>
<div class="complete">
<p><span class="completeness">60%</span> complete</p>
##<p><span class="completeness">60%</span> complete</p>
</div>
</section>
</section>
......@@ -105,25 +134,3 @@
</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" />
<%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.stack.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">
.grade_a {color:green;}
......
......@@ -2,7 +2,7 @@
<%namespace name='static' file='static_content.html'/>
<%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.stack.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.symbol.js')}"></script>
......
......@@ -112,6 +112,9 @@
%endif
<div class="post-name">
<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>
</div>
</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 @@
location.href="${reverse('dashboard')}";
} else {
if($('#login_error').length == 0) {
$('#login_form').prepend('<div id="login_error" class="modal-form-error">Email or password is incorrect.</div>');
$('#login_form').prepend('<div id="login_error" class="modal-form-error"></div>');
}
$('#login_error').stop().css("display", "block");
$('#login_error').html(json.value).stop().css("display", "block");
}
});
})(this)
......
......@@ -4,67 +4,15 @@
<head>
<%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="stylesheet" href="${static.url('css/vendor/jquery.treeview.css')}" type="text/css" media="all" />
<link rel="icon" type="image/image/x-icon" href="${static.url('images/favicon.ico')}" />
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:css group='application'/>
<!--[if lt IE 9]>
<%static:css group='ie-fixes'/>
<![endif]-->
% endif
% 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]-->
<%static:js group='main_vendor'/>
<%block name="headextra"/>
<%include file="mathjax_include.html" />
<meta name="path_prefix" content="${MITX_ROOT_URL}">
</head>
......@@ -76,10 +24,13 @@
<%block name="bodyextra"/>
<%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>
</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 @@
from courseware.courses import course_image_url, get_course_about_section
%>
<%namespace name='static' file='../static_content.html'/>
<%inherit file="../main.html" />
<%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>
</%block>
<%inherit file="../main.html" />
<%block name="title"><title>About ${course.number}</title></%block>
......@@ -25,10 +61,10 @@
%if registered:
<span class="register disabled">You are registered for this course (${course.number}).</span>
%else:
<a href="#" class="register submit_registration">Register for ${course.number}</a>
<a href="#" class="register">Register for ${course.number}</a>
%endif
%else:
<a href="#signup-modal" class="register" rel="leanModal" data-notice="You must Sign Up in order to register">Register for ${course.number}</a>
<a href="#signup-modal" class="register" rel="leanModal" data-notice='You must Sign Up or <a href="#login-modal" rel="leanModal">Log In</a> to enroll.'>Register for ${course.number}</a>
%endif
</div>
......@@ -108,28 +144,17 @@
</section>
%if not registered:
<div display="hidden">
<form id="enroll_form" method="post" data-remote="true" action="${reverse('change_enrollment')}">
<div style="display: none;">
<form id="class_enroll_form" method="post" data-remote="true" action="${reverse('change_enrollment')}">
<fieldset class="enroll_fieldset">
<input name="course_id" type="hidden" value="${course.id}">
<input name="enrollment_action" type="hidden" value="enroll">
</fieldset>
<div class="submit">
<input name="submit" type="submit" value="enroll">
</div>
</form>
</div>
<script type="text/javascript">
(function() {
$(".submit_registration").click(function() {
$("#enroll_form").submit();
});
$(document).delegate('#enroll_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
location.href="${reverse('dashboard')}";
}
});
})(this)
</script>
%endif
......
......@@ -8,7 +8,7 @@
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.stack.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 %>
<%inherit file="main.html" />
<%inherit file="../main.html" />
<%namespace name='static' file='static_content.html'/>
<%namespace name='static' file='../static_content.html'/>
<section class="container activation">
......
<header>
<h2>Thanks For Registering!</h2>
<hr>
</header>
<p class='activation-message'>Please check your email. An activation link has been sent to <strong>${ email }</strong>, along with
instructions for activating your account.</p>
......@@ -7,16 +7,16 @@
<section id="signup-modal" class="modal signup-modal">
<div class="inner-wrapper">
<div id="enroll">
<div id="register">
<header>
<h2>Sign Up for <span class="edx">edX</span></h2>
<hr>
</header>
<form id="enroll_form" method="post" data-remote="true" action="/create_account">
<form id="register_form" method="post" data-remote="true" action="/create_account">
<div class="notice"></div>
<div id="enroll_error" class="modal-form-error" name="enroll_error"></div>
<div id="enroll_error" name="enroll_error"></div>
<div id="register_error" class="modal-form-error" name="register_error"></div>
<div id="register_error" name="register_error"></div>
<div class="input-group">
<label>E-mail*</label>
......@@ -27,18 +27,16 @@
<input name="username" type="text" placeholder="Public Username*">
<label>Full Name</label>
<input name="name" type="text" placeholder="Full Name*">
<label>Mailing address</label>
<textarea name="mailing_address" placeholder="Mailing address"></textarea>
</div>
<div class="input-group">
<section class="citizenship">
<label>Country</label>
<label>Ed. completed</label>
<div class="input-wrapper">
<select name="country">
<select name="level_of_education">
<option value="">--</option>
%for country_code, country_name in COUNTRIES:
<option value="${country_code}">${country_name}</option>
%for code, ed_level in UserProfile.LEVEL_OF_EDUCATION_CHOICES:
<option value="${code}">${ed_level}</option>
%endfor
</select>
</div>
......@@ -56,31 +54,24 @@
</div>
</section>
<section class="date-of-birth">
<label>Date of birth</label>
<section class="gender">
<label>Year of birth</label>
<div class="input-wrapper">
<select name='date_of_birth__month'>
<option value="">month</option>
%for month in range(1,13):
<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):
<select name="year_of_birth">
<option value="">--</option>
%for year in UserProfile.VALID_YEARS:
<option value="${year}">${year}</option>
%endfor
</select>
##<input name="year_of_birth" type="text" placeholder="Year of birth">
</div>
</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 class="input-group">
......@@ -120,11 +111,11 @@
<script type="text/javascript">
(function() {
$(document).delegate('#enroll_form', 'ajax:success', function(data, json, xhr) {
$(document).delegate('#register_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
$('#enroll').html(json.value);
location.href="${reverse('dashboard')}";
} else {
$('#enroll_error').html(json.value).stop().css("display", "block");
$('#register_error').html(json.value).stop().css("display", "block");
}
});
})(this)
......
......@@ -8,9 +8,13 @@
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>
## 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">
function set_related_article_id(s) {
document.getElementById('wiki_related_input_id').value = s.id;
......
......@@ -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>
<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>
<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 = ('',
{'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
# url(r'^send_feedback$', 'util.views.send_feedback'),
# url(r'^reactivate/(?P<key>[^/]*)$', 'student.views.reactivation_email'),
......@@ -106,7 +108,7 @@ if settings.COURSEWARE_ENABLED:
url(r'^courses/?$', 'courseware.views.courses', name="courses"),
url(r'^change_enrollment$',
'courseware.views.change_enrollment', name="change_enrollment"),
'student.views.change_enrollment_view', name="change_enrollment"),
#About the course
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/about$',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment