Commit 24045999 by Bridger Maxwell

Merge remote-tracking branch 'origin/master' into course_start

Conflicts:
	common/lib/xmodule/xmodule/course_module.py
	lms/urls.py
parents 9e16e85d 836f6df5
...@@ -4,45 +4,165 @@ from django.test import TestCase ...@@ -4,45 +4,165 @@ from django.test import TestCase
from mock import patch, Mock from mock import patch, Mock
from override_settings import override_settings from override_settings import override_settings
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse
from student.models import Registration
from django.contrib.auth.models import User
def parse_json(response): def parse_json(response):
"""Parse response, which is assumed to be json""" """Parse response, which is assumed to be json"""
return json.loads(response.content) return json.loads(response.content)
class AuthTestCase(TestCase):
"""Check that various permissions-related things work"""
def test_index(self): def user(email):
"""Make sure the main page loads.""" '''look up a user by email'''
resp = self.client.get('/') return User.objects.get(email=email)
self.assertEqual(resp.status_code, 200)
def test_signup_load(self): def registration(email):
"""Make sure the signup page loads.""" '''look up registration object by email'''
resp = self.client.get('/signup') return Registration.objects.get(user__email=email)
self.assertEqual(resp.status_code, 200)
class AuthTestCase(TestCase):
"""Check that various permissions-related things work"""
def test_create_account(self): def setUp(self):
self.email = 'a@b.com'
self.pw = 'xyz'
self.username = 'testuser'
def check_page_get(self, url, expected):
resp = self.client.get(url)
self.assertEqual(resp.status_code, expected)
return resp
def test_public_pages_load(self):
"""Make sure pages that don't require login load without error."""
pages = (
reverse('login'),
reverse('signup'),
)
for page in pages:
print "Checking '{0}'".format(page)
self.check_page_get(page, 200)
def test_create_account_errors(self):
# No post data -- should fail # No post data -- should fail
resp = self.client.post('/create_account', {}) resp = self.client.post('/create_account', {})
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
data = parse_json(resp) data = parse_json(resp)
self.assertEqual(data['success'], False) self.assertEqual(data['success'], False)
# Should work def _create_account(self, username, email, pw):
'''Try to create an account. No error checking'''
resp = self.client.post('/create_account', { resp = self.client.post('/create_account', {
'username': 'user', 'username': username,
'email': 'a@b.com', 'email': email,
'password': 'xyz', 'password': pw,
'location' : 'home', 'location' : 'home',
'language' : 'Franglish', 'language' : 'Franglish',
'name' : 'Fred Weasley', 'name' : 'Fred Weasley',
'terms_of_service' : 'true', 'terms_of_service' : 'true',
'honor_code' : 'true'}) 'honor_code' : 'true'})
return resp
def create_account(self, username, email, pw):
'''Create the account and check that it worked'''
resp = self._create_account(username, email, pw)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
data = parse_json(resp) data = parse_json(resp)
self.assertEqual(data['success'], True) self.assertEqual(data['success'], True)
# Check both that the user is created, and inactive
self.assertFalse(user(self.email).is_active)
return resp
def _activate_user(self, email):
'''look up the user's activation key in the db, then hit the activate view.
No error checking'''
activation_key = registration(email).activation_key
# and now we try to activate
resp = self.client.get(reverse('activate', kwargs={'key': activation_key}))
return resp
def activate_user(self, email):
resp = self._activate_user(email)
self.assertEqual(resp.status_code, 200)
# Now make sure that the user is now actually activated
self.assertTrue(user(self.email).is_active)
def test_create_account(self):
self.create_account(self.username, self.email, self.pw)
self.activate_user(self.email)
def _login(self, email, pw):
'''Login. View should always return 200. The success/fail is in the
returned json'''
resp = self.client.post(reverse('login_post'),
{'email': email, 'password': pw})
self.assertEqual(resp.status_code, 200)
return resp
def login(self, email, pw):
'''Login, check that it worked.'''
resp = self._login(self.email, self.pw)
data = parse_json(resp)
self.assertTrue(data['success'])
return resp
def test_login(self):
self.create_account(self.username, self.email, self.pw)
# Not activated yet. Login should fail.
resp = self._login(self.email, self.pw)
data = parse_json(resp)
self.assertFalse(data['success'])
self.activate_user(self.email)
# Now login should work
self.login(self.email, self.pw)
def test_private_pages_auth(self):
"""Make sure pages that do require login work."""
auth_pages = (
reverse('index'),
reverse('edit_item'),
reverse('save_item'),
)
# These are pages that should just load when the user is logged in
# (no data needed)
simple_auth_pages = (
reverse('index'),
)
# need an activated user
self.test_create_account()
# Not logged in. Should redirect to login.
print 'Not logged in'
for page in auth_pages:
print "Checking '{0}'".format(page)
self.check_page_get(page, expected=302)
# Logged in should work.
self.login(self.email, self.pw)
print 'Logged in'
for page in simple_auth_pages:
print "Checking '{0}'".format(page)
self.check_page_get(page, expected=200)
def test_index_auth(self):
# not logged in. Should return a redirect.
resp = self.client.get(reverse('index'))
self.assertEqual(resp.status_code, 302)
# Logged in should work.
...@@ -2,6 +2,7 @@ from util.json_request import expect_json ...@@ -2,6 +2,7 @@ from util.json_request import expect_json
import json import json
from django.http import HttpResponse from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf from django.core.context_processors import csrf
from django_future.csrf import ensure_csrf_cookie from django_future.csrf import ensure_csrf_cookie
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -13,8 +14,28 @@ from github_sync import export_to_github ...@@ -13,8 +14,28 @@ from github_sync import export_to_github
from mitxmako.shortcuts import render_to_response from mitxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
# ==== Public views ==================================================
@ensure_csrf_cookie @ensure_csrf_cookie
def signup(request):
"""
Display the signup form.
"""
csrf_token = csrf(request)['csrf_token']
return render_to_response('signup.html', {'csrf': csrf_token })
@ensure_csrf_cookie
def login_page(request):
"""
Display the login form.
"""
csrf_token = csrf(request)['csrf_token']
return render_to_response('login.html', {'csrf': csrf_token })
# ==== Views for any logged-in user ==================================
@login_required
@ensure_csrf_cookie
def index(request): def index(request):
courses = modulestore().get_items(['i4x', None, None, 'course', None]) courses = modulestore().get_items(['i4x', None, None, 'course', None])
return render_to_response('index.html', { return render_to_response('index.html', {
...@@ -26,26 +47,34 @@ def index(request): ...@@ -26,26 +47,34 @@ def index(request):
for course in courses] for course in courses]
}) })
# ==== Views with per-item permissions================================
@ensure_csrf_cookie def has_access(user, location):
def signup(request): '''Return True if user allowed to access this piece of data'''
""" # TODO (vshnayder): actually check perms
Display the signup form. return user.is_active and user.is_authenticated
"""
csrf_token = csrf(request)['csrf_token']
return render_to_response('signup.html', {'csrf': csrf_token })
@login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def course_index(request, org, course, name): def course_index(request, org, course, name):
location = ['i4x', org, course, 'course', name]
if not has_access(request.user, location):
raise Http404 # TODO (vshnayder): better error
# TODO (cpennington): These need to be read in from the active user # TODO (cpennington): These need to be read in from the active user
course = modulestore().get_item(['i4x', org, course, 'course', name]) course = modulestore().get_item(location)
weeks = course.get_children() weeks = course.get_children()
return render_to_response('course_index.html', {'weeks': weeks}) return render_to_response('course_index.html', {'weeks': weeks})
@login_required
def edit_item(request): def edit_item(request):
item_id = request.GET['id'] # TODO (vshnayder): change name from id to location in coffee+html as well.
item = modulestore().get_item(item_id) item_location = request.GET['id']
print item_location, request.GET
if not has_access(request.user, item_location):
raise Http404 # TODO (vshnayder): better error
item = modulestore().get_item(item_location)
return render_to_response('unit.html', { return render_to_response('unit.html', {
'contents': item.get_html(), 'contents': item.get_html(),
'js_module': item.js_module_name(), 'js_module': item.js_module_name(),
...@@ -54,18 +83,39 @@ def edit_item(request): ...@@ -54,18 +83,39 @@ def edit_item(request):
}) })
def user_author_string(user):
'''Get an author string for commits by this user. Format:
first last <email@email.com>.
If the first and last names are blank, uses the username instead.
Assumes that the email is not blank.
'''
f = user.first_name
l = user.last_name
if f == '' and l == '':
f = user.username
return '{first} {last} <{email}>'.format(first=f,
last=l,
email=user.email)
@login_required
@expect_json @expect_json
def save_item(request): def save_item(request):
item_id = request.POST['id'] item_location = request.POST['id']
if not has_access(request.user, item_location):
raise Http404 # TODO (vshnayder): better error
data = json.loads(request.POST['data']) data = json.loads(request.POST['data'])
modulestore().update_item(item_id, data) modulestore().update_item(item_location, data)
# Export the course back to github # Export the course back to github
# This uses wildcarding to find the course, which requires handling # This uses wildcarding to find the course, which requires handling
# multiple courses returned, but there should only ever be one # multiple courses returned, but there should only ever be one
course_location = Location(item_id)._replace(category='course', name=None) course_location = Location(item_location)._replace(
category='course', name=None)
courses = modulestore().get_items(course_location, depth=None) courses = modulestore().get_items(course_location, depth=None)
for course in courses: for course in courses:
export_to_github(course, "CMS Edit") author_string = user_author_string(request.user)
export_to_github(course, "CMS Edit", author_string)
return HttpResponse(json.dumps({})) return HttpResponse(json.dumps({}))
...@@ -38,7 +38,12 @@ def import_from_github(repo_settings): ...@@ -38,7 +38,12 @@ def import_from_github(repo_settings):
return git_repo.head.commit.hexsha, module_store.courses[course_dir] return git_repo.head.commit.hexsha, module_store.courses[course_dir]
def export_to_github(course, commit_message): def export_to_github(course, commit_message, author_str=None):
'''
Commit any changes to the specified course with given commit message,
and push to github (if MITX_FEATURES['GITHUB_PUSH'] is True).
If author_str is specified, uses it in the commit.
'''
repo_path = settings.DATA_DIR / course.metadata.get('course_dir', course.location.course) repo_path = settings.DATA_DIR / course.metadata.get('course_dir', course.location.course)
fs = OSFS(repo_path) fs = OSFS(repo_path)
xml = course.export_to_xml(fs) xml = course.export_to_xml(fs)
...@@ -49,8 +54,11 @@ def export_to_github(course, commit_message): ...@@ -49,8 +54,11 @@ def export_to_github(course, commit_message):
git_repo = Repo(repo_path) git_repo = Repo(repo_path)
if git_repo.is_dirty(): if git_repo.is_dirty():
git_repo.git.add(A=True) git_repo.git.add(A=True)
git_repo.git.commit(m=commit_message) if author_str is not None:
git_repo.git.commit(m=commit_message, author=author_str)
else:
git_repo.git.commit(m=commit_message)
origin = git_repo.remotes.origin origin = git_repo.remotes.origin
if settings.MITX_FEATURES['GITHUB_PUSH']: if settings.MITX_FEATURES['GITHUB_PUSH']:
push_infos = origin.push() push_infos = origin.push()
......
...@@ -49,4 +49,4 @@ def github_post_receive(request): ...@@ -49,4 +49,4 @@ def github_post_receive(request):
revision, course = import_from_github(repo) revision, course = import_from_github(repo)
export_to_github(course, repo['path'], "Changes from cms import of revision %s" % revision) export_to_github(course, repo['path'], "Changes from cms import of revision %s" % revision)
return HttpResponse('Push recieved') return HttpResponse('Push received')
...@@ -70,6 +70,10 @@ TEMPLATE_DIRS = ( ...@@ -70,6 +70,10 @@ TEMPLATE_DIRS = (
MITX_ROOT_URL = '' MITX_ROOT_URL = ''
LOGIN_REDIRECT_URL = MITX_ROOT_URL + '/login'
LOGIN_URL = MITX_ROOT_URL + '/login'
TEMPLATE_CONTEXT_PROCESSORS = ( TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request', 'django.core.context_processors.request',
'django.core.context_processors.static', 'django.core.context_processors.static',
......
...@@ -29,39 +29,37 @@ DATABASES = { ...@@ -29,39 +29,37 @@ DATABASES = {
} }
} }
REPO_ROOT = ENV_ROOT / "content"
REPOS = { REPOS = {
'edx4edx': { 'edx4edx': {
'path': REPO_ROOT / "edx4edx", 'path': DATA_DIR / "edx4edx",
'org': 'edx', 'org': 'edx',
'course': 'edx4edx', 'course': 'edx4edx',
'branch': 'for_cms', 'branch': 'for_cms',
'origin': 'git@github.com:MITx/edx4edx.git', 'origin': 'git@github.com:MITx/edx4edx.git',
}, },
'6002x-fall-2012': { '6002x-fall-2012': {
'path': REPO_ROOT / '6002x-fall-2012', 'path': DATA_DIR / '6002x-fall-2012',
'org': 'mit.edu', 'org': 'mit.edu',
'course': '6.002x', 'course': '6.002x',
'branch': 'for_cms', 'branch': 'for_cms',
'origin': 'git@github.com:MITx/6002x-fall-2012.git', 'origin': 'git@github.com:MITx/6002x-fall-2012.git',
}, },
'6.00x': { '6.00x': {
'path': REPO_ROOT / '6.00x', 'path': DATA_DIR / '6.00x',
'org': 'mit.edu', 'org': 'mit.edu',
'course': '6.00x', 'course': '6.00x',
'branch': 'for_cms', 'branch': 'for_cms',
'origin': 'git@github.com:MITx/6.00x.git', 'origin': 'git@github.com:MITx/6.00x.git',
}, },
'7.00x': { '7.00x': {
'path': REPO_ROOT / '7.00x', 'path': DATA_DIR / '7.00x',
'org': 'mit.edu', 'org': 'mit.edu',
'course': '7.00x', 'course': '7.00x',
'branch': 'for_cms', 'branch': 'for_cms',
'origin': 'git@github.com:MITx/7.00x.git', 'origin': 'git@github.com:MITx/7.00x.git',
}, },
'3.091x': { '3.091x': {
'path': REPO_ROOT / '3.091x', 'path': DATA_DIR / '3.091x',
'org': 'mit.edu', 'org': 'mit.edu',
'course': '3.091x', 'course': '3.091x',
'branch': 'for_cms', 'branch': 'for_cms',
......
<%inherit file="marketing.html" /> <%inherit file="base.html" />
<%block name="content"> <%block name="content">
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
<section class="activation"> <section class="activation">
<h1>Account already active!</h1> <h1>Account already active!</h1>
<p> This account has already been activated. You can log in at <p> This account has already been activated. <a href="/login">Log in here</a>.</p>
the <a href="/">home page</a>.</p>
</div> </div>
</section> </section>
......
<%inherit file="marketing.html" /> <%inherit file="base.html" />
<%block name="content"> <%block name="content">
<section class="tos"> <section class="tos">
<div> <div>
<h1>Activation Complete!</h1> <h1>Activation Complete!</h1>
<p>Thanks for activating your account. You can log in at the <a href="/">home page</a>.</p> <p>Thanks for activating your account. <a href="/login">Log in here</a>.</p>
</div> </div>
</section> </section>
......
<%inherit file="marketing.html" /> <%inherit file="base.html" />
<%block name="content"> <%block name="content">
<section class="tos"> <section class="tos">
......
<form name="login" action="login", method="post"> <%inherit file="base.html" />
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/> <%! from django.core.urlresolvers import reverse %>
<%block name="title">Log in</%block>
% if next is not None: <%block name="content">
<input type="hidden" name="next" value="${next}"/>
% endif
Username: <input type="text" name="username" /> <section class="main-container">
Possword: <input type="password" name="password" />
<input type="submit" value="Submit" /> <section class="main-content">
</form> <header>
<h3>Log in</h3>
<hr>
</header>
<form id="login_form" action="login_post" method="post">
<label>E-mail</label>
<input name="email" type="email" placeholder="E-mail">
<label>Password</label>
<input name="password" type="password" placeholder="Password">
<label class="remember-me">
<input name="remember" type="checkbox">
Remember me
</label>
<div class="submit">
<input name="submit" type="submit" value="Submit">
</div>
</form>
<section class="login-extra">
<p>
<span>Not enrolled? <a href="${reverse('signup')}">Sign up.</a></span>
<a href="#" class="pwd-reset">Forgot password?</a>
</p>
</section>
</section>
</section>
<script type="text/javascript">
(function() {
function getCookie(name) {
return $.cookie(name);
}
function postJSON(url, data, callback) {
$.ajax({type:'POST',
url: url,
dataType: 'json',
data: data,
success: callback,
headers : {'X-CSRFToken':getCookie('csrftoken')}
});
}
$('form#login_form').submit(function(e) {
e.preventDefault();
var submit_data = $('#login_form').serialize();
postJSON('/login_post',
submit_data,
function(json) {
if(json.success) {
location.href="${reverse('index')}";
} 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);
}
}
);
});
})(this)
</script>
</%block>
<%inherit file="base.html" />
\ No newline at end of file
<h1>Check your email</h1>
<p>An activation link has been sent to ${ email }, along with
instructions for activating your account.</p>
<%! from django.core.urlresolvers import reverse %>
<header> <header>
<nav> <nav>
<h2><a href="/">6.002x circuits and electronics</a></h2> <h2><a href="/">edX CMS: TODO:-course-name-here</a></h2>
<ul> <ul>
<li> <li>
<a href="#" class="new-module wip">New Module</a> <a href="#" class="new-module wip">New Module</a>
...@@ -13,6 +14,12 @@ ...@@ -13,6 +14,12 @@
<ul class="user-nav"> <ul class="user-nav">
<li><a href="#" class="wip">Tasks</a></li> <li><a href="#" class="wip">Tasks</a></li>
<li><a href="#" class="wip">Settings</a></li> <li><a href="#" class="wip">Settings</a></li>
% if user.is_authenticated():
<li><a href="${reverse('logout')}">Log out</a></li>
% else:
<li><a href="${reverse('login')}">Log in</a></li>
% endif
</ul> </ul>
</nav> </nav>
</header> </header>
...@@ -11,16 +11,25 @@ urlpatterns = ('', ...@@ -11,16 +11,25 @@ urlpatterns = ('',
url(r'^$', 'contentstore.views.index', name='index'), url(r'^$', 'contentstore.views.index', name='index'),
url(r'^edit_item$', 'contentstore.views.edit_item', name='edit_item'), url(r'^edit_item$', 'contentstore.views.edit_item', name='edit_item'),
url(r'^save_item$', 'contentstore.views.save_item', name='save_item'), url(r'^save_item$', 'contentstore.views.save_item', name='save_item'),
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<name>[^/]+)$', 'contentstore.views.course_index', name='course_index'), url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<name>[^/]+)$',
'contentstore.views.course_index', name='course_index'),
url(r'^github_service_hook$', 'github_sync.views.github_post_receive'), url(r'^github_service_hook$', 'github_sync.views.github_post_receive'),
) )
# User creation and updating views # User creation and updating views
urlpatterns += ( urlpatterns += (
url(r'^signup$', 'contentstore.views.signup'), url(r'^signup$', 'contentstore.views.signup', name='signup'),
url(r'^create_account$', 'student.views.create_account'), url(r'^create_account$', 'student.views.create_account'),
url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account'), url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account', name='activate'),
# form page
url(r'^login$', 'contentstore.views.login_page', name='login'),
# ajax view that actually does the work
url(r'^login_post$', 'student.views.login_user', name='login_post'),
url(r'^logout$', 'student.views.logout_user', name='logout'),
) )
if settings.DEBUG: if settings.DEBUG:
......
...@@ -147,12 +147,12 @@ def create_account(request, post_override=None): ...@@ -147,12 +147,12 @@ def create_account(request, post_override=None):
js['value'] = "Error (401 {field}). E-mail us.".format(field=a) js['value'] = "Error (401 {field}). E-mail us.".format(field=a)
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
if 'honor_code' not in post_vars or post_vars['honor_code'] != u'true': if post_vars.get('honor_code', 'false') != u'true':
js['value']="To enroll, you must follow the honor code.".format(field=a) js['value']="To enroll, you must follow the honor code.".format(field=a)
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
if 'terms_of_service' not in post_vars or post_vars['terms_of_service'] != u'true': if post_vars.get('terms_of_service', 'false') != u'true':
js['value']="You must accept the terms of service.".format(field=a) js['value']="You must accept the terms of service.".format(field=a)
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
......
...@@ -22,6 +22,7 @@ import random ...@@ -22,6 +22,7 @@ import random
import re import re
import scipy import scipy
import struct import struct
import sys
from lxml import etree from lxml import etree
from xml.sax.saxutils import unescape from xml.sax.saxutils import unescape
...@@ -78,7 +79,7 @@ class LoncapaProblem(object): ...@@ -78,7 +79,7 @@ class LoncapaProblem(object):
- id (string): identifier for this problem; often a filename (no spaces) - id (string): identifier for this problem; often a filename (no spaces)
- state (dict): student state - state (dict): student state
- seed (int): random number generator seed (int) - seed (int): random number generator seed (int)
- system (I4xSystme): I4xSystem instance which provides OS, rendering, and user context - system (I4xSystem): I4xSystem instance which provides OS, rendering, and user context
''' '''
...@@ -196,7 +197,7 @@ class LoncapaProblem(object): ...@@ -196,7 +197,7 @@ class LoncapaProblem(object):
Thus, for example, input_ID123 -> ID123, and input_fromjs_ID123 -> fromjs_ID123 Thus, for example, input_ID123 -> ID123, and input_fromjs_ID123 -> fromjs_ID123
Calles the Response for each question in this problem, to do the actual grading. Calls the Response for each question in this problem, to do the actual grading.
''' '''
self.student_answers = answers self.student_answers = answers
oldcmap = self.correct_map # old CorrectMap oldcmap = self.correct_map # old CorrectMap
...@@ -276,6 +277,34 @@ class LoncapaProblem(object): ...@@ -276,6 +277,34 @@ class LoncapaProblem(object):
parent.remove(inc) parent.remove(inc)
log.debug('Included %s into %s' % (file, self.problem_id)) log.debug('Included %s into %s' % (file, self.problem_id))
def _extract_system_path(self, script):
'''
Extracts and normalizes additional paths for code execution.
For now, there's a default path of data/course/code; this may be removed
at some point.
'''
DEFAULT_PATH = ['code']
# Separate paths by :, like the system path.
raw_path = script.get('system_path', '').split(":") + DEFAULT_PATH
# find additional comma-separated modules search path
path = []
for dir in raw_path:
if not dir:
continue
# path is an absolute path or a path relative to the data dir
dir = os.path.join(self.system.filestore.root_path, dir)
abs_dir = os.path.normpath(dir)
log.debug("appending to path: %s" % abs_dir)
path.append(abs_dir)
return path
def _extract_context(self, tree, seed=struct.unpack('i', os.urandom(4))[0]): # private def _extract_context(self, tree, seed=struct.unpack('i', os.urandom(4))[0]): # private
''' '''
Extract content of <script>...</script> from the problem.xml file, and exec it in the Extract content of <script>...</script> from the problem.xml file, and exec it in the
...@@ -291,7 +320,20 @@ class LoncapaProblem(object): ...@@ -291,7 +320,20 @@ class LoncapaProblem(object):
context['the_lcp'] = self # pass instance of LoncapaProblem in context['the_lcp'] = self # pass instance of LoncapaProblem in
context['script_code'] = '' context['script_code'] = ''
for script in tree.findall('.//script'): self._execute_scripts(tree.findall('.//script'), context)
return context
def _execute_scripts(self, scripts, context):
'''
Executes scripts in the given context.
'''
original_path = sys.path
for script in scripts:
sys.path = original_path + self._extract_system_path(script)
stype = script.get('type') stype = script.get('type')
if stype: if stype:
if 'javascript' in stype: if 'javascript' in stype:
...@@ -308,7 +350,8 @@ class LoncapaProblem(object): ...@@ -308,7 +350,8 @@ class LoncapaProblem(object):
except Exception: except Exception:
log.exception("Error while execing script code: " + code) log.exception("Error while execing script code: " + code)
raise responsetypes.LoncapaProblemError("Error while executing script code") raise responsetypes.LoncapaProblemError("Error while executing script code")
return context finally:
sys.path = original_path
def _extract_html(self, problemtree): # private def _extract_html(self, problemtree): # private
''' '''
......
...@@ -42,6 +42,10 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -42,6 +42,10 @@ class CourseDescriptor(SequenceDescriptor):
@property @property
def title(self): def title(self):
return self.metadata['display_name'] return self.metadata['display_name']
@property
def number(self):
return self.location.course
@property @property
def instructors(self): def instructors(self):
...@@ -79,7 +83,7 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -79,7 +83,7 @@ class CourseDescriptor(SequenceDescriptor):
'requirements', 'syllabus', 'textbook', 'faq', 'more_info', 'number', 'instructors']: 'requirements', 'syllabus', 'textbook', 'faq', 'more_info', 'number', 'instructors']:
try: try:
with self.system.resources_fs.open(path("about") / section_key + ".html") as htmlFile: with self.system.resources_fs.open(path("about") / section_key + ".html") as htmlFile:
return htmlFile.read() return htmlFile.read().decode('utf-8')
except ResourceNotFoundError: except ResourceNotFoundError:
log.exception("Missing about section {key} in course {url}".format(key=section_key, url=self.location.url())) log.exception("Missing about section {key} in course {url}".format(key=section_key, url=self.location.url()))
return "! About section missing !" return "! About section missing !"
...@@ -108,7 +112,7 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -108,7 +112,7 @@ class CourseDescriptor(SequenceDescriptor):
if section_key in ['handouts', 'guest_handouts', 'updates', 'guest_updates']: if section_key in ['handouts', 'guest_handouts', 'updates', 'guest_updates']:
try: try:
with self.system.resources_fs.open(path("info") / section_key + ".html") as htmlFile: with self.system.resources_fs.open(path("info") / section_key + ".html") as htmlFile:
return htmlFile.read() return htmlFile.read().decode('utf-8')
except ResourceNotFoundError: except ResourceNotFoundError:
log.exception("Missing info section {key} in course {url}".format(key=section_key, url=self.location.url())) log.exception("Missing info section {key} in course {url}".format(key=section_key, url=self.location.url()))
return "! Info section missing !" return "! Info section missing !"
......
# Running the CMS
One can start the CMS by running `rake cms`. This will run the server on localhost
port 8001.
However, the server also needs data to work from.
## Installing Mongodb
Please see http://www.mongodb.org/downloads for more detailed instructions.
### Ubuntu
sudo apt-get install mongodb
### OSX
Use the MacPorts package `mongodb` or the Homebrew formula `mongodb`
## Initializing Mongodb
Check out the course data directories that you want to work with into the
`GITHUB_REPO_ROOT` (by default, `../data`). Then run the following command:
rake django-admin[import,cms,dev,../data]
Replace `../data` with your `GITHUB_REPO_ROOT` if it's not the default value.
This will import all courses in your data directory into mongodb
...@@ -108,7 +108,7 @@ environments, defined in `cms/envs`. ...@@ -108,7 +108,7 @@ environments, defined in `cms/envs`.
- javascript -- we use coffeescript, which compiles to js, and is much nicer to work with. Look for `*.coffee` files. We use _jasmine_ for testing js. - javascript -- we use coffeescript, which compiles to js, and is much nicer to work with. Look for `*.coffee` files. We use _jasmine_ for testing js.
- _mako_ -- we use this for templates, and have a fork called mitxmako (TODO: why did we have to fork mako?) - _mako_ -- we use this for templates, and have wrapper called mitxmako that makes mako look like the django templating calls.
We use a fork of django-pipeline to make sure that the js and css always reflect the latest `*.coffee` and `*.sass` files (We're hoping to get our changes merged in the official version soon). This works differently in development and production. Test uses the production settings. We use a fork of django-pipeline to make sure that the js and css always reflect the latest `*.coffee` and `*.sass` files (We're hoping to get our changes merged in the official version soon). This works differently in development and production. Test uses the production settings.
......
...@@ -95,7 +95,7 @@ for static_dir in STATICFILES_DIRS: ...@@ -95,7 +95,7 @@ for static_dir in STATICFILES_DIRS:
except ValueError: except ValueError:
data_dir = static_dir data_dir = static_dir
if not data_dir.startswith(REPO_ROOT): if data_dir.startswith(REPO_ROOT):
new_staticfiles_dirs.append(static_dir) new_staticfiles_dirs.append(static_dir)
STATICFILES_DIRS = new_staticfiles_dirs STATICFILES_DIRS = new_staticfiles_dirs
......
.container.about { .container.about {
padding: 20px 0 120px; padding: 20px 10px 120px;
> nav { > nav {
margin-bottom: 80px; margin-bottom: 80px;
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
} }
.photo { .photo {
@include box-sizing(border-box);
background: rgb(255,255,255); background: rgb(255,255,255);
border: 1px solid rgb(210,210,210); border: 1px solid rgb(210,210,210);
padding: 1px; padding: 1px;
...@@ -64,6 +65,11 @@ ...@@ -64,6 +65,11 @@
} }
} }
> article {
float: left;
width: flex-grid(8);
}
&.left { &.left {
.photo { .photo {
float: left; float: left;
......
...@@ -24,8 +24,9 @@ ...@@ -24,8 +24,9 @@
@include clearfix; @include clearfix;
margin: 0 auto; margin: 0 auto;
max-width: 1200px; max-width: 1200px;
padding: 0px 10px;
position: relative; position: relative;
width: flex-grid(12); width: grid-width(12);
z-index: 2; z-index: 2;
...@@ -243,12 +244,12 @@ ...@@ -243,12 +244,12 @@
border: 1px solid rgb(200,200,200); border: 1px solid rgb(200,200,200);
border-top: none; border-top: none;
float: left; float: left;
padding: 20px 20px 30px; padding: 16px 20px 30px;
width: flex-grid(4); width: flex-grid(4);
header { header {
margin-bottom: 30px; margin-bottom: 30px;
padding-bottom: 20px; padding-bottom: 16px;
position: relative; position: relative;
text-align: center; text-align: center;
...@@ -358,18 +359,42 @@ ...@@ -358,18 +359,42 @@
margin-bottom: 20px; margin-bottom: 20px;
padding-bottom: 10px; padding-bottom: 10px;
&:hover {
.icon {
opacity: 1;
}
}
p { p {
color: $lighter-base-font-color; color: $lighter-base-font-color;
float: left; float: left;
font-family: $sans-serif; font-family: $sans-serif;
} }
img { .icon {
background: rgb(230,230,230); background-size: cover;
float: left; float: left;
height: 19px; height: 19px;
margin: 3px 10px 0 0; margin: 2px 10px 0 0;
opacity: 0.6;
@include transition(all, 0.15s, linear);
width: 19px; width: 19px;
&.start-icon {
@include background-image(url('/static/images/portal-icons/calendar-icon.png'));
}
&.final-icon {
@include background-image(url('/static/images/portal-icons/pencil-icon.png'));
}
&.length-icon {
@include background-image(url('/static/images/portal-icons/chart-icon.png'));
}
&.number-icon {
@include background-image(url('/static/images/portal-icons/course-info-icon.png'));
}
} }
span { span {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
header.search { header.search {
background: rgb(240,240,240); background: rgb(240,240,240);
@include background-image(url('/static/images/shot-2-large.jpg')); //@include background-image(url('/static/images/shot-2-large.jpg'));
background-size: cover; background-size: cover;
border-bottom: 1px solid rgb(100,100,100); border-bottom: 1px solid rgb(100,100,100);
@include box-shadow(inset 0 -1px 8px 0 rgba(0,0,0, 0.2), inset 0 1px 12px 0 rgba(0,0,0, 0.3)); @include box-shadow(inset 0 -1px 8px 0 rgba(0,0,0, 0.2), inset 0 1px 12px 0 rgba(0,0,0, 0.3));
......
...@@ -30,29 +30,62 @@ ...@@ -30,29 +30,62 @@
> ul { > ul {
background: rgb(250,250,250); background: rgb(250,250,250);
border: 1px solid rgb(220,220,220); border: 1px solid rgb(200,200,200);
border-top: none; border-top: none;
@include border-bottom-radius(4px); @include border-bottom-radius(4px);
@include box-sizing(border-box); @include box-sizing(border-box);
@include box-shadow(inset 0 0 3px 0 rgba(0,0,0, 0.15));
@include clearfix; @include clearfix;
margin: 0px; margin: 0px;
padding: 0px 10px 20px; padding: 20px 10px 10px;
width: flex-grid(12); width: flex-grid(12);
li { li {
@include clearfix;
border-bottom: 1px dotted rgb(220,220,220);
list-style: none; list-style: none;
margin-bottom: 20px;
padding-bottom: 10px;
p { &:hover {
.title .icon {
opacity: 1;
}
}
span.title {
color: $lighter-base-font-color; color: $lighter-base-font-color;
float: left;
font-family: $sans-serif; font-family: $sans-serif;
text-shadow: 0 1px rgba(255,255,255, 0.8);
span { .icon {
font-weight: 700; background-size: cover;
margin-left: 10px; float: left;
text-transform: none; height: 19px;
margin: 2px 8px 0 0;
opacity: 0.6;
@include transition(all, 0.15s, linear);
width: 19px;
&.email-icon {
@include background-image(url('/static/images/portal-icons/email-icon.png'));
}
&.location-icon {
@include background-image(url('/static/images/portal-icons/home-icon.png'));
}
&.language-icon {
@include background-image(url('/static/images/portal-icons/language-icon.png'));
}
} }
} }
span.data {
color: $lighter-base-font-color;
font-weight: 700;
margin-left: 12px;
}
} }
} }
} }
...@@ -254,9 +287,11 @@ ...@@ -254,9 +287,11 @@
.course-work-icon { .course-work-icon {
background: rgb(200,200,200); @include background-image(url('/static/images/portal-icons/pencil-icon.png'));
background-size: cover;
float: left; float: left;
height: 22px; height: 22px;
opacity: 0.7;
width: 22px; width: 22px;
} }
...@@ -280,7 +315,7 @@ ...@@ -280,7 +315,7 @@
.progress { .progress {
@include box-shadow(0 1px 0 0 rgba(255,255,255, 0.6)); @include box-shadow(0 1px 0 0 rgba(255,255,255, 0.6));
left: 40px; left: 35px;
position: absolute; position: absolute;
right: 130px; right: 130px;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
@extend .animation-home-header-pop-up; @extend .animation-home-header-pop-up;
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
padding: 0 10px;
position: relative; position: relative;
text-align: center; text-align: center;
...@@ -32,7 +33,7 @@ ...@@ -32,7 +33,7 @@
border: 1px solid rgb(100,100,100); border: 1px solid rgb(100,100,100);
@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 inline-block; @include inline-block;
padding: 30px 50px 30px; padding: 20px 30px 30px;
position: relative; position: relative;
text-align: center; text-align: center;
z-index: 1; z-index: 1;
...@@ -40,22 +41,10 @@ ...@@ -40,22 +41,10 @@
.title { .title {
@include inline-block; @include inline-block;
margin-right: 50px;
padding-right: 50px;
position: relative; position: relative;
text-align: left; text-align: left;
vertical-align: middle; vertical-align: middle;
&::before {
@extend .faded-vertical-divider;
content: "";
display: block;
height: 170px;
position: absolute;
right: 0px;
top: -20px;
}
&::after { &::after {
@extend .faded-vertical-divider-light; @extend .faded-vertical-divider-light;
content: ""; content: "";
...@@ -99,66 +88,139 @@ ...@@ -99,66 +88,139 @@
} }
} }
.social-sharing { .secondary-actions {
@include box-sizing(border-box); @include box-sizing(border-box);
@include clearfix;
float: left; float: left;
height: 44px; height: 47px;
position: relative;
text-align: center;
width: flex-grid(6); width: flex-grid(6);
&:hover { a.intro-video {
.sharing-message { background: rgb(245,245,245);
opacity: 1; @include background-image(linear-gradient(-90deg, rgb(250,250,250), rgb(235,235,235)));
top: 56px; border: 1px solid rgb(200,200,200);
} @include border-radius(30px);
}
.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); @include box-sizing(border-box);
color: rgb(255,255,255); @include box-shadow(inset 0 -1px 0 0 rgba(255,255,255, 0.8), inset 0 1px 0 0 rgba(255,255,255, 0.8));
float: right; @include clearfix;
font-family: $serif; display: block;
font-size: 0.9em; float: left;
font-style: italic; height: 100%;
left: 50%; overflow: hidden;
margin-left: -110px; text-align: middle;
opacity: 0; width: flex-grid(6);
padding: 6px 10px;
position: absolute;
text-align: center;
@include transition(all, 0.15s, ease-out);
top: 65px;
width: 220px;
&:hover { &:hover {
opacity: 0; text-decoration: none;
p {
color: $base-font-color;
}
.video {
opacity: 1;
}
} }
}
.share { .video {
@include background-image(url('/static/images/shot-2-large.jpg'));
background-size: cover;
border-right: 1px solid rgb(200,200,200);
@include border-left-radius(30px);
@include box-shadow(1px 0 0 0 rgba(255,255,255, 0.6), inset 1px 0 0 0 rgba(255,255,255, 0.8), inset 0 0 0 1px rgba(255,255,255, 0.7));
float: left;
height: 100%;
opacity: 0.8;
position: relative;
@include transition(all, 0.15s, linear);
width: 60px;
vertical-align: middle;
.play {
@include background-image(url('/static/images/portal-icons/video-play-icon.png'));
background-size: cover;
height: 31px;
margin-left: -13px;
margin-top: -15px;
left: 50%;
position: absolute;
top: 50%;
width: 31px;
}
}
p {
color: $lighter-base-font-color;
font-style: italic;
padding-top: 10px;
text-align: center;
text-shadow: 0 1px rgba(255,255,255, 0.6);
@include transition(all, 0.15s, linear);
vertical-align: middle;
}
}
.social-sharing {
@include box-sizing(border-box);
float: left;
height: 44px; height: 44px;
@include inline-block; margin-right: flex-gutter();
margin-right: 10px; position: relative;
opacity: 0.5; text-align: center;
@include transition(all, 0.15s, linear); width: flex-grid(6);
width: 44px;
&:hover { &:hover {
opacity: 1; .sharing-message {
opacity: 1;
top: 56px;
}
} }
img { .sharing-message {
width: 100%; @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: 65px;
width: 220px;
&:hover {
opacity: 0;
}
} }
&:last-child { .share {
margin-right: 0px; 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;
}
} }
} }
} }
...@@ -168,15 +230,18 @@ ...@@ -168,15 +230,18 @@
background: #fff; background: #fff;
border: 1px solid rgb(200,200,200); border: 1px solid rgb(200,200,200);
@include box-sizing(border-box); @include box-sizing(border-box);
float: left;
@include inline-block; @include inline-block;
padding: 1px; padding: 1px;
position: relative; position: relative;
vertical-align: middle; vertical-align: middle;
width: 210px; //width: 210px;
width: flex-grid(3);
z-index: 2; z-index: 2;
.hero { .hero {
height: 125px; //height: 125px;
height: 100%;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
@import 'bourbon/bourbon'; @import 'bourbon/bourbon';
@import 'base_styles/reset';
@import 'base_styles/font_face';
@import 'base_styles/base';
@import 'base_styles/base_mixins';
@import 'base_styles/base_extends';
@import 'base_styles/base_animations';
@import 'base/reset';
@import 'base/font_face';
@import 'base/variables';
@import 'base/base';
@import 'base/mixins';
@import 'base/extends';
@import 'base/animations';
// Courseware styles
@import 'sass_old/base/variables'; @import 'sass_old/base/variables';
@import 'sass_old/base/extends'; @import 'sass_old/base/extends';
@import 'sass_old/base/functions'; @import 'sass_old/base/functions';
@import 'shared_styles/shared_forms';
@import 'shared_styles/shared_footer'; // Multicourse styles
@import 'shared_styles/shared_header'; @import 'shared/forms';
@import 'shared_styles/shared_list_of_courses'; @import 'shared/footer';
@import 'shared_styles/shared_course_filter'; @import 'shared/header';
@import 'shared_styles/shared_modal'; @import 'shared/course_object';
@import 'shared/course_filter';
@import 'shared/modal';
@import 'shared/activation_messages';
@import 'home'; @import 'home';
@import 'dashboard'; @import 'dashboard';
@import 'course_object'; @import 'courseware_subnav';
@import 'courses'; @import 'courses';
@import 'course_about'; @import 'course_about';
@import 'jobs'; @import 'jobs';
@import 'about_pages'; @import 'about_pages';
@import 'press_release'; @import 'press_release';
// Courseware styles
@import 'sass_old/courseware/courseware'; @import 'sass_old/courseware/courseware';
@import 'sass_old/courseware/sequence-nav'; @import 'sass_old/courseware/sequence-nav';
@import 'sass_old/courseware/sidebar'; @import 'sass_old/courseware/sidebar';
......
$gw-column: 60px;
$gw-gutter: 25px;
$fg-column: $gw-column;
$fg-gutter: $gw-gutter;
$fg-max-columns: 12;
$sans-serif: 'Open Sans', $verdana;
$serif: $georgia;
$base-font-color: rgb(60,60,60);
$lighter-base-font-color: rgb(160,160,160);
$blue: rgb(29,157,217);
$pink: rgb(182,37,104);
$yellow: rgb(255, 252, 221);
html, body { html, body {
background: rgb(250,250,250); background: rgb(250,250,250);
//background: rgb(77, 82, 99);
font-family: $sans-serif; font-family: $sans-serif;
font-size: 1em; font-size: 1em;
line-height: 1em; line-height: 1em;
-webkit-font-smoothing: antialiased;
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
...@@ -99,8 +82,8 @@ a:link, a:visited { ...@@ -99,8 +82,8 @@ a:link, a:visited {
.container { .container {
@include clearfix; @include clearfix;
margin: 0 auto 0; margin: 0 auto 0;
max-width: 1200px; padding: 0px 10px;
width: flex-grid(12); width: grid-width(12);
} }
.static-container { .static-container {
......
...@@ -76,3 +76,16 @@ ...@@ -76,3 +76,16 @@
rgba(200,200,200, 0))); rgba(200,200,200, 0)));
border: none; border: none;
} }
//Styles for Error messages
.error-message-colors {
background: $error-red;
border: 1px solid rgb(202, 17, 17);
color: rgb(143, 14, 14);
}
.success-message-colors {
background: rgb(99, 236, 137);
border: 1px solid rgb(17, 202, 54);
color: rgb(35, 143, 14);
}
$gw-column: 80px;
$gw-gutter: 20px;
$fg-column: $gw-column;
$fg-gutter: $gw-gutter;
$fg-max-columns: 12;
$sans-serif: 'Open Sans', $verdana;
$serif: $georgia;
$base-font-color: rgb(60,60,60);
$lighter-base-font-color: rgb(160,160,160);
$blue: rgb(29,157,217);
$pink: rgb(182,37,104);
$yellow: rgb(255, 252, 221);
$error-red: rgb(253, 87, 87);
.container.activation {
padding: 60px 0px 120px;
h1 {
margin-bottom: 20px;
padding: 10px;
&.invalid {
@extend .error-message-colors;
}
&.valid {
@extend .success-message-colors;
}
}
h1 + hr {
margin-bottom: 30px;
}
.message {
background: rgb(252,252,252);
border: 1px solid rgb(200,200,200);
@include box-shadow(0 3px 20px 0 rgba(0,0,0, 0.2));
@include border-radius(4px);
margin: 0 auto;
padding: 40px;
width: flex-grid(6);
}
}
.highlighted-courses, .find-courses { .highlighted-courses, .find-courses {
.courses { .courses {
@include clearfix; @include clearfix;
padding: 40px 15px 15px; padding: 40px 0px 15px;
.course { .course {
background: rgb(250,250,250); background: rgb(250,250,250);
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
p { p {
color: rgb(255,255,255); color: rgb(255,255,255);
font-style: italic;
line-height: 1.2em; line-height: 1.2em;
padding: 4px 12px 5px; padding: 4px 12px 5px;
} }
...@@ -69,7 +70,11 @@ ...@@ -69,7 +70,11 @@
h2 { h2 {
color: $base-font-color; color: $base-font-color;
font-family: $sans-serif;
font-size: 1em;
font-weight: 700;
margin-bottom: 0px; margin-bottom: 0px;
overflow: hidden;
padding-top: 9px; padding-top: 9px;
text-shadow: 0 1px rgba(255,255,255, 0.6); text-shadow: 0 1px rgba(255,255,255, 0.6);
text-overflow: ellipsis; text-overflow: ellipsis;
......
...@@ -12,11 +12,10 @@ footer { ...@@ -12,11 +12,10 @@ footer {
} }
nav { nav {
@include box-sizing(border-box);
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
padding: 30px 10px 0; padding: 30px 10px 0;
width: flex-grid(12); width: grid-width(12);
.top { .top {
border-bottom: 1px solid rgb(200,200,200); border-bottom: 1px solid rgb(200,200,200);
......
...@@ -42,5 +42,6 @@ form { ...@@ -42,5 +42,6 @@ form {
letter-spacing: 1px; letter-spacing: 1px;
text-transform: uppercase; text-transform: uppercase;
vertical-align: top; vertical-align: top;
-webkit-font-smoothing: antialiased;
} }
} }
...@@ -9,12 +9,11 @@ header.global { ...@@ -9,12 +9,11 @@ header.global {
nav { nav {
@include clearfix; @include clearfix;
@include box-sizing(border-box);
height: 40px; height: 40px;
margin: 0 auto; margin: 0 auto;
max-width: 1200px; max-width: 1200px;
padding-top: 14px; padding: 14px 10px 0px;
width: flex-grid(12); width: grid-width(12);
} }
h1.logo { h1.logo {
...@@ -136,57 +135,65 @@ header.global { ...@@ -136,57 +135,65 @@ header.global {
&.user { &.user {
float: right; float: right;
> li.primary {
display: block;
float: left;
margin: 0px;
> a {
margin: 0px;
@include border-right-radius(0px);
}
&:last-child {
> a {
@include border-radius(0 4px 4px 0);
border-left: none;
}
}
}
a.user-link { a.user-link {
padding: 10px 12px 10px 42px; padding: 10px 12px 10px 42px;
position: relative; position: relative;
text-transform: none; text-transform: none;
.avatar { .avatar {
background: rgb(220,220,220); //background: rgb(220,220,220);
@include border-radius(3px); @include background-image(url('/static/images/portal-icons/home-icon.png'));
border: 1px solid rgb(80,80,80); background-size: cover;
@include box-shadow(0 1px 0 0 rgba(255,255,255, 0.6)); //@include border-radius(3px);
height: 21px; //border: 1px solid rgb(80,80,80);
//@include box-shadow(0 1px 0 0 rgba(255,255,255, 0.6));
height: 26px;
@include inline-block; @include inline-block;
left: 8px; left: 8px;
opacity: 0.5;
overflow: hidden; overflow: hidden;
position: absolute; position: absolute;
top: 7px; top: 4px;
width: 21px; @include transition(all, 0.15s, linear);
width: 26px;
&::after { }
@include background-image(linear-gradient((-60deg), rgba(0,0,0, 0) 0%, rgba(0,0,0, 0.1) 50%, rgba(0,0,0, 0.2) 50%, rgba(0,0,0, 0.3) 100%));
content: "";
display: block;
height: 100%;
position: absolute;
right: 0px;
top: 0px;
width: 100%;
}
img { &:hover {
@include border-radius(4px); .avatar {
display: block; opacity: 0.8;
min-height: 100%;
min-width: 100%;
height: 100%;
} }
} }
} }
ul.dropdown-menu { ul.dropdown-menu {
background: rgb(252,252,252);
@include border-radius(4px); @include border-radius(4px);
@include box-shadow(0 1px 6px 0 rgba(0,0,0, 0.3)); @include box-shadow(0 2px 24px 0 rgba(0,0,0, 0.3));
border: 1px solid rgb(0,0,0); border: 1px solid rgb(100,100,100);
@include background-image(linear-gradient(-90deg, rgba(0,0,0, 0.9) 0%,
rgba(0,0,0, 0.7) 100%));
display: none; display: none;
padding: 5px 10px; padding: 5px 10px;
position: absolute; position: absolute;
right: 4px; right: 0px;
top: 50px; top: 50px;
width: 150px; width: 170px;
z-index: 3; z-index: 3;
&.expanded { &.expanded {
...@@ -196,8 +203,8 @@ header.global { ...@@ -196,8 +203,8 @@ header.global {
&::before { &::before {
background: transparent; background: transparent;
border: { border: {
top: 6px solid rgba(0,0,0, 1); top: 6px solid rgba(252,252,252, 1);
right: 6px solid rgba(0,0,0, 1); right: 6px solid rgba(252,252,252, 1);
bottom: 6px solid transparent; bottom: 6px solid transparent;
left: 6px solid transparent; left: 6px solid transparent;
} }
...@@ -214,7 +221,7 @@ header.global { ...@@ -214,7 +221,7 @@ header.global {
li { li {
display: block; display: block;
border-top: 1px solid rgba(0,0,0, 0.4); border-top: 1px dotted rgba(200,200,200, 1);
@include box-shadow(inset 0 1px 0 0 rgba(255,255,255, 0.05)); @include box-shadow(inset 0 1px 0 0 rgba(255,255,255, 0.05));
&:first-child { &:first-child {
...@@ -223,31 +230,23 @@ header.global { ...@@ -223,31 +230,23 @@ header.global {
} }
> a { > a {
@include box-sizing(border-box); border: 1px solid transparent;
@include border-radius(3px); @include border-radius(3px);
color: rgba(255,255,255, 0.9); @include box-sizing(border-box);
color: $blue;
cursor: pointer;
display: block; display: block;
font-family: $serif;
height: auto;
line-height: 1em;
margin: 5px 0px; margin: 5px 0px;
overflow: hidden; overflow: hidden;
padding: 3px 5px 4px; padding: 3px 5px 4px;
text-shadow: none;
text-overflow: ellipsis; text-overflow: ellipsis;
text-transform: none; @include transition(padding, 0.15s, linear);
@include transition(padding, 0.1s, linear);
white-space: nowrap; white-space: nowrap;
width: 100%; width: 100%;
&:hover { &:hover {
background: $blue; color: $base-font-color;
@include background-image(linear-gradient(-90deg, lighten($blue, 15%) 0%, text-decoration: none;
rgba($blue, 1) 100%));
border-color: rgba(0,0,0, 1);
@include box-shadow(none);
padding-left: 8px;
text-shadow: 0 -1px rgba(0,0,0, 0.2);
} }
} }
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
left: 50%; left: 50%;
padding: 8px; padding: 8px;
position: absolute; position: absolute;
width: grid-width(6); width: grid-width(5);
z-index: 12; z-index: 12;
&.video-modal { &.video-modal {
...@@ -107,7 +107,7 @@ ...@@ -107,7 +107,7 @@
} }
#enroll_error, #login_error { #enroll_error, #login_error {
background: rgb(253, 87, 87); background: $error-red;
border: 1px solid rgb(202, 17, 17); border: 1px solid rgb(202, 17, 17);
color: rgb(143, 14, 14); color: rgb(143, 14, 14);
display: none; display: none;
...@@ -115,15 +115,9 @@ ...@@ -115,15 +115,9 @@
padding: 12px; padding: 12px;
} }
//#enroll { .activation-message {
//padding: 0 40px; padding: 0 40px 10px;
}
//h1 {
//font: normal 1em/1.6em $sans-serif;
//margin-bottom: 10px;
//text-align: left;
//}
//}
form { form {
margin-bottom: 12px; margin-bottom: 12px;
......
...@@ -12,14 +12,16 @@ ...@@ -12,14 +12,16 @@
<section class="vision"> <section class="vision">
<section class="company-mission message left"> <section class="company-mission message left">
<div class="inner-wrapper"> <div class="photo">
<div class="photo"> <img src="">
<img src="">
</div>
<h2>Mission: Educate 1 billion people around the world</h2>
<p>“EdX represents a unique opportunity to improve education on our own campuses through online learning, while simultaneously creating a bold new educational path for millions of learners worldwide,” MIT President Susan Hockfield said.</p>
<p>Harvard President Drew Faust said, “edX gives Harvard and MIT an unprecedented opportunity to dramatically extend our collective reach by conducting groundbreaking research into effective education and by extending online access to quality higher education.”
</div> </div>
<article>
<h2>About edX</h2>
<p>EdX is a joint partnership between The Massachusetts Institute of Technology (MIT) and Harvard University to offer online learning to millions of people around the world. EdX offer Harvard and MIT classes online for free. Through this partnership, with other partners to follow, the institutions aim to extend their collective reach to build a global community of online students.</p>
<p>MIT’s Director of the Computer Science and Artificial Intelligence Laboratory Anant Agarwal serves as the first president of edX, and Harvard’s Faculty of Arts and Sciences Dean Michael D. Smith leads faculty in developing courses. Along with offering online courses, the institutions will use edX to research how students learn and how technology can facilitate teaching—both on-campus and online.</p>
<p>EdX is based on an open-source technological platform that provides interactive educational materials designed specifically for the web, and is available to anyone in the world with an internet connection.</p>
<p>Harvard and MIT have created edX open-source software and invite interested institutions to join edX with their own educational content. EdX is a Cambridge-based not-for-profit, equally owned and funded by Harvard and MIT</p>
</article>
<hr class="fade-right-hr-divider"> <hr class="fade-right-hr-divider">
</section> </section>
...@@ -27,9 +29,11 @@ ...@@ -27,9 +29,11 @@
<div class="photo"> <div class="photo">
<img src=""> <img src="">
</div> </div>
<h2>Mission: Educate 1 billion people around the world</h2> <article>
<p>“EdX represents a unique opportunity to improve education on our own campuses through online learning, while simultaneously creating a bold new educational path for millions of learners worldwide,” MIT President Susan Hockfield said.</p> <h2>Harvard University</h2>
<p>Harvard President Drew Faust said, “edX gives Harvard and MIT an unprecedented opportunity to dramatically extend our collective reach by conducting groundbreaking research into effective education and by extending online access to quality higher education.” <p>Harvard University is devoted to excellence in teaching, learning, and research, and to developing leaders in many disciplines who make a difference globally. Harvard faculty are engaged with teaching and research to push the boundaries of human knowledge. For students who are excited to investigate the biggest issues of the 21st century, Harvard offers an unparalleled student experience and a generous financial aid program, with over $160 million awarded to more than 60% of our undergraduate students. The University has twelve degree-granting Schools in addition to the Radcliffe Institute for Advanced Study, offering a truly global education.</p>
<p>Established in 1636, Harvard is the oldest institution of higher education in the United States. The University, which is based in Cambridge and Boston, Massachusetts, has an enrollment of over 20,000 degree candidates, including undergraduate, graduate, and professional students. Harvard has more than 360,000 alumni around the world.</p>
</article>
<hr class="fade-left-hr-divider"> <hr class="fade-left-hr-divider">
</section> </section>
...@@ -37,9 +41,12 @@ ...@@ -37,9 +41,12 @@
<div class="photo"> <div class="photo">
<img src=""> <img src="">
</div> </div>
<h2>Mission: Educate 1 billion people around the world</h2> <article>
<p>“EdX represents a unique opportunity to improve education on our own campuses through online learning, while simultaneously creating a bold new educational path for millions of learners worldwide,” MIT President Susan Hockfield said.</p> <h2>Massachusetts Institute of Technology</h2>
<p>Harvard President Drew Faust said, “edX gives Harvard and MIT an unprecedented opportunity to dramatically extend our collective reach by conducting groundbreaking research into effective education and by extending online access to quality higher education.” <p>The Massachusetts Institute of Technology — a coeducational, privately endowed research university founded in 1861 — is dedicated to advancing knowledge and educating students in science, technology, and other areas of scholarship that will best serve the nation and the world in the 21st century. The Institute has close to 1,000 faculty and 10,000 undergraduate and graduate students. It is organized into five Schools: Architecture and Urban Planning; Engineering; Humanities, Arts, and Social Sciences; Sloan School of Management; and Science.</p>
<p>MIT's commitment to innovation has led to a host of scientific breakthroughs and technological advances. Seventy-eight MIT alumni, faculty, researchers and staff have won Nobel Prizes.</p>
<p>Current areas of research and education include neuroscience and the study of the brain and mind, bioengineering, cancer, energy, the environment and sustainable development, information sciences and technology, new media, financial technology, and entrepreneurship.</p>
</article>
</section> </section>
</section> </section>
</section> </section>
......
<%inherit file="marketing.html" /> <%! from django.core.urlresolvers import reverse %>
<%inherit file="main.html" />
<section class="tos"> <%namespace name='static' file='static_content.html'/>
<div>
<section class="activation"> <section class="container activation">
<h1>Account already active!</h1>
<!-- <p>Now go <a href="/">log in</a> and try the course!</a></p> --> <section class="message">
<p> This account has already been activated. You can log in at <h1>Account already active!</h1>
the <a href="/">6.002x course page</a>.</p> <hr class="horizontal-divider">
</div>
<p> This account has already been activated. You can now <a href="#login-modal" rel="leanModal">login</a>.</p>
</section>
</section> </section>
<%inherit file="marketing.html" /> <%! from django.core.urlresolvers import reverse %>
<%inherit file="main.html" />
<section class="tos">
<div> <%namespace name='static' file='static_content.html'/>
<h1>Activation Complete!</h1>
<!-- <p>Now go <a href="/">log in</a> and try the course!</a></p> --> <section class="container activation">
<p>Thanks for activating your account. You can log in at the <a href="/">6.002x course page</a>.</p>
</div> <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> </section>
<%inherit file="marketing.html" /> <%! from django.core.urlresolvers import reverse %>
<%inherit file="main.html" />
<section class="tos"> <%namespace name='static' file='static_content.html'/>
<div>
<h1>Activation Invalid</h1>
<p>Something went wrong. Check to make sure the URL you went to was <section class="container activation">
correct -- e-mail programs will sometimes split it into two
lines. If you still have issues, e-mail us to let us know what happened
at <a href="mailto:bugs@mitx.mit.edu">bugs@mitx.mit.edu</a>.</p>
<p>Or you can go back to the <a href="/">6.002x course page</a>.</p> <section class="message">
</div> <h1 class="invalid">Activation Invalid</h1>
<hr class="horizontal-divider">
<p>Something went wrong. Check to make sure the URL you went to was
correct -- e-mail programs will sometimes split it into two
lines. If you still have issues, e-mail us to let us know what happened
at <a href="mailto:bugs@edx.org">bugs@edx.org</a>.</p>
<p>Or you can go back to the <a href="/">home page</a>.</p>
</section>
</section> </section>
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<header class="course-preview"> <header class="course-preview">
<a href="${reverse('about_course', args=[course.id])}"> <a href="${reverse('about_course', args=[course.id])}">
<hgroup> <hgroup>
<h2>${course.get_about_section('title')}</h2> <h2>${course.number} ${course.get_about_section('title')}</h2>
</hgroup> </hgroup>
<div class="info-link">&#x2794;</div> <div class="info-link">&#x2794;</div>
</a> </a>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
<section class="find-courses"> <section class="find-courses">
<header class="search"> <header class="search" style="background: url('/static/images/shot-2-large.jpg')">
<div class="inner-wrapper main-search"> <div class="inner-wrapper main-search">
<hgroup> <hgroup>
<div class="logo"> <div class="logo">
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<section class="container"> <section class="container">
## I'm removing this for now since we aren't using it for the fall. ## I'm removing this for now since we aren't using it for the fall.
<%include file="course_filter.html" /> ## <%include file="course_filter.html" />
<section class="courses"> <section class="courses">
%for course in courses: %for course in courses:
<%include file="course.html" args="course=course" /> <%include file="course.html" args="course=course" />
......
...@@ -11,13 +11,13 @@ ...@@ -11,13 +11,13 @@
<section class="user-info"> <section class="user-info">
<ul> <ul>
<li> <li>
<img src=""><p>Email<span>${ user.email }</span></p> <span class="title"><div class="icon email-icon"></div>Email</span><span class="data">${ user.email }</span>
</li> </li>
<li> <li>
<img src=""><p>Location<span>${ user.profile.location }</span></p> <span class="title"><div class="icon location-icon"></div>Location</span><span class="data">${ user.profile.location }</span>
</li> </li>
<li> <li>
<img src=""><p>Language<span>${ user.profile.language }</span></p> <span class="title"><div class="icon language-icon"></div>Language</span><span class="data">${ user.profile.language }</span>
</li> </li>
</ul> </ul>
</section> </section>
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
<p>Class Starts - <span>9/2/2012</span></div> <p>Class Starts - <span>9/2/2012</span></div>
</section> </section>
<section class="meta"> <section class="meta">
<div src="" class="course-work-icon"></div> <div class="course-work-icon"></div>
<div class="progress"> <div class="progress">
<div class="meter"> <div class="meter">
<div class="meter-fill"></div> <div class="meter-fill"></div>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<a href="/t/about.html">About</a> <a href="/t/about.html">About</a>
<a href="#">Blog</a> <a href="#">Blog</a>
<a href="/t/jobs.html">Jobs</a> <a href="/t/jobs.html">Jobs</a>
<a href="/t/contact.html">Contact</a>
</section> </section>
<section class="social"> <section class="social">
......
...@@ -7,31 +7,37 @@ ...@@ -7,31 +7,37 @@
<div class="outer-wrapper"> <div class="outer-wrapper">
<div class="inner-wrapper"> <div class="inner-wrapper">
<div class="title"> <div class="title">
<h1>The Future of Online Education</h1> <h1>Online education for anyone, anywhere, at anytime</h1>
<div class="main-cta"> <div class="main-cta">
<a href="${reverse('courses')}" class="find-courses">Find Courses</a> <a href="#signup-modal" class="find-courses" rel="leanModal">Sign Up</a>
</div> </div>
<div class="social-sharing"> <div class="secondary-actions">
<div class="sharing-message">Share with friends and family!</div> <div class="social-sharing">
<a href="#" class="share"> <div class="sharing-message">Share with friends and family!</div>
<img src="${static.url('images/twitter-sharing.png')}"> <a href="#" class="share">
</a> <img src="${static.url('images/twitter-sharing.png')}">
<a href="#" class="share"> </a>
<img src="${static.url('images/facebook-sharing.png')}"> <a href="#" class="share">
</a> <img src="${static.url('images/facebook-sharing.png')}">
<a href="#" class="share"> </a>
<img src="${static.url('images/email-sharing.png')}"> <a href="#" class="share">
<img src="${static.url('images/email-sharing.png')}">
</a>
</div>
<a href="#video-modal" class="intro-video" rel="leanModal">
<!--
-<img src="${static.url('images/courses/space1.jpg')}" />
-->
<div class="video">
<div class="play"></div>
</div>
<p>Play intro video</p>
</a> </a>
</div> </div>
</div> </div>
<a href="#video-modal" class="media" rel="leanModal">
<div class="hero">
<img src="${static.url('images/courses/space1.jpg')}" />
<div class="play-intro"></div>
</div>
</a>
</div> </div>
</div> </div>
</header> </header>
...@@ -87,10 +93,10 @@ ...@@ -87,10 +93,10 @@
<section class="blog-posts"> <section class="blog-posts">
<article> <article>
<a href="#" class="post-graphics"> <a href="#" class="post-graphics">
<img src="${static.url('images/courses/space1.jpg')}" /> <img src="${static.url('images/mongolia_post.jpeg')}" />
</a> </a>
<div class="post-name"> <div class="post-name">
<a href="">Online Classes Cut Costs, But Do They Dilute Brands?</a> <a href="">Opening Doors For Exceptional Students: 6.002x in Mongolia.</a>
<p class="post-date">7/12/2012</p> <p class="post-date">7/12/2012</p>
</div> </div>
</article> </article>
......
...@@ -22,6 +22,14 @@ ...@@ -22,6 +22,14 @@
<h2>We are currently looking for</h2> <h2>We are currently looking for</h2>
<section class="jobs-listing"> <section class="jobs-listing">
<article id="technology-team" class="job">
<div class="inner-wrapper">
<h3>Technology Team</h3>
<p>[Looking for both back-end and front-end developers. Strong backgrounds in machine learning, education, user interaction design, big data, or social network analysis are desirable, but team members do wear many hats. Best candidate would be a masterful hacker who went and did startups after finishing their Ph.D. We should find a way to make some positions that parallel fellows, and can leverage MIT/Harvard prestige]</p>
<p>If you're interested in this position, send an e-mail to <a href="">content-engineer@edxonline.org</a></p>
</div>
</article>
<article id="edx-fellow" class="job"> <article id="edx-fellow" class="job">
<div class="inner-wrapper"> <div class="inner-wrapper">
<h3>edX Fellow</h3> <h3>edX Fellow</h3>
...@@ -49,27 +57,20 @@ ...@@ -49,27 +57,20 @@
<p>If you're interested in this position, send an e-mail to <a href="">content-engineer@edxonline.org</a></p> <p>If you're interested in this position, send an e-mail to <a href="">content-engineer@edxonline.org</a></p>
</div> </div>
</article> </article>
<article id="technology-team" class="job">
<div class="inner-wrapper">
<h3>Technology Team</h3>
<p>[Looking for both back-end and front-end developers. Strong backgrounds in machine learning, education, user interaction design, big data, or social network analysis are desirable, but team members do wear many hats. Best candidate would be a masterful hacker who went and did startups after finishing their Ph.D. We should find a way to make some positions that parallel fellows, and can leverage MIT/Harvard prestige]</p>
<p>If you're interested in this position, send an e-mail to <a href="">content-engineer@edxonline.org</a></p>
</div>
</article>
</section> </section>
<section class="jobs-sidebar"> <section class="jobs-sidebar">
<h2>Positions</h2> <h2>Positions</h2>
<nav> <nav>
<a href="#technology-team">Technology Team</a>
<a href="#edx-fellow">edX Fellow</a> <a href="#edx-fellow">edX Fellow</a>
<a href="#content-engineer">Content Engineer</a> <a href="#content-engineer">Content Engineer</a>
<a href="#technology-team">Technology Team</a>
</nav> </nav>
<h2>How to Apply</h2> <h2>How to Apply</h2>
<p>E-mail your resume, coverletter and any other materials to <a href="#">careers@edxonline.org</a></p> <p>E-mail your resume, coverletter and any other materials to <a href="#">careers@edx.org</a></p>
<h2>Our Location</h2> <h2>Our Location</h2>
<p>11 Cambridge Center, Cambridge MA USA</p> <p>11 Cambridge Center <br/>
Cambridge, MA 02142</p>
</section> </section>
</section> </section>
......
...@@ -17,17 +17,17 @@ ...@@ -17,17 +17,17 @@
<ol class="user"> <ol class="user">
<li class="primary"> <li class="primary">
<a href="${reverse('dashboard')}" class="user-link"> <a href="${reverse('dashboard')}" class="user-link">
<span class="avatar"><img src="${static.url('images/profile.jpg')}" /></span> <span class="avatar"></span>
${user.username} ${user.username}
</a> </a>
</li> </li>
<li class="primary"> <li class="primary">
<a href="#" class="dropdown">&#9662</a> <a href="#" class="dropdown">&#9662</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#">Account Settings</a></li> <li><a href="#">Account Settings</a></li>
<li><a href="${reverse('help')}">Help</a></li> <li><a href="${reverse('help')}">Help</a></li>
<li><a href="${reverse('logout')}">Log Out</a></li> <li><a href="${reverse('logout')}">Log Out</a></li>
</ul> </ul>
</li> </li>
</ol> </ol>
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
<a href="/t/about.html">About</a> <a href="/t/about.html">About</a>
<a href="#">Blog</a> <a href="#">Blog</a>
<a href="${reverse('jobs')}">Jobs</a> <a href="${reverse('jobs')}">Jobs</a>
<a href="/t/contact.html">Contact</a>
<a href="#login-modal" id="login" rel="leanModal">Log In</a> <a href="#login-modal" id="login" rel="leanModal">Log In</a>
</li> </li>
<li class="primary"> <li class="primary">
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<div class="intro-inner-wrapper"> <div class="intro-inner-wrapper">
<section class="intro"> <section class="intro">
<hgroup> <hgroup>
<h1>${course.get_about_section("title")}</h1><h2><a href="#">${course.get_about_section("university")}</a></h2> <h1>${course.number}: ${course.get_about_section("title")}</h1><h2><a href="#">${course.get_about_section("university")}</a></h2>
</hgroup> </hgroup>
<div class="main-cta"> <div class="main-cta">
...@@ -47,6 +47,10 @@ ...@@ -47,6 +47,10 @@
<section class="course-staff"> <section class="course-staff">
<h2>Course staff</h3> <h2>Course staff</h3>
${course.get_about_section("instructors")}
<!--
<article class="teacher"> <article class="teacher">
<div class="teacher-image"> <div class="teacher-image">
<img src="${static.url('images/anant.jpg')}" /> <img src="${static.url('images/anant.jpg')}" />
...@@ -70,6 +74,7 @@ ...@@ -70,6 +74,7 @@
<h3>Piotr Mitros</h3> <h3>Piotr Mitros</h3>
<p>Research Scientist at MIT. His research focus is in finding ways to apply techniques from control systems to optimizing the learning process. Dr. Mitros has worked as an analog designer at Texas Instruments, Talking Lights, and most recently, designed the analog front end for a novel medical imaging modality for Rhythmia Medical.</p> <p>Research Scientist at MIT. His research focus is in finding ways to apply techniques from control systems to optimizing the learning process. Dr. Mitros has worked as an analog designer at Texas Instruments, Talking Lights, and most recently, designed the analog front end for a novel medical imaging modality for Rhythmia Medical.</p>
</article> </article>
-->
</section> </section>
<section class="requirements"> <section class="requirements">
...@@ -98,9 +103,6 @@ ...@@ -98,9 +103,6 @@
<section class="course-sidebar"> <section class="course-sidebar">
<section class="course-summary"> <section class="course-summary">
<header> <header>
<!--
-<a href="#" class="university-name">${course.get_about_section("university")}</a><span>${course.get_about_section("title")}</span>
-->
<div class="social-sharing"> <div class="social-sharing">
<div class="sharing-message">Share with friends and family!</div> <div class="sharing-message">Share with friends and family!</div>
<a href="#" class="share"> <a href="#" class="share">
...@@ -116,10 +118,10 @@ ...@@ -116,10 +118,10 @@
</header> </header>
<ol class="important-dates"> <ol class="important-dates">
<li><img src=""><p>Classes Start</p><span class="start-date">7/12/12</span></li> <li><div class="icon start-icon"></div><p>Classes Start</p><span class="start-date">7/12/12</span></li>
<li><img src=""><p>Final Exam</p><span class="final-date">12/09/12</span></li> <li><div class="icon final-icon"></div><p>Final Exam</p><span class="final-date">12/09/12</span></li>
<li><img src=""><p>Course Length</p><span class="course-length">15 weeks</span></li> <li><div class="icon length-icon"></div><p>Course Length</p><span class="course-length">15 weeks</span></li>
<li><img src=""><p>Course Number</p><span class="course-number">${course.get_about_section("number")}</span></li> <li><div class="icon number-icon"></div><p>Course Number</p><span class="course-number">${course.get_about_section("number")}</span></li>
</ol> </ol>
</section> </section>
</section> </section>
......
<h1>Check your email</h1> <header>
<p>An activation link has been sent to ${ email }, along with <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> instructions for activating your account.</p>
...@@ -2,12 +2,11 @@ ...@@ -2,12 +2,11 @@
<section id="signup-modal" class="modal signup-modal"> <section id="signup-modal" class="modal signup-modal">
<div class="inner-wrapper"> <div class="inner-wrapper">
<header>
<h2>Sign Up for edX</h2>
<hr>
</header>
<div id="enroll"> <div id="enroll">
<header>
<h2>Sign Up for edX</h2>
<hr>
</header>
<form id="enroll_form" method="post"> <form id="enroll_form" method="post">
<div id="enroll_error" name="enroll_error"></div> <div id="enroll_error" name="enroll_error"></div>
...@@ -32,26 +31,27 @@ ...@@ -32,26 +31,27 @@
<input name="honor_code" type="checkbox" value="true"> <input name="honor_code" type="checkbox" value="true">
I agree to the I agree to the
<a href="/t/honor.html" target="blank">Honor Code</a> <a href="/t/honor.html" target="blank">Honor Code</a>
, sumarized below as:
</label> </label>
<div class="honor-code-summary"> <!--
<ul> -<div class="honor-code-summary">
<li> - <ul>
<p>Complete all mid-terms and final exams with only my own work.</p> - <li>
</li> - <p>Complete all mid-terms and final exams with only my own work.</p>
<li> - </li>
<p>Maintain only one account, and not share the username or password.</p> - <li>
</li> - <p>Maintain only one account, and not share the username or password.</p>
<li> - </li>
<p>Not engage in any activity that would dishonestly improve my results, or improve or hurt those of others.</p> - <li>
</li> - <p>Not engage in any activity that would dishonestly improve my results, or improve or hurt those of others.</p>
<li> - </li>
<p>Not post answers to problems that are being used to assess student performance.</p> - <li>
</li> - <p>Not post answers to problems that are being used to assess student performance.</p>
</ul> - </li>
<hr> - </ul>
</div> - <hr>
-</div>
-->
<div class="submit"> <div class="submit">
<input name="submit" type="submit" value="Create My Account"> <input name="submit" type="submit" value="Create My Account">
......
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
<section class="university-profile"> <section class="university-profile">
<header class="search"> <header class="search" style="background: url('/static/images/shot-5-large.jpg')">
<div class="inner-wrapper university-search"> <div class="inner-wrapper university-search">
<hgroup> <hgroup>
<div class="logo"> <div class="logo">
<img src="${static.url('images/harvard.png')}" /> <img src="${static.url('images/mit.png')}" />
</div> </div>
<h1>HarvardX</h1> <h1>MITx</h1>
</hgroup> </hgroup>
</div> </div>
</header> </header>
......
...@@ -88,9 +88,8 @@ end ...@@ -88,9 +88,8 @@ end
# Per System tasks # Per System tasks
desc "Run all django tests on our djangoapps for the #{system}" desc "Run all django tests on our djangoapps for the #{system}"
task "test_#{system}" => [report_dir, :predjango, "#{system}:collectstatic:test"] do task "test_#{system}" => ["#{system}:collectstatic:test", "fasttest_#{system}"]
run_tests(system, report_dir)
end
# Have a way to run the tests without running collectstatic -- useful when debugging without # Have a way to run the tests without running collectstatic -- useful when debugging without
# messing with static files. # messing with static files.
task "fasttest_#{system}" => [report_dir, :predjango] do task "fasttest_#{system}" => [report_dir, :predjango] do
......
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