diff --git a/cms/djangoapps/contentstore/tests/tests.py b/cms/djangoapps/contentstore/tests/tests.py index b503a1819d..80909dad7a 100644 --- a/cms/djangoapps/contentstore/tests/tests.py +++ b/cms/djangoapps/contentstore/tests/tests.py @@ -352,6 +352,33 @@ class ContentStoreTest(TestCase): def test_edit_unit_full(self): self.check_edit_unit('full') + def test_static_tab_reordering(self): + import_from_xml(modulestore(), 'common/test/data/', ['full']) + + ms = modulestore('direct') + course = ms.get_item(Location(['i4x','edX','full','course','6.002_Spring_2012', None])) + + # reverse the ordering + reverse_tabs = [] + for tab in course.tabs: + if tab['type'] == 'static_tab': + reverse_tabs.insert(0, 'i4x://edX/full/static_tab/{0}'.format(tab['url_slug'])) + + resp = self.client.post(reverse('reorder_static_tabs'), json.dumps({'tabs':reverse_tabs}), "application/json") + + course = ms.get_item(Location(['i4x','edX','full','course','6.002_Spring_2012', None])) + + # compare to make sure that the tabs information is in the expected order after the server call + course_tabs = [] + for tab in course.tabs: + if tab['type'] == 'static_tab': + course_tabs.append('i4x://edX/full/static_tab/{0}'.format(tab['url_slug'])) + + self.assertEqual(reverse_tabs, course_tabs) + + + + def test_about_overrides(self): ''' This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 816ccab091..14f96e312a 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -903,6 +903,52 @@ def static_pages(request, org, course, coursename): def edit_static(request, org, course, coursename): return render_to_response('edit-static-page.html', {}) + +@login_required +@expect_json +def reorder_static_tabs(request): + tabs = request.POST['tabs'] + course = get_course_for_item(tabs[0]) + + if not has_access(request.user, course.location): + raise PermissionDenied() + + # get list of existing static tabs in course + # make sure they are the same lengths (i.e. the number of passed in tabs equals the number + # that we know about) otherwise we can drop some! + + existing_static_tabs = [t for t in course.tabs if t['type'] == 'static_tab'] + if len(existing_static_tabs) != len(tabs): + return HttpResponseBadRequest() + + # load all reference tabs, return BadRequest if we can't find any of them + tab_items =[] + for tab in tabs: + item = modulestore('direct').get_item(Location(tab)) + if item is None: + return HttpResponseBadRequest() + + tab_items.append(item) + + # now just go through the existing course_tabs and re-order the static tabs + reordered_tabs = [] + static_tab_idx = 0 + for tab in course.tabs: + if tab['type'] == 'static_tab': + reordered_tabs.append({'type': 'static_tab', + 'name' : tab_items[static_tab_idx].metadata.get('display_name'), + 'url_slug' : tab_items[static_tab_idx].location.name}) + static_tab_idx += 1 + else: + reordered_tabs.append(tab) + + + # OK, re-assemble the static tabs in the new order + course.tabs = reordered_tabs + modulestore('direct').update_metadata(course.location, course.metadata) + return HttpResponse() + + @login_required @ensure_csrf_cookie def edit_tabs(request, org, course, coursename): @@ -914,12 +960,19 @@ def edit_tabs(request, org, course, coursename): if not has_access(request.user, location): raise PermissionDenied() - static_tabs = modulestore('direct').get_items(static_tabs_loc) - # see tabs have been uninitialized (e.g. supporing courses created before tab support in studio) if course_item.tabs is None or len(course_item.tabs) == 0: initialize_course_tabs(course_item) + # first get all static tabs from the tabs list + # we do this because this is also the order in which items are displayed in the LMS + static_tabs_refs = [t for t in course_item.tabs if t['type'] == 'static_tab'] + + static_tabs = [] + for static_tab_ref in static_tabs_refs: + static_tab_loc = Location(location)._replace(category='static_tab', name=static_tab_ref['url_slug']) + static_tabs.append(modulestore('direct').get_item(static_tab_loc)) + components = [ static_tab.location.url() for static_tab @@ -1326,7 +1379,6 @@ def import_course(request, org, course, name): @login_required def generate_export_course(request, org, course, name): location = ['i4x', org, course, 'course', name] - course_module = modulestore().get_item(location) # check that logged in user has permissions to this item if not has_access(request.user, location): raise PermissionDenied() @@ -1373,3 +1425,10 @@ def export_course(request, org, course, name): 'active_tab': 'export', 'successful_import_redirect_url' : '' }) + +def event(request): + ''' + A noop to swallow the analytics call so that cms methods don't spook and poor developers looking at + console logs don't get distracted :-) + ''' + return HttpResponse(True) \ No newline at end of file diff --git a/cms/static/coffee/src/views/tabs.coffee b/cms/static/coffee/src/views/tabs.coffee index 1fbc6ffa7f..5a826c1794 100644 --- a/cms/static/coffee/src/views/tabs.coffee +++ b/cms/static/coffee/src/views/tabs.coffee @@ -15,7 +15,7 @@ class CMS.Views.TabsEdit extends Backbone.View @$('.components').sortable( handle: '.drag-handle' - update: (event, ui) => alert 'not yet implemented!' + update: @tabMoved helper: 'clone' opacity: '0.5' placeholder: 'component-placeholder' @@ -24,6 +24,20 @@ class CMS.Views.TabsEdit extends Backbone.View items: '> .component' ) + tabMoved: (event, ui) => + tabs = [] + @$('.component').each((idx, element) => + tabs.push($(element).data('id')) + ) + $.ajax({ + type:'POST', + url: '/reorder_static_tabs', + data: JSON.stringify({ + tabs : tabs + }), + contentType: 'application/json' + }) + addNewTab: (event) => event.preventDefault() diff --git a/cms/urls.py b/cms/urls.py index 6f8736551b..c928e74d19 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -17,6 +17,7 @@ urlpatterns = ('', url(r'^publish_draft$', 'contentstore.views.publish_draft', name='publish_draft'), url(r'^unpublish_unit$', 'contentstore.views.unpublish_unit', name='unpublish_unit'), url(r'^create_new_course', 'contentstore.views.create_new_course', name='create_new_course'), + url(r'^reorder_static_tabs', 'contentstore.views.reorder_static_tabs', name='reorder_static_tabs'), url(r'^(?P[^/]+)/(?P[^/]+)/course/(?P[^/]+)$', 'contentstore.views.course_index', name='course_index'), @@ -67,6 +68,8 @@ urlpatterns = ('', # temporary landing page for edge url(r'^edge$', 'contentstore.views.edge', name='edge'), + # noop to squelch ajax errors + url(r'^event$', 'contentstore.views.event', name='event'), url(r'^heartbeat$', include('heartbeat.urls')), ) diff --git a/common/djangoapps/student/management/commands/pearson_dump.py b/common/djangoapps/student/management/commands/pearson_dump.py index 28931dc468..228508efb1 100644 --- a/common/djangoapps/student/management/commands/pearson_dump.py +++ b/common/djangoapps/student/management/commands/pearson_dump.py @@ -1,5 +1,6 @@ from optparse import make_option from json import dump +from datetime import datetime from django.core.management.base import BaseCommand, CommandError @@ -32,10 +33,9 @@ class Command(BaseCommand): def handle(self, *args, **options): if len(args) < 1: - raise CommandError("Missing single argument: output JSON file") - - # get output location: - outputfile = args[0] + outputfile = datetime.utcnow().strftime("pearson-dump-%Y%m%d-%H%M%S.json") + else: + outputfile = args[0] # construct the query object to dump: registrations = TestCenterRegistration.objects.all() @@ -65,6 +65,8 @@ class Command(BaseCommand): } if len(registration.upload_error_message) > 0: record['registration_error'] = registration.upload_error_message + if len(registration.testcenter_user.upload_error_message) > 0: + record['demographics_error'] = registration.testcenter_user.upload_error_message if registration.needs_uploading: record['needs_uploading'] = True @@ -72,5 +74,5 @@ class Command(BaseCommand): # dump output: with open(outputfile, 'w') as outfile: - dump(output, outfile) + dump(output, outfile, indent=2) diff --git a/common/test/data/full/policies/6.002_Spring_2012.json b/common/test/data/full/policies/6.002_Spring_2012.json index 345309ff5c..2f55528b7b 100644 --- a/common/test/data/full/policies/6.002_Spring_2012.json +++ b/common/test/data/full/policies/6.002_Spring_2012.json @@ -8,6 +8,7 @@ {"type": "courseware"}, {"type": "course_info", "name": "Course Info"}, {"type": "static_tab", "url_slug": "syllabus", "name": "Syllabus"}, + {"type": "static_tab", "url_slug": "resources", "name": "Resources"}, {"type": "discussion", "name": "Discussion"}, {"type": "wiki", "name": "Wiki"}, {"type": "progress", "name": "Progress"} diff --git a/lms/djangoapps/courseware/tests/factories.py b/lms/djangoapps/courseware/tests/factories.py new file mode 100644 index 0000000000..6950e28565 --- /dev/null +++ b/lms/djangoapps/courseware/tests/factories.py @@ -0,0 +1,44 @@ +import factory +from student.models import (User, UserProfile, Registration, + CourseEnrollmentAllowed) +from django.contrib.auth.models import Group +from datetime import datetime +import uuid + +class UserProfileFactory(factory.Factory): + FACTORY_FOR = UserProfile + + user = None + name = 'Robot Studio' + courseware = 'course.xml' + +class RegistrationFactory(factory.Factory): + FACTORY_FOR = Registration + + user = None + activation_key = uuid.uuid4().hex + +class UserFactory(factory.Factory): + FACTORY_FOR = User + + username = 'robot' + email = 'robot@edx.org' + password = 'test' + first_name = 'Robot' + last_name = 'Tester' + is_staff = False + is_active = True + is_superuser = False + last_login = datetime.now() + date_joined = datetime.now() + +class GroupFactory(factory.Factory): + FACTORY_FOR = Group + + name = 'test_group' + +class CourseEnrollmentAllowedFactory(factory.Factory): + FACTORY_FOR = CourseEnrollmentAllowed + + email = 'test@edx.org' + course_id = 'edX/test/2012_Fall' diff --git a/lms/djangoapps/courseware/tests/test_access.py b/lms/djangoapps/courseware/tests/test_access.py new file mode 100644 index 0000000000..ed9335d382 --- /dev/null +++ b/lms/djangoapps/courseware/tests/test_access.py @@ -0,0 +1,109 @@ +import unittest +import time +from mock import Mock +from django.test import TestCase + +from xmodule.modulestore import Location +from factories import CourseEnrollmentAllowedFactory +import courseware.access as access + +class AccessTestCase(TestCase): + def test__has_global_staff_access(self): + u = Mock(is_staff=False) + self.assertFalse(access._has_global_staff_access(u)) + + u = Mock(is_staff=True) + self.assertTrue(access._has_global_staff_access(u)) + + def test__has_access_to_location(self): + location = Location('i4x://edX/toy/course/2012_Fall') + + self.assertFalse(access._has_access_to_location(None, location, + 'staff', None)) + u = Mock() + u.is_authenticated.return_value = False + self.assertFalse(access._has_access_to_location(u, location, + 'staff', None)) + u = Mock(is_staff=True) + self.assertTrue(access._has_access_to_location(u, location, + 'instructor', None)) + # A user has staff access if they are in the staff group + u = Mock(is_staff=False) + g = Mock() + g.name = 'staff_edX/toy/2012_Fall' + u.groups.all.return_value = [g] + self.assertTrue(access._has_access_to_location(u, location, + 'staff', None)) + # A user has staff access if they are in the instructor group + g.name = 'instructor_edX/toy/2012_Fall' + self.assertTrue(access._has_access_to_location(u, location, + 'staff', None)) + + # A user has instructor access if they are in the instructor group + g.name = 'instructor_edX/toy/2012_Fall' + self.assertTrue(access._has_access_to_location(u, location, + 'instructor', None)) + + # A user does not have staff access if they are + # not in either the staff or the the instructor group + g.name = 'student_only' + self.assertFalse(access._has_access_to_location(u, location, + 'staff', None)) + + # A user does not have instructor access if they are + # not in the instructor group + g.name = 'student_only' + self.assertFalse(access._has_access_to_location(u, location, + 'instructor', None)) + + def test__has_access_string(self): + u = Mock(is_staff=True) + self.assertFalse(access._has_access_string(u, 'not_global', 'staff', None)) + + u._has_global_staff_access.return_value = True + self.assertTrue(access._has_access_string(u, 'global', 'staff', None)) + + self.assertRaises(ValueError, access._has_access_string, u, 'global', 'not_staff', None) + + def test__has_access_descriptor(self): + # TODO: override DISABLE_START_DATES and test the start date branch of the method + u = Mock() + d = Mock() + d.start = time.gmtime(time.time() - 86400) # make sure the start time is in the past + + # Always returns true because DISABLE_START_DATES is set in test.py + self.assertTrue(access._has_access_descriptor(u, d, 'load')) + self.assertRaises(ValueError, access._has_access_descriptor, u, d, 'not_load_or_staff') + + def test__has_access_course_desc_can_enroll(self): + u = Mock() + yesterday = time.gmtime(time.time() - 86400) + tomorrow = time.gmtime(time.time() + 86400) + c = Mock(enrollment_start=yesterday, enrollment_end=tomorrow) + c.metadata.get = 'is_public' + + # User can enroll if it is between the start and end dates + self.assertTrue(access._has_access_course_desc(u, c, 'enroll')) + + # User can enroll if authenticated and specifically allowed for that course + # even outside the open enrollment period + u = Mock(email='test@edx.org', is_staff=False) + u.is_authenticated.return_value = True + + c = Mock(enrollment_start=tomorrow, enrollment_end=tomorrow, id='edX/test/2012_Fall') + c.metadata.get = 'is_public' + + allowed = CourseEnrollmentAllowedFactory(email=u.email, course_id=c.id) + + self.assertTrue(access._has_access_course_desc(u, c, 'enroll')) + + # Staff can always enroll even outside the open enrollment period + u = Mock(email='test@edx.org', is_staff=True) + u.is_authenticated.return_value = True + + c = Mock(enrollment_start=tomorrow, enrollment_end=tomorrow, id='edX/test/Whenever') + c.metadata.get = 'is_public' + self.assertTrue(access._has_access_course_desc(u, c, 'enroll')) + + # TODO: + # Non-staff cannot enroll outside the open enrollment period if not specifically allowed diff --git a/lms/static/images/press/releases/eric-lander-lab.jpg b/lms/static/images/press/releases/eric-lander-lab.jpg new file mode 100644 index 0000000000..54f027775d Binary files /dev/null and b/lms/static/images/press/releases/eric-lander-lab.jpg differ diff --git a/lms/static/images/press/releases/eric-lander-lab_x300.jpg b/lms/static/images/press/releases/eric-lander-lab_x300.jpg new file mode 100644 index 0000000000..38c4a208ed Binary files /dev/null and b/lms/static/images/press/releases/eric-lander-lab_x300.jpg differ diff --git a/lms/static/images/press/releases/eric-lander_240x180.jpg b/lms/static/images/press/releases/eric-lander_240x180.jpg new file mode 100644 index 0000000000..ee5b2d875b Binary files /dev/null and b/lms/static/images/press/releases/eric-lander_240x180.jpg differ diff --git a/lms/templates/feed.rss b/lms/templates/feed.rss index 9d20ed67bc..8048c86cbd 100644 --- a/lms/templates/feed.rss +++ b/lms/templates/feed.rss @@ -6,7 +6,16 @@ ## EdX Blog - 2013-01-21T14:00:12-07:00 + 2013-01-30T14:00:12-07:00 + + tag:www.edx.org,2012:Post/13 + 2013-01-30T10:00:00-07:00 + 2013-01-30T10:00:00-07:00 + + New biology course from human genome pioneer Eric Lander + <img src="${static.url('images/press/releases/eric-lander_240x180.jpg')}" /> + <p></p> + tag:www.edx.org,2012:Post/12 2013-01-29T10:00:00-07:00 diff --git a/lms/templates/static_templates/faq.html b/lms/templates/static_templates/faq.html index f6f5b07fe7..a0d8c6d577 100644 --- a/lms/templates/static_templates/faq.html +++ b/lms/templates/static_templates/faq.html @@ -39,7 +39,14 @@

Will certificates be awarded?

-

Yes. Online learners who demonstrate mastery of subjects can earn a certificate of mastery. Certificates will be issued by edX under the name of the underlying "X University" from where the course originated, i.e. HarvardX, MITx or BerkeleyX. For the courses in Fall 2012, those certificates will be free. There is a plan to charge a modest fee for certificates in the future.

+

Yes. Online learners who demonstrate mastery of subjects can earn a certificate + of mastery. Certificates will be issued at the discretion of edX and the underlying + X University that offered the course under the name of the underlying "X + University" from where the course originated, i.e. HarvardX, MITx or BerkeleyX. + For the courses in Fall 2012, those certificates will be free. There is a plan to + charge a modest fee for certificates in the future. Note: At this time, edX is + holding certificates for learners connected with Cuba, Iran, Syria and Sudan + pending confirmation that the issuance is in compliance with U.S. embargoes.

What will the scope of the online courses be? How many? Which faculty?

diff --git a/lms/templates/static_templates/help.html b/lms/templates/static_templates/help.html index 74b4c2afc9..e150b5dbc8 100644 --- a/lms/templates/static_templates/help.html +++ b/lms/templates/static_templates/help.html @@ -180,8 +180,17 @@

Will I get a certificate for taking an edX course?

-
-

Online learners who receive a passing grade for a course will receive a certificate of mastery from edX and the underlying X University that offered the course. For example, a certificate of mastery for MITx’s 6.002x Circuits & Electronics will come from edX and MITx.

+
+

Online learners who receive a passing grade for a course will receive a certificate + of mastery at the discretion of edX and the underlying X University that offered + the course. For example, a certificate of mastery for MITx’s 6.002x Circuits & + Electronics will come from edX and MITx.

+

If you passed the course, your certificate of mastery will be delivered online + through edx.org. So be sure to check your email in the weeks following the final + grading – you will be able to download and print your certificate. Note: At this + time, edX is holding certificates for learners connected with Cuba, Iran, Syria + and Sudan pending confirmation that the issuance is in compliance with U.S. + embargoes.

diff --git a/lms/templates/static_templates/press_releases/eric_lander_secret_of_life.html b/lms/templates/static_templates/press_releases/eric_lander_secret_of_life.html new file mode 100644 index 0000000000..d91c8091d7 --- /dev/null +++ b/lms/templates/static_templates/press_releases/eric_lander_secret_of_life.html @@ -0,0 +1,92 @@ +<%! from django.core.urlresolvers import reverse %> +<%inherit file="../../main.html" /> + +<%namespace name='static' file='../../static_content.html'/> + +<%block name="title">Human Genome Pioneer Eric Lander to reveal “the secret of life” +
+ + +
+
+

Human Genome Pioneer Eric Lander to reveal “the secret of life”

+
+
+

Broad Institute Director shares his MIT introductory biology course, covering topics in biochemistry, genetics and genomics, through edX.

+ +
+ +
+

Eric Lander, the founding director of the Broad Institute and a professor at MIT and Harvard Medical School.

+ High Resolution Image

+
+
+ + + +

CAMBRIDGE, MA – January 30, 2013 – +In the past 10 years, the ability to decode or “sequence” DNA has grown by a million-fold, a stunning rate of progress that is producing a flood of information about human biology and disease. Because of these advances, the scientific community — and the world as a whole — stands on the verge of a revolution in biology. In the coming decades scientists will be able to understand how cells are “wired” and how that wiring is disrupted in human diseases ranging from diabetes to cancer to schizophrenia. Now, with his free online course, 7.00x Introductory Biology: “The Secret of Life”, genome pioneer Eric Lander, the founding director of the Broad Institute and a professor at MIT and Harvard Medical School, will explain to students around the world the basics of biology – the secret of life, so to speak – so that they can understand today’s revolution in biology.

+ +

EdX, the not-for-profit online learning initiative founded by Harvard University and the Massachusetts Institute of Technology (MIT), brings the best courses from the best faculty at the best institutions to anyone with an Internet connection. For the past 20 years, legendary teacher Lander has taught Introductory Biology to more than half of all MIT students. He has now adapted his course for online education, creating the newest course on the edX platform. The course, 7.00X, is now open for enrollment, with the first class slated for March 5th. This course will include innovative technology including a 3D molecule viewer and gene explorer tool to transform the learning experience. It is open to all levels and types of learners.

+ +

“Introducing the freshman class of MIT to the basics of biology is exhilarating,” said Lander. “Now, with this edX course, I look forward to teaching people around the world. There are no prerequisites for this course – other than curiosity and an interest in understanding some of the greatest scientific challenges of our time.”

+ +

Those taking the course will learn the fundamental ideas that underlie modern biology and medicine, including genetics, biochemistry, molecular biology, recombinant DNA, genomics and genomic medicine. They will become familiar with the structure and function of macromolecules such as DNA, RNA and proteins and understand how information flows within cells. Students will explore how mutations affect biological function and cause human disease. They will learn about modern molecular biological techniques and their wide-ranging impact.

+ +

“Eric Lander has created this remarkable digitally enhanced introduction to genetics and biology,” said Anant Agarwal, President of edX. “With this unique online version, he has brought the introductory biology course to a new level. It has been completely rethought and retooled, incorporating cutting-edge online interactive tools as well as community-building contests and milestone-based prizes.”

+ +

With online courses through edX like 7.00x, what matters isn’t what people have achieved or their transcripts, but their desire to learn. Students only need to come with a real interest in science and the desire to understand what's going on at the forefront of biology, and to learn the fundamental principles on which an amazing biomedical revolution is based – from one of the top scientist in the world. 7.00x Introductory Biology: The Secret of Life is now available for enrollment. Classes will start on March 5, 2013.

+ +

Dr. Eric Lander is President and Founding Director of the Broad Institute of Harvard and MIT, a new kind of collaborative biomedical research institution focused on genomic medicine. Dr. Lander is also Professor of Biology at MIT and Professor of Systems Biology at the Harvard Medical School. In addition, Dr. Lander serves as Co-Chair of the President’s Council of Advisors on Science and Technology, which advises the White House on science and technology. A geneticist, molecular biologist and mathematician, Dr. Lander has played a pioneering role in all aspects of the reading, understanding and medical application of the human genome. He was a principal leader of the international Human Genome Project (HGP) from 1990-2003, with his group being the largest contributor to the mapping and sequencing of the human genetic blueprint. Dr. Lander was an early pioneer in the free availability of genomic tools and information. Finally, he has mentored an extraordinary cadre of young scientists who have become the next generation of leaders in medical genomics. The recipient of numerous awards and honorary degrees, Dr. Lander was elected a member of the U.S. National Academy of Sciences in 1997 and of the U.S. Institute of Medicine in 1999.

+ + +

Previously announced new 2013 courses include: +8.02x Electricity and Magnetism from Walter Lewin +Justice from Michael Sandel; Introduction to Statistics from Ani Adhikari; The Challenges of Global Poverty from Esther Duflo; The Ancient Greek Hero from Gregory Nagy; Quantum Mechanics and Quantum Computation from Umesh Vazirani; Human Health and Global Environmental Change, from Aaron Bernstein and Jack Spengler.

+ +

In addition to these new courses, edX is bringing back several courses from the popular fall 2012 semester: Introduction to Computer Science and Programming; Introduction to Solid State Chemistry; Introduction to Artificial Intelligence; Software as a Service I; Software as a Service II; Foundations of Computer Graphics.

+ +

About the Broad Institute of MIT and Harvard

+ +

The Eli and Edythe L. Broad Institute of MIT and Harvard was founded in 2003 to empower this generation of creative scientists to transform medicine with new genome-based knowledge. The Broad Institute seeks to describe all the molecular components of life and their connections; discover the molecular basis of major human diseases; develop effective new approaches to diagnostics and therapeutics; and disseminate discoveries, tools, methods and data openly to the entire scientific community.

+ +

Founded by MIT, Harvard and its affiliated hospitals, and the visionary Los Angeles philanthropists Eli and Edythe L. Broad, the Broad Institute includes faculty, professional staff and students from throughout the MIT and Harvard biomedical research communities and beyond, with collaborations spanning over a hundred private and public institutions in more than 40 countries worldwide. For further information about the Broad Institute, go to www.broadinstitute.org.

+ +

About edX

+ +

EdX is a not-for-profit enterprise of its founding partners Harvard University and the Massachusetts Institute of Technology focused on transforming online and on-campus learning through groundbreaking methodologies, game-like experiences and cutting-edge research. EdX provides inspirational and transformative knowledge to students of all ages, social status, and income who form worldwide communities of learners. EdX uses its open source technology to transcend physical and social borders. We’re focused on people, not profit. EdX is based in Cambridge, Massachusetts in the USA.

+ +
+

Contact:

+

Brad Baker, Weber Shandwick for edX

+

BBaker@webershandwick.com

+

(617) 520-7043

+
+ + + +
+
+
diff --git a/lms/templates/static_templates/press_releases/template.html b/lms/templates/static_templates/press_releases/template.html new file mode 100644 index 0000000000..bf2ba9bc6f --- /dev/null +++ b/lms/templates/static_templates/press_releases/template.html @@ -0,0 +1,60 @@ +<%! from django.core.urlresolvers import reverse %> +<%inherit file="../../main.html" /> + +<%namespace name='static' file='../../static_content.html'/> + +<%block name="title">TITLE +
+ + +
+
+

TITLE

+
+
+

SUBTITLE

+ +

CAMBRIDGE, MA – MONTH DAY, YEAR – + +Text

+ +

more text

+ + +

About edX

+ +

EdX is a not-for-profit enterprise of its founding partners Harvard University and the Massachusetts Institute of Technology focused on transforming online and on-campus learning through groundbreaking methodologies, game-like experiences and cutting-edge research. EdX provides inspirational and transformative knowledge to students of all ages, social status, and income who form worldwide communities of learners. EdX uses its open source technology to transcend physical and social borders. We’re focused on people, not profit. EdX is based in Cambridge, Massachusetts in the USA.

+ + +
+

Contact:

+

Brad Baker, Weber Shandwick for edX

+

BBaker@webershandwick.com

+

(617) 520-7043

+
+ + +
+
+
diff --git a/lms/urls.py b/lms/urls.py index f92b63aac2..d54883ef4c 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -125,11 +125,14 @@ urlpatterns = ('', url(r'^press/bostonx-announcement$', 'static_template_view.views.render', {'template': 'press_releases/bostonx_announcement.html'}, name="press/bostonx-announcement"), + url(r'^press/eric-lander-secret-of-life$', 'static_template_view.views.render', + {'template': 'press_releases/eric_lander_secret_of_life.html'}, + name="press/eric-lander-secret-of-life"), # Should this always update to point to the latest press release? (r'^pressrelease$', 'django.views.generic.simple.redirect_to', - {'url': '/press/bostonx-announcement'}), + {'url': '/press/eric-lander-secret-of-life'}), (r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}),