Commit bde93aea by Bridger Maxwell

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

Conflicts:
	lms/templates/footer.html
	lms/templates/signup_modal.html
parents 70e2f7c0 c3437342
......@@ -4,45 +4,165 @@ from django.test import TestCase
from mock import patch, Mock
from override_settings import override_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):
"""Parse response, which is assumed to be json"""
return json.loads(response.content)
class AuthTestCase(TestCase):
"""Check that various permissions-related things work"""
def test_index(self):
"""Make sure the main page loads."""
resp = self.client.get('/')
self.assertEqual(resp.status_code, 200)
def user(email):
'''look up a user by email'''
return User.objects.get(email=email)
def test_signup_load(self):
"""Make sure the signup page loads."""
resp = self.client.get('/signup')
self.assertEqual(resp.status_code, 200)
def registration(email):
'''look up registration object by email'''
return Registration.objects.get(user__email=email)
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
resp = self.client.post('/create_account', {})
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
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', {
'username': 'user',
'email': 'a@b.com',
'password': 'xyz',
'username': username,
'email': email,
'password': pw,
'location' : 'home',
'language' : 'Franglish',
'name' : 'Fred Weasley',
'terms_of_service' : '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)
data = parse_json(resp)
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
import json
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf
from django_future.csrf import ensure_csrf_cookie
from django.core.urlresolvers import reverse
......@@ -13,8 +14,28 @@ from github_sync import export_to_github
from mitxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore
# ==== Public views ==================================================
@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):
courses = modulestore().get_items(['i4x', None, None, 'course', None])
return render_to_response('index.html', {
......@@ -26,26 +47,34 @@ def index(request):
for course in courses]
})
# ==== Views with per-item permissions================================
@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 })
def has_access(user, location):
'''Return True if user allowed to access this piece of data'''
# TODO (vshnayder): actually check perms
return user.is_active and user.is_authenticated
@login_required
@ensure_csrf_cookie
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
course = modulestore().get_item(['i4x', org, course, 'course', name])
course = modulestore().get_item(location)
weeks = course.get_children()
return render_to_response('course_index.html', {'weeks': weeks})
@login_required
def edit_item(request):
item_id = request.GET['id']
item = modulestore().get_item(item_id)
# TODO (vshnayder): change name from id to location in coffee+html as well.
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', {
'contents': item.get_html(),
'js_module': item.js_module_name(),
......@@ -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
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'])
modulestore().update_item(item_id, data)
modulestore().update_item(item_location, data)
# Export the course back to github
# This uses wildcarding to find the course, which requires handling
# 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)
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({}))
......@@ -38,7 +38,12 @@ def import_from_github(repo_settings):
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)
fs = OSFS(repo_path)
xml = course.export_to_xml(fs)
......@@ -49,8 +54,11 @@ def export_to_github(course, commit_message):
git_repo = Repo(repo_path)
if git_repo.is_dirty():
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
if settings.MITX_FEATURES['GITHUB_PUSH']:
push_infos = origin.push()
......
......@@ -49,4 +49,4 @@ def github_post_receive(request):
revision, course = import_from_github(repo)
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 = (
MITX_ROOT_URL = ''
LOGIN_REDIRECT_URL = MITX_ROOT_URL + '/login'
LOGIN_URL = MITX_ROOT_URL + '/login'
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
'django.core.context_processors.static',
......
......@@ -29,39 +29,37 @@ DATABASES = {
}
}
REPO_ROOT = ENV_ROOT / "content"
REPOS = {
'edx4edx': {
'path': REPO_ROOT / "edx4edx",
'path': DATA_DIR / "edx4edx",
'org': 'edx',
'course': 'edx4edx',
'branch': 'for_cms',
'origin': 'git@github.com:MITx/edx4edx.git',
},
'6002x-fall-2012': {
'path': REPO_ROOT / '6002x-fall-2012',
'path': DATA_DIR / '6002x-fall-2012',
'org': 'mit.edu',
'course': '6.002x',
'branch': 'for_cms',
'origin': 'git@github.com:MITx/6002x-fall-2012.git',
},
'6.00x': {
'path': REPO_ROOT / '6.00x',
'path': DATA_DIR / '6.00x',
'org': 'mit.edu',
'course': '6.00x',
'branch': 'for_cms',
'origin': 'git@github.com:MITx/6.00x.git',
},
'7.00x': {
'path': REPO_ROOT / '7.00x',
'path': DATA_DIR / '7.00x',
'org': 'mit.edu',
'course': '7.00x',
'branch': 'for_cms',
'origin': 'git@github.com:MITx/7.00x.git',
},
'3.091x': {
'path': REPO_ROOT / '3.091x',
'path': DATA_DIR / '3.091x',
'org': 'mit.edu',
'course': '3.091x',
'branch': 'for_cms',
......
<%inherit file="marketing.html" />
<%inherit file="base.html" />
<%block name="content">
......@@ -7,8 +7,7 @@
<section class="activation">
<h1>Account already active!</h1>
<p> This account has already been activated. You can log in at
the <a href="/">home page</a>.</p>
<p> This account has already been activated. <a href="/login">Log in here</a>.</p>
</div>
</section>
......
<%inherit file="marketing.html" />
<%inherit file="base.html" />
<%block name="content">
<section class="tos">
<div>
<h1>Activation Complete!</h1>
<p>Thanks for activating your account. You can log in at the <a href="/">home page</a>.</p>
<p>Thanks for activating your account. <a href="/login">Log in here</a>.</p>
</div>
</section>
......
<%inherit file="marketing.html" />
<%inherit file="base.html" />
<%block name="content">
<section class="tos">
......
<form name="login" action="login", method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
<%inherit file="base.html" />
<%! from django.core.urlresolvers import reverse %>
<%block name="title">Log in</%block>
% if next is not None:
<input type="hidden" name="next" value="${next}"/>
% endif
<%block name="content">
Username: <input type="text" name="username" />
Possword: <input type="password" name="password" />
<input type="submit" value="Submit" />
</form>
<section class="main-container">
<section class="main-content">
<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>
<nav>
<h2><a href="/">6.002x circuits and electronics</a></h2>
<h2><a href="/">edX CMS: TODO:-course-name-here</a></h2>
<ul>
<li>
<a href="#" class="new-module wip">New Module</a>
......@@ -13,6 +14,12 @@
<ul class="user-nav">
<li><a href="#" class="wip">Tasks</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>
</nav>
</header>
......@@ -11,16 +11,25 @@ urlpatterns = ('',
url(r'^$', 'contentstore.views.index', name='index'),
url(r'^edit_item$', 'contentstore.views.edit_item', name='edit_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'),
)
# User creation and updating views
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'^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:
......
......@@ -146,12 +146,12 @@ def create_account(request, post_override=None):
js['value'] = "Error (401 {field}). E-mail us.".format(field=a)
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)
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)
return HttpResponse(json.dumps(js))
......
......@@ -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.
- _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.
......
......@@ -95,7 +95,7 @@ for static_dir in STATICFILES_DIRS:
except ValueError:
data_dir = static_dir
if not data_dir.startswith(REPO_ROOT):
if data_dir.startswith(REPO_ROOT):
new_staticfiles_dirs.append(static_dir)
STATICFILES_DIRS = new_staticfiles_dirs
......
......@@ -51,6 +51,7 @@
}
.photo {
@include box-sizing(border-box);
background: rgb(255,255,255);
border: 1px solid rgb(210,210,210);
padding: 1px;
......@@ -64,6 +65,11 @@
}
}
> article {
float: left;
width: flex-grid(8);
}
&.left {
.photo {
float: left;
......
......@@ -40,15 +40,15 @@
.title {
@include inline-block;
margin-right: 50px;
padding-right: 50px;
//margin-right: 50px;
//padding-right: 50px;
position: relative;
text-align: left;
vertical-align: middle;
&::before {
@extend .faded-vertical-divider;
content: "";
//content: "";
display: block;
height: 170px;
position: absolute;
......@@ -99,66 +99,138 @@
}
}
.social-sharing {
.secondary-actions {
@include box-sizing(border-box);
@include clearfix;
float: left;
height: 44px;
position: relative;
text-align: center;
height: 47px;
width: flex-grid(6);
&:hover {
.sharing-message {
opacity: 1;
top: 56px;
}
}
.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));
a.intro-video {
background: rgb(245,245,245);
@include background-image(linear-gradient(-90deg, rgb(250,250,250), rgb(235,235,235)));
border: 1px solid rgb(200,200,200);
@include border-radius(30px);
@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;
@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));
@include clearfix;
display: block;
float: left;
height: 100%;
overflow: hidden;
text-align: middle;
width: flex-grid(6);
&: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 {
background: rgba(255,255,255, 0.6);
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;
@include inline-block;
margin-right: 10px;
opacity: 0.5;
@include transition(all, 0.15s, linear);
width: 44px;
margin-right: flex-gutter();
position: relative;
text-align: center;
width: flex-grid(6);
&:hover {
opacity: 1;
.sharing-message {
opacity: 1;
top: 56px;
}
}
img {
width: 100%;
.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: 65px;
width: 220px;
&:hover {
opacity: 0;
}
}
&:last-child {
margin-right: 0px;
.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;
}
}
}
}
......@@ -168,15 +240,18 @@
background: #fff;
border: 1px solid rgb(200,200,200);
@include box-sizing(border-box);
float: left;
@include inline-block;
padding: 1px;
position: relative;
vertical-align: middle;
width: 210px;
//width: 210px;
width: flex-grid(3);
z-index: 2;
.hero {
height: 125px;
//height: 125px;
height: 100%;
overflow: hidden;
position: relative;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -17,10 +17,10 @@ $yellow: rgb(255, 252, 221);
html, body {
background: rgb(250,250,250);
//background: rgb(77, 82, 99);
font-family: $sans-serif;
font-size: 1em;
line-height: 1em;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
......
......@@ -42,5 +42,6 @@ form {
letter-spacing: 1px;
text-transform: uppercase;
vertical-align: top;
-webkit-font-smoothing: antialiased;
}
}
......@@ -115,15 +115,9 @@
padding: 12px;
}
//#enroll {
//padding: 0 40px;
//h1 {
//font: normal 1em/1.6em $sans-serif;
//margin-bottom: 10px;
//text-align: left;
//}
//}
.activation-message {
padding: 0 40px 10px;
}
form {
margin-bottom: 12px;
......
......@@ -16,7 +16,7 @@
<section class="container">
## 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">
%for course in courses:
<%include file="course.html" args="course=course" />
......
......@@ -10,6 +10,7 @@
<a href="${reverse('about_edx')}">About</a>
<a href="#">Blog</a>
<a href="${reverse('jobs')}">Jobs</a>
<a href="${reverse('contact')}">Contact</a>
</section>
<section class="social">
......
......@@ -7,31 +7,37 @@
<div class="outer-wrapper">
<div class="inner-wrapper">
<div class="title">
<h1>The Future of Online Education</h1>
<h1>Online education for anyone, anywhere, at anytime</h1>
<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 class="social-sharing">
<div class="sharing-message">Share with friends and family!</div>
<a href="#" class="share">
<img src="${static.url('images/twitter-sharing.png')}">
</a>
<a href="#" class="share">
<img src="${static.url('images/facebook-sharing.png')}">
</a>
<a href="#" class="share">
<img src="${static.url('images/email-sharing.png')}">
<div class="secondary-actions">
<div class="social-sharing">
<div class="sharing-message">Share with friends and family!</div>
<a href="#" class="share">
<img src="${static.url('images/twitter-sharing.png')}">
</a>
<a href="#" class="share">
<img src="${static.url('images/facebook-sharing.png')}">
</a>
<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>
</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>
</header>
......@@ -87,10 +93,10 @@
<section class="blog-posts">
<article>
<a href="#" class="post-graphics">
<img src="${static.url('images/courses/space1.jpg')}" />
<img src="${static.url('images/mongolia_post.jpeg')}" />
</a>
<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>
</div>
</article>
......
......@@ -37,6 +37,7 @@
<a href="${reverse('about_edx')}">About</a>
<a href="#">Blog</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>
</li>
<li class="primary">
......
<h1>Check your email</h1>
<p>An activation link has been sent to ${ email }, along with
<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>
......@@ -3,12 +3,11 @@
<section id="signup-modal" class="modal signup-modal">
<div class="inner-wrapper">
<header>
<h2>Sign Up for edX</h2>
<hr>
</header>
<div id="enroll">
<header>
<h2>Sign Up for edX</h2>
<hr>
</header>
<form id="enroll_form" method="post">
<div id="enroll_error" name="enroll_error"></div>
......@@ -33,26 +32,27 @@
<input name="honor_code" type="checkbox" value="true">
I agree to the
<a href="${reverse('honor')}" target="blank">Honor Code</a>
, sumarized below as:
</label>
<div class="honor-code-summary">
<ul>
<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>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>
</ul>
<hr>
</div>
<!--
-<div class="honor-code-summary">
- <ul>
- <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>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>
- </ul>
- <hr>
-</div>
-->
<div class="submit">
<input name="submit" type="submit" value="Create My Account">
......
......@@ -13,14 +13,16 @@
<section class="vision">
<section class="company-mission message left">
<div class="inner-wrapper">
<div class="photo">
<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 class="photo">
<img src="">
</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">
</section>
......@@ -28,9 +30,11 @@
<div class="photo">
<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.”
<article>
<h2>Harvard University</h2>
<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">
</section>
......@@ -38,9 +42,12 @@
<div class="photo">
<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.”
<article>
<h2>Massachusetts Institute of Technology</h2>
<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>
......
......@@ -22,6 +22,14 @@
<h2>We are currently looking for</h2>
<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">
<div class="inner-wrapper">
<h3>edX Fellow</h3>
......@@ -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>
</div>
</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 class="jobs-sidebar">
<h2>Positions</h2>
<nav>
<a href="#technology-team">Technology Team</a>
<a href="#edx-fellow">edX Fellow</a>
<a href="#content-engineer">Content Engineer</a>
<a href="#technology-team">Technology Team</a>
</nav>
<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>
<p>11 Cambridge Center, Cambridge MA USA</p>
<p>11 Cambridge Center <br/>
Cambridge, MA 02142</p>
</section>
</section>
......
......@@ -88,9 +88,8 @@ end
# Per System tasks
desc "Run all django tests on our djangoapps for the #{system}"
task "test_#{system}" => [report_dir, :predjango, "#{system}:collectstatic:test"] do
run_tests(system, report_dir)
end
task "test_#{system}" => ["#{system}:collectstatic:test", "fasttest_#{system}"]
# Have a way to run the tests without running collectstatic -- useful when debugging without
# messing with static files.
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