Commit d5ba5457 by Vik Paruchuri

Merge remote-tracking branch 'origin/master' into feature/vik/check-if-submission-allowed

Conflicts:
	common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py
parents c3d485a6 fbce67a8
......@@ -208,4 +208,4 @@ class CombinedOpenEndedDescriptor(XmlDescriptor, EditingDescriptor):
for child in ['task']:
add_child(child)
return elt
\ No newline at end of file
return elt
......@@ -2,8 +2,7 @@ import json
import logging
from lxml import etree
from lxml.html import rewrite_links
from xmodule.timeinfo import TimeInfo
from xmodule.capa_module import only_one, ComplexEncoder
from xmodule.editing_module import EditingDescriptor
from xmodule.html_checker import check_html
......@@ -14,9 +13,6 @@ from xmodule.xml_module import XmlDescriptor
import self_assessment_module
import open_ended_module
from combined_open_ended_rubric import CombinedOpenEndedRubric, GRADER_TYPE_IMAGE_DICT, HUMAN_GRADER_TYPE, LEGEND_LIST
import dateutil
import dateutil.parser
from xmodule.timeparse import parse_timedelta
log = logging.getLogger("mitx.courseware")
......@@ -153,28 +149,14 @@ class CombinedOpenEndedV1Module():
self.skip_basic_checks = self.metadata.get('skip_spelling_checks', SKIP_BASIC_CHECKS)
display_due_date_string = self.metadata.get('due', None)
if display_due_date_string is not None:
try:
self.display_due_date = dateutil.parser.parse(display_due_date_string)
except ValueError:
#This is a staff_facing_error
log.error("Could not parse due date {0} for location {1}. Contact the learning sciences group for assistance.".format(display_due_date_string, location))
raise
else:
self.display_due_date = None
grace_period_string = self.metadata.get('graceperiod', None)
if grace_period_string is not None and self.display_due_date:
try:
self.grace_period = parse_timedelta(grace_period_string)
self.close_date = self.display_due_date + self.grace_period
except:
#This is a staff_facing_error
log.error("Error parsing the grace period {0} for location {1}. Contact the learning sciences group for assistance.".format(grace_period_string, location))
raise
else:
self.grace_period = None
self.close_date = self.display_due_date
try:
self.timeinfo = TimeInfo(display_due_date_string, grace_period_string)
except:
log.error("Error parsing due date information in location {0}".format(location))
raise
self.display_due_date = self.timeinfo.display_due_date
# Used for progress / grading. Currently get credit just for
# completion (doesn't matter if you self-assessed correct/incorrect).
......@@ -192,7 +174,7 @@ class CombinedOpenEndedV1Module():
'rubric': definition['rubric'],
'display_name': self.display_name,
'accept_file_upload': self.accept_file_upload,
'close_date' : self.close_date,
'close_date' : self.timeinfo.close_date,
's3_interface' : self.system.s3_interface,
'skip_basic_checks' : self.skip_basic_checks,
}
......
......@@ -106,7 +106,7 @@ class MockPeerGradingService(object):
'max_score': 4})
def save_grade(self, location, grader_id, submission_id,
score, feedback, submission_key):
score, feedback, submission_key, rubric_scores, submission_flagged):
return json.dumps({'success': True})
def is_student_calibrated(self, problem_location, grader_id):
......@@ -122,7 +122,8 @@ class MockPeerGradingService(object):
'max_score': 4})
def save_calibration_essay(self, problem_location, grader_id,
calibration_essay_id, submission_key, score, feedback):
calibration_essay_id, submission_key, score,
feedback, rubric_scores):
return {'success': True, 'actual_score': 2}
def get_problem_list(self, course_id, grader_id):
......
......@@ -3,6 +3,7 @@ import logging
from lxml import etree
from datetime import datetime
from pkg_resources import resource_string
from .capa_module import ComplexEncoder
from .editing_module import EditingDescriptor
......@@ -10,6 +11,8 @@ from .stringify import stringify_children
from .x_module import XModule
from .xml_module import XmlDescriptor
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
from timeinfo import TimeInfo
from xmodule.open_ended_grading_classes.peer_grading_service import PeerGradingService, GradingServiceError
......@@ -52,6 +55,7 @@ class PeerGradingModule(XModule):
self.system = system
self.peer_gs = PeerGradingService(self.system.open_ended_grading_interface, self.system)
self.use_for_single_location = self.metadata.get('use_for_single_location', USE_FOR_SINGLE_LOCATION)
if isinstance(self.use_for_single_location, basestring):
self.use_for_single_location = (self.use_for_single_location in TRUE_DICT)
......@@ -60,10 +64,28 @@ class PeerGradingModule(XModule):
if isinstance(self.is_graded, basestring):
self.is_graded = (self.is_graded in TRUE_DICT)
display_due_date_string = self.metadata.get('due', None)
grace_period_string = self.metadata.get('graceperiod', None)
try:
self.timeinfo = TimeInfo(display_due_date_string, grace_period_string)
except:
log.error("Error parsing due date information in location {0}".format(location))
raise
self.display_due_date = self.timeinfo.display_due_date
self.link_to_location = self.metadata.get('link_to_location', USE_FOR_SINGLE_LOCATION)
if self.use_for_single_location == True:
#This will raise an exception if the location is invalid
link_to_location_object = Location(self.link_to_location)
try:
self.linked_problem = modulestore().get_instance(self.system.course_id, self.link_to_location)
except:
log.error("Linked location {0} for peer grading module {1} does not exist".format(
self.link_to_location, self.location))
raise
due_date = self.linked_problem.metadata.get('peer_grading_due', None)
if due_date:
self.metadata['due'] = due_date
self.ajax_url = self.system.ajax_url
if not self.ajax_url.endswith("/"):
......@@ -75,6 +97,15 @@ class PeerGradingModule(XModule):
#This could result in an exception, but not wrapping in a try catch block so it moves up the stack
self.max_grade = int(self.max_grade)
def closed(self):
return self._closed(self.timeinfo)
def _closed(self, timeinfo):
if timeinfo.close_date is not None and datetime.utcnow() > timeinfo.close_date:
return True
return False
def _err_response(self, msg):
"""
Return a HttpResponse with a json dump with success=False, and the given error message.
......@@ -94,6 +125,8 @@ class PeerGradingModule(XModule):
Needs to be implemented by inheritors. Renders the HTML that students see.
@return:
"""
if self.closed():
return self.peer_grading_closed()
if not self.use_for_single_location:
return self.peer_grading()
else:
......@@ -397,6 +430,16 @@ class PeerGradingModule(XModule):
#This is a student_facing_error
return self._err_response('There was an error saving your score. Please notify course staff.')
def peer_grading_closed(self):
'''
Show the Peer grading closed template
'''
html = self.system.render_template('peer_grading/peer_grading_closed.html', {
'use_for_single_location': self.use_for_single_location
})
return html
def peer_grading(self, get=None):
'''
Show a peer grading interface
......@@ -425,6 +468,40 @@ class PeerGradingModule(XModule):
error_text = "Could not get list of problems to peer grade. Please notify course staff."
success = False
def _find_corresponding_module_for_location(location):
'''
find the peer grading module that links to the given location
'''
try:
return modulestore().get_instance(self.system.course_id, location)
except:
# the linked problem doesn't exist
log.error("Problem {0} does not exist in this course".format(location))
raise
for problem in problem_list:
problem_location = problem['location']
descriptor = _find_corresponding_module_for_location(problem_location)
if descriptor:
problem['due'] = descriptor.metadata.get('peer_grading_due', None)
grace_period_string = descriptor.metadata.get('graceperiod', None)
try:
problem_timeinfo = TimeInfo(problem['due'], grace_period_string)
except:
log.error("Malformed due date or grace period string for location {0}".format(problem_location))
raise
if self._closed(problem_timeinfo):
problem['closed'] = True
else:
problem['closed'] = False
else:
# if we can't find the due date, assume that it doesn't have one
problem['due'] = None
problem['closed'] = False
ajax_url = self.ajax_url
html = self.system.render_template('peer_grading/peer_grading.html', {
'course_id': self.system.course_id,
......
import json
from mock import Mock
from mock import Mock, MagicMock
import unittest
from xmodule.open_ended_grading_classes.self_assessment_module import SelfAssessmentModule
from xmodule.modulestore import Location
from lxml import etree
from nose.plugins.skip import SkipTest
from . import test_system
......@@ -64,13 +63,21 @@ class SelfAssessmentTest(unittest.TestCase):
self.assertTrue("This is sample prompt text" in html)
def test_self_assessment_flow(self):
raise SkipTest()
responses = {'assessment': '0', 'score_list[]': ['0', '0']}
def get_fake_item(name):
return responses[name]
mock_query_dict = MagicMock()
mock_query_dict.__getitem__.side_effect = get_fake_item
mock_query_dict.getlist = get_fake_item
self.assertEqual(self.module.get_score()['score'], 0)
self.module.save_answer({'student_answer': "I am an answer"}, test_system)
self.assertEqual(self.module.state, self.module.ASSESSING)
self.module.save_assessment({'assessment': '0'}, test_system)
self.module.save_assessment(mock_query_dict, test_system)
self.assertEqual(self.module.state, self.module.DONE)
......@@ -80,5 +87,6 @@ class SelfAssessmentTest(unittest.TestCase):
# if we now assess as right, skip the REQUEST_HINT state
self.module.save_answer({'student_answer': 'answer 4'}, test_system)
self.module.save_assessment({'assessment': '1'}, test_system)
responses['assessment'] = '1'
self.module.save_assessment(mock_query_dict, test_system)
self.assertEqual(self.module.state, self.module.DONE)
import dateutil
import dateutil.parser
import datetime
from timeparse import parse_timedelta
import logging
log = logging.getLogger(__name__)
class TimeInfo(object):
"""
This is a simple object that calculates and stores datetime information for an XModule
based on the due date string and the grace period string
So far it parses out three different pieces of time information:
self.display_due_date - the 'official' due date that gets displayed to students
self.grace_period - the length of the grace period
self.close_date - the real due date
"""
def __init__(self, display_due_date_string, grace_period_string):
if display_due_date_string is not None:
try:
self.display_due_date = dateutil.parser.parse(display_due_date_string)
except ValueError:
log.error("Could not parse due date {0}".format(display_due_date_string))
raise
else:
self.display_due_date = None
if grace_period_string is not None and self.display_due_date:
try:
self.grace_period = parse_timedelta(grace_period_string)
self.close_date = self.display_due_date + self.grace_period
except:
log.error("Error parsing the grace period {0}".format(grace_period_string))
raise
else:
self.grace_period = None
self.close_date = self.display_due_date
......@@ -16,7 +16,7 @@ import courseware.tests.tests as ct
from xmodule.modulestore.django import modulestore
import xmodule.modulestore.django
from nose import SkipTest
from mock import patch, Mock
from mock import patch, Mock, MagicMock
import json
from xmodule.x_module import ModuleSystem
from mitxmako.shortcuts import render_to_string
......@@ -169,23 +169,35 @@ class TestPeerGradingService(ct.PageLoader):
def test_get_next_submission_missing_location(self):
data = {}
r = self.peer_module.get_next_submission(data)
d = r
d = self.peer_module.get_next_submission(data)
self.assertFalse(d['success'])
self.assertEqual(d['error'], "Missing required keys: location")
def test_save_grade_success(self):
raise SkipTest()
data = 'rubric_scores[]=1|rubric_scores[]=2|location=' + self.location + '|submission_id=1|submission_key=fake key|score=2|feedback=feedback|submission_flagged=False'
qdict = QueryDict(data.replace("|", "&"))
data = {
'rubric_scores[]': [0, 0],
'location': self.location,
'submission_id': 1,
'submission_key': 'fake key',
'score': 2,
'feedback': 'feedback',
'submission_flagged': 'false'
}
qdict = MagicMock()
def fake_get_item(key):
return data[key]
qdict.__getitem__.side_effect = fake_get_item
qdict.getlist = fake_get_item
qdict.keys = data.keys
r = self.peer_module.save_grade(qdict)
d = r
d = json.loads(r)
self.assertTrue(d['success'])
def test_save_grade_missing_keys(self):
data = {}
r = self.peer_module.save_grade(data)
d = r
d = self.peer_module.save_grade(data)
self.assertFalse(d['success'])
self.assertTrue(d['error'].find('Missing required keys:') > -1)
......@@ -198,8 +210,7 @@ class TestPeerGradingService(ct.PageLoader):
def test_is_calibrated_failure(self):
data = {}
r = self.peer_module.is_student_calibrated(data)
d = r
d = self.peer_module.is_student_calibrated(data)
self.assertFalse(d['success'])
self.assertFalse('calibrated' in d)
......@@ -219,25 +230,36 @@ class TestPeerGradingService(ct.PageLoader):
def test_show_calibration_essay_missing_key(self):
data = {}
r = self.peer_module.show_calibration_essay(data)
d = r
d = self.peer_module.show_calibration_essay(data)
self.assertFalse(d['success'])
self.assertEqual(d['error'], "Missing required keys: location")
def test_save_calibration_essay_success(self):
raise SkipTest()
data = 'rubric_scores[]=1|rubric_scores[]=2|location=' + self.location + '|submission_id=1|submission_key=fake key|score=2|feedback=feedback|submission_flagged=False'
qdict = QueryDict(data.replace("|", "&"))
r = self.peer_module.save_calibration_essay(qdict)
d = r
data = {
'rubric_scores[]': [0, 0],
'location': self.location,
'submission_id': 1,
'submission_key': 'fake key',
'score': 2,
'feedback': 'feedback',
'submission_flagged': 'false'
}
qdict = MagicMock()
def fake_get_item(key):
return data[key]
qdict.__getitem__.side_effect = fake_get_item
qdict.getlist = fake_get_item
qdict.keys = data.keys
d = self.peer_module.save_calibration_essay(qdict)
self.assertTrue(d['success'])
self.assertTrue('actual_score' in d)
def test_save_calibration_essay_missing_keys(self):
data = {}
r = self.peer_module.save_calibration_essay(data)
d = r
d = self.peer_module.save_calibration_essay(data)
self.assertFalse(d['success'])
self.assertTrue(d['error'].find('Missing required keys:') > -1)
self.assertFalse('actual_score' in d)
.home {
padding: 0px;
> .container {
@include box-sizing(border-box);
width: flex-grid(12);
}
> header {
background: rgb(255,255,255);
@include background-image(url('/static/images/homepage-bg.jpg'));
......@@ -175,9 +180,6 @@
}
.university-partners {
@include background-image(linear-gradient(180deg, rgba(245,245,245, 0) 0%,
rgba(245,245,245, 1) 50%,
rgba(245,245,245, 0) 100%));
border-bottom: 1px solid rgb(210,210,210);
margin-bottom: 0px;
overflow: hidden;
......@@ -300,7 +302,6 @@
}
img {
max-width: 190px;
position: relative;
@include transition(all, 0.25s, ease-in-out);
vertical-align: middle;
......@@ -324,6 +325,44 @@
}
}
}
&.university-partners2x6 {
@include box-sizing(border-box);
width: flex-grid(12, 12);
.partners {
@include box-sizing(border-box);
@include clearfix();
margin-left: 60px;
padding: 12px 0;
.partner {
@include box-sizing(border-box);
width: flex-grid(2, 12);
display: block;
float: left;
padding: 0 12px;
a {
img {
width: 100%;
height: auto;
}
.name > span {
font-size: 1.0em;
}
&:hover {
.name {
bottom: 14px;
}
}
}
}
}
}
}
.more-info {
......
......@@ -47,8 +47,8 @@
<section class="highlighted-courses">
<h2>Explore free courses from <span class="edx">edX</span> universities</h2>
<section class="university-partners">
<ol class="partners partners-primary">
<section class="university-partners university-partners2x6">
<ol class="partners">
<li class="partner mit">
<a href="${reverse('university_profile', args=['MITx'])}">
<img src="${static.url('images/university/mit/mit.png')}" />
......@@ -65,7 +65,7 @@
</div>
</a>
</li>
<li class="partner last">
<li class="partner">
<a href="${reverse('university_profile', args=['BerkeleyX'])}">
<img src="${static.url('images/university/berkeley/berkeley.png')}" />
<div class="name">
......@@ -73,11 +73,6 @@
</div>
</a>
</li>
</ol>
<hr />
<ol class="partners">
<li class="partner">
<a href="${reverse('university_profile', args=['UTx'])}">
<img src="${static.url('images/university/ut/ut-rollover_350x150.png')}" />
......@@ -87,6 +82,27 @@
</a>
</li>
<li class="partner">
<a href="${reverse('university_profile', args=['McGillX'])}">
<img src="${static.url('images/university/mcgill/mcgill.png')}" />
<div class="name">
<span>McGillX</span>
</div>
</a>
</li>
<li class="partner">
<a href="${reverse('university_profile', args=['ANUx'])}">
<img src="${static.url('images/university/anu/anu.png')}" />
<div class="name">
<span>ANUx</span>
</div>
</a>
</li>
</ol>
<hr />
<ol class="partners">
<li class="partner">
<a href="${reverse('university_profile', args=['WellesleyX'])}">
<img src="${static.url('images/university/wellesley/wellesley-rollover_350x150.png')}" />
<div class="name">
......@@ -94,7 +110,7 @@
</div>
</a>
</li>
<li class="partner last">
<li class="partner">
<a href="${reverse('university_profile', args=['GeorgetownX'])}">
<img src="${static.url('images/university/georgetown/georgetown-rollover_350x150.png')}" />
<div class="name">
......@@ -102,6 +118,38 @@
</div>
</a>
</li>
<li class="partner">
<a href="${reverse('university_profile', args=['TorontoX'])}">
<img src="${static.url('images/university/toronto/toronto.png')}" />
<div class="name">
<span>TorontoX</span>
</div>
</a>
</li>
<li class="partner">
<a href="${reverse('university_profile', args=['EPFLx'])}">
<img src="${static.url('images/university/epfl/epfl.png')}" />
<div class="name">
<span>EPFLx</span>
</div>
</a>
</li>
<li class="partner">
<a href="${reverse('university_profile', args=['DelftX'])}">
<img src="${static.url('images/university/delft/delft.png')}" />
<div class="name">
<span>DelftX</span>
</div>
</a>
</li>
<li class="partner">
<a href="${reverse('university_profile', args=['RiceX'])}">
<img src="${static.url('images/university/rice/rice.png')}" />
<div class="name">
<span>RiceX</span>
</div>
</a>
</li>
</ol>
</section>
......
......@@ -14,6 +14,7 @@
<table class="problem-list">
<tr>
<th>Problem Name</th>
<th>Due date</th>
<th>Graded</th>
<th>Available</th>
<th>Required</th>
......@@ -22,7 +23,18 @@
%for problem in problem_list:
<tr data-graded="${problem['num_graded']}" data-required="${problem['num_required']}">
<td class="problem-name">
<a href="#problem" data-location="${problem['location']}" class="problem-button">${problem['problem_name']}</a>
%if problem['closed']:
${problem['problem_name']}
%else:
<a href="#problem" data-location="${problem['location']}" class="problem-button">${problem['problem_name']}</a>
%endif
</td>
<td>
% if problem['due']:
${problem['due']}
% else:
No due date
% endif
</td>
<td>
${problem['num_graded']}
......
<section class="container peer-grading-container">
<h2>Peer Grading</h2>
<p>The due date has passed, and
% if use_for_single_location:
peer grading for this problem is closed at this time.
%else:
peer grading is closed at this time.
%endif
</p>
</section>
<%inherit file="base.html" />
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>ANUx</title></%block>
<%block name="university_header">
<header class="search" style="background: url('/static/images/university/anu/anu-cover.jpg')">
<div class="inner-wrapper university-search">
<hgroup>
<div class="logo">
<img src="${static.url('images/university/anu/anu.png')}" />
</div>
<h1>ANUx</h1>
</hgroup>
</div>
</header>
</%block>
<%block name="university_description">
<p>The Australian National University (ANU) is a celebrated place of intensive research, education and policy engagement. Our research has always been central to everything we do, shaping a holistic learning experience that goes beyond the classroom, giving students access to researchers who are among the best in their fields and to opportunities for development around Australia and the world.</p>
</%block>
${parent.body()}
<%inherit file="base.html" />
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>DelftX</title></%block>
<%block name="university_header">
<header class="search" style="background: url('/static/images/university/delft/delft-cover.jpg')">
<div class="inner-wrapper university-search">
<hgroup>
<div class="logo">
<img src="${static.url('images/university/delft/delft.png')}" />
</div>
<h1>DelftX</h1>
</hgroup>
</div>
</header>
</%block>
<%block name="university_description">
<p>Delft University of Technology is the largest and oldest technological university in the Netherlands. Our research is inspired by the desire to increase fundamental understanding, as well as by societal challenges. We encourage our students to be independent thinkers so they will become engineers capable of solving complex problems. Our students have chosen Delft University of Technology because of our reputation for quality education and research.</p>
</%block>
${parent.body()}
<%inherit file="base.html" />
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>EPFLx</title></%block>
<%block name="university_header">
<header class="search" style="background: url('/static/images/university/epfl/epfl-cover.jpg')">
<div class="inner-wrapper university-search">
<hgroup>
<div class="logo">
<img src="${static.url('images/university/epfl/epfl.png')}" />
</div>
<h1>EPFLx</h1>
</hgroup>
</div>
</header>
</%block>
<%block name="university_description">
<p>EPFL is one of the two Swiss Federal Institutes of Technology. With the status of a national school since 1969, the young engineering school has grown in many dimensions, to the extent of becoming one of the most famous European institutions of science and technology. It has three core missions: training, research and technology transfer. </p>
<p>EPFL is located in Lausanne in Switzerland, on the shores of the largest lake in Europe, Lake Geneva and at the foot of the Alps and Mont-Blanc. Its main campus brings together over 11,000 persons, students, researchers and staff in the same magical place. Because of its dynamism and rich student community, EPFL has been able to create a special spirit imbued with curiosity and simplicity. Daily interactions amongst students, researchers and entrepreneurs on campus give rise to new scientific, technological and architectural projects.
</p>
</%block>
${parent.body()}
<%inherit file="base.html" />
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>McGillX</title></%block>
<%block name="university_header">
<header class="search" style="background: url('/static/images/university/mcgill/mcgill-cover.jpg')">
<div class="inner-wrapper university-search">
<hgroup>
<div class="logo">
<img src="${static.url('images/university/mcgill/mcgill.png')}" />
</div>
<h1>McGillX</h1>
</hgroup>
</div>
</header>
</%block>
<%block name="university_description">
<p>McGill University is one of Canada's best-known institutions of higher learning and one of the leading universities in the world. McGill is located in vibrant multicultural Montreal, in the province of Quebec. Our 11 faculties and 11 professional schools offer more than 300 programs to some 38,000 graduate, undergraduate and continuing studies students. McGill ranks 1st in Canada among medical-doctoral universities (Maclean’s) and 18th in the world (QS World University Rankings).</p>
</%block>
${parent.body()}
<%inherit file="base.html" />
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>RiceX</title></%block>
<%block name="university_header">
<header class="search" style="background: url('/static/images/university/rice/rice-cover.jpg')">
<div class="inner-wrapper university-search">
<hgroup>
<div class="logo">
<img src="${static.url('images/university/rice/rice.png')}" />
</div>
<h1>RiceX</h1>
</hgroup>
</div>
</header>
</%block>
<%block name="university_description">
<p>Located on a 300-acre forested campus in Houston, Rice University is consistently ranked among the nation's top 20 universities by U.S. News & World Report. Rice has highly respected schools of Architecture, Business, Continuing Studies, Engineering, Humanities, Music, Natural Sciences and Social Sciences and is home to the Baker Institute for Public Policy. With 3,708 undergraduates and 2,374 graduate students, Rice's undergraduate student-to-faculty ratio is 6-to-1. Its residential college system builds close-knit communities and lifelong friendships, just one reason why Rice has been ranked No. 1 for best quality of life multiple times by the Princeton Review and No. 2 for "best value" among private universities by Kiplinger's Personal Finance.</p>
</%block>
${parent.body()}
<%inherit file="base.html" />
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>SCHOOLX</title></%block>
<%block name="university_header">
<header class="search" style="background: url('/static/images/university/SCHOOL/IMAGE.jpg')">
<div class="inner-wrapper university-search">
<hgroup>
<div class="logo">
<img src="${static.url('images/university/SCHOOL/IMAGE.png')}" />
</div>
<h1>SCHOOLX</h1>
</hgroup>
</div>
</header>
</%block>
<%block name="university_description">
<p></p>
</%block>
${parent.body()}
<%inherit file="base.html" />
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>TorontoX</title></%block>
<%block name="university_header">
<header class="search" style="background: url('/static/images/university/toronto/toronto-cover.jpg')">
<div class="inner-wrapper university-search">
<hgroup>
<div class="logo">
<img src="${static.url('images/university/toronto/toronto.png')}" />
</div>
<h1>TorontoX</h1>
</hgroup>
</div>
</header>
</%block>
<%block name="university_description">
<p>Established in 1827, the University of Toronto is a vibrant and diverse academic community. It includes 80,000 students, 12,000 colleagues holding faculty appointments, 200 librarians, and 6,000 staff members across three distinctive campuses and at many partner sites, including world-renowned hospitals. With over 800 undergraduate programs, 150 graduate programs, and 40 professional programs, U of T attracts students of the highest calibre, from across Canada and from 160 countries around the world. The University is one of the most respected and influential institutions of higher education and advanced research in the world. Its strengths extend across the full range of disciplines: the 2012-13 Times Higher Education ranking groups the University of Toronto with Stanford, UC Berkeley, UCLA, Columbia, Cambridge, Oxford, the University of Melbourne, and the University of Michigan as the only institutions in the top 27 in all 6 broad disciplinary areas. The University is also consistently rated one of Canada’s Top 100 employers, and ranks with Harvard and Yale for the top university library resources in North America.</p>
</%block>
${parent.body()}
......@@ -2,6 +2,7 @@ from django.conf import settings
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf.urls.static import static
from django.views.generic import RedirectView
import django.contrib.auth.views
# Uncomment the next two lines to enable the admin:
......@@ -65,10 +66,47 @@ urlpatterns = ('',
url(r'^heartbeat$', include('heartbeat.urls')),
url(r'^university_profile/UTx$', 'courseware.views.static_university_profile', name="static_university_profile", kwargs={'org_id': 'UTx'}),
url(r'^university_profile/WellesleyX$', 'courseware.views.static_university_profile', name="static_university_profile", kwargs={'org_id': 'WellesleyX'}),
url(r'^university_profile/GeorgetownX$', 'courseware.views.static_university_profile', name="static_university_profile", kwargs={'org_id': 'GeorgetownX'}),
url(r'^university_profile/(?P<org_id>[^/]+)$', 'courseware.views.university_profile', name="university_profile"),
url(r'^university_profile/UTx$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'UTx'}),
url(r'^university_profile/WellesleyX$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'WellesleyX'}),
url(r'^university_profile/GeorgetownX$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'GeorgetownX'}),
# Dan accidentally sent out a press release with lower case urls for McGill, Toronto,
# Rice, ANU, Delft, and EPFL. Hence the redirects.
url(r'^university_profile/McGillX$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'McGillX'}),
url(r'^university_profile/mcgillx$',
RedirectView.as_view(url='/university_profile/McGillX')),
url(r'^university_profile/TorontoX$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'TorontoX'}),
url(r'^university_profile/torontox$',
RedirectView.as_view(url='/university_profile/TorontoX')),
url(r'^university_profile/RiceX$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'RiceX'}),
url(r'^university_profile/ricex$',
RedirectView.as_view(url='/university_profile/RiceX')),
url(r'^university_profile/ANUx$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'ANUx'}),
url(r'^university_profile/anux$',
RedirectView.as_view(url='/university_profile/ANUx')),
url(r'^university_profile/DelftX$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'DelftX'}),
url(r'^university_profile/delftx$',
RedirectView.as_view(url='/university_profile/DelftX')),
url(r'^university_profile/EPFLx$', 'courseware.views.static_university_profile',
name="static_university_profile", kwargs={'org_id': 'EPFLx'}),
url(r'^university_profile/epflx$',
RedirectView.as_view(url='/university_profile/EPFLx')),
url(r'^university_profile/(?P<org_id>[^/]+)$', 'courseware.views.university_profile',
name="university_profile"),
#Semi-static views (these need to be rendered and have the login bar, but don't change)
url(r'^404$', 'static_template_view.views.render',
......
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