Commit 371418b3 by David Ormsbee

implement subdomain-based course displays

parent 63e0f470
import functools
import json import json
import logging import logging
import random import random
...@@ -156,7 +157,7 @@ def edXauth_signup(request, eamap=None): ...@@ -156,7 +157,7 @@ def edXauth_signup(request, eamap=None):
log.debug('ExtAuth: doing signup for %s' % eamap.external_email) log.debug('ExtAuth: doing signup for %s' % eamap.external_email)
return student_views.main_index(extra_context=context) return student_views.main_index(request, extra_context=context)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# MIT SSL # MIT SSL
...@@ -206,7 +207,7 @@ def edXauth_ssl_login(request): ...@@ -206,7 +207,7 @@ def edXauth_ssl_login(request):
pass pass
if not cert: if not cert:
# no certificate information - go onward to main index # no certificate information - go onward to main index
return student_views.main_index() return student_views.main_index(request)
(user, email, fullname) = ssl_dn_extract_info(cert) (user, email, fullname) = ssl_dn_extract_info(cert)
...@@ -216,4 +217,4 @@ def edXauth_ssl_login(request): ...@@ -216,4 +217,4 @@ def edXauth_ssl_login(request):
credentials=cert, credentials=cert,
email=email, email=email,
fullname=fullname, fullname=fullname,
retfun = student_views.main_index) retfun = functools.partial(student_views.main_index, request))
...@@ -68,9 +68,9 @@ def index(request): ...@@ -68,9 +68,9 @@ def index(request):
from external_auth.views import edXauth_ssl_login from external_auth.views import edXauth_ssl_login
return edXauth_ssl_login(request) return edXauth_ssl_login(request)
return main_index(user=request.user) return main_index(request, user=request.user)
def main_index(extra_context = {}, user=None): def main_index(request, extra_context={}, user=None):
''' '''
Render the edX main page. Render the edX main page.
...@@ -93,7 +93,8 @@ def main_index(extra_context = {}, user=None): ...@@ -93,7 +93,8 @@ def main_index(extra_context = {}, user=None):
entry.summary = soup.getText() entry.summary = soup.getText()
# The course selection work is done in courseware.courses. # The course selection work is done in courseware.courses.
universities = get_courses_by_university(None) universities = get_courses_by_university(None,
domain=request.META['HTTP_HOST'])
context = {'universities': universities, 'entries': entries} context = {'universities': universities, 'entries': entries}
context.update(extra_context) context.update(extra_context)
return render_to_response('index.html', context) return render_to_response('index.html', context)
......
...@@ -2,8 +2,8 @@ from collections import defaultdict ...@@ -2,8 +2,8 @@ from collections import defaultdict
from fs.errors import ResourceNotFoundError from fs.errors import ResourceNotFoundError
from functools import wraps from functools import wraps
import logging import logging
from path import path
from path import path
from django.conf import settings from django.conf import settings
from django.http import Http404 from django.http import Http404
...@@ -142,19 +142,95 @@ def get_course_info_section(course, section_key): ...@@ -142,19 +142,95 @@ def get_course_info_section(course, section_key):
raise KeyError("Invalid about key " + str(section_key)) raise KeyError("Invalid about key " + str(section_key))
<<<<<<< HEAD
def get_courses_by_university(user): def get_courses_by_university(user):
=======
def course_staff_group_name(course):
'''
course should be either a CourseDescriptor instance, or a string (the
.course entry of a Location)
'''
if isinstance(course, str) or isinstance(course, unicode):
coursename = course
else:
# should be a CourseDescriptor, so grab its location.course:
coursename = course.location.course
return 'staff_%s' % coursename
def has_staff_access_to_course(user, course):
'''
Returns True if the given user has staff access to the course.
This means that user is in the staff_* group, or is an overall admin.
TODO (vshnayder): this needs to be changed to allow per-course_id permissions, not per-course
(e.g. staff in 2012 is different from 2013, but maybe some people always have access)
course is the course field of the location being accessed.
'''
if user is None or (not user.is_authenticated()) or course is None:
return False
if user.is_staff:
return True
# note this is the Auth group, not UserTestGroup
user_groups = [x[1] for x in user.groups.values_list()]
staff_group = course_staff_group_name(course)
if staff_group in user_groups:
return True
return False
def has_staff_access_to_course_id(user, course_id):
"""Helper method that takes a course_id instead of a course name"""
loc = CourseDescriptor.id_to_location(course_id)
return has_staff_access_to_course(user, loc.course)
def has_staff_access_to_location(user, location):
"""Helper method that checks whether the user has staff access to
the course of the location.
location: something that can be passed to Location
"""
return has_staff_access_to_course(user, Location(location).course)
def has_access_to_course(user, course):
'''course is the .course element of a location'''
if course.metadata.get('ispublic'):
return True
return has_staff_access_to_course(user,course)
def get_courses_by_university(user, domain=None):
>>>>>>> implement subdomain-based course displays
''' '''
Returns dict of lists of courses available, keyed by course.org (ie university). Returns dict of lists of courses available, keyed by course.org (ie university).
Courses are sorted by course.number. Courses are sorted by course.number.
''' '''
subdomain = domain.split(".")[0]
# TODO: Clean up how 'error' is done. # TODO: Clean up how 'error' is done.
# filter out any courses that errored. # filter out any courses that errored.
if settings.MITX_FEATURES.get('SUBDOMAIN_COURSE_LISTINGS'):
if subdomain in settings.COURSE_LISTINGS:
visible_courses = settings.COURSE_LISTINGS[subdomain]
else:
visible_courses = frozenset(settings.COURSE_LISTINGS['default'])
courses = [c for c in modulestore().get_courses() courses = [c for c in modulestore().get_courses()
if isinstance(c, CourseDescriptor)] if isinstance(c, CourseDescriptor)]
courses = sorted(courses, key=lambda course: course.number) courses = sorted(courses, key=lambda course: course.number)
universities = defaultdict(list) universities = defaultdict(list)
for course in courses: for course in courses:
<<<<<<< HEAD
if has_access(user, course, 'see_exists'): if has_access(user, course, 'see_exists'):
universities[course.org].append(course) universities[course.org].append(course)
=======
if settings.MITX_FEATURES.get('ACCESS_REQUIRE_STAFF_FOR_COURSE'):
if not has_access_to_course(user,course):
continue
if settings.MITX_FEATURES.get('SUBDOMAIN_COURSE_LISTINGS'):
if course.id not in visible_courses:
continue
universities[course.org].append(course)
>>>>>>> implement subdomain-based course displays
return universities return universities
...@@ -63,7 +63,8 @@ def courses(request): ...@@ -63,7 +63,8 @@ def courses(request):
''' '''
Render "find courses" page. The course selection work is done in courseware.courses. Render "find courses" page. The course selection work is done in courseware.courses.
''' '''
universities = get_courses_by_university(request.user) universities = get_courses_by_university(request.user,
domain=request.META['HTTP_HOST'])
return render_to_response("courses.html", {'universities': universities}) return render_to_response("courses.html", {'universities': universities})
...@@ -241,7 +242,8 @@ def university_profile(request, org_id): ...@@ -241,7 +242,8 @@ def university_profile(request, org_id):
raise Http404("University Profile not found for {0}".format(org_id)) raise Http404("University Profile not found for {0}".format(org_id))
# Only grab courses for this org... # Only grab courses for this org...
courses = get_courses_by_university(request.user)[org_id] courses = get_courses_by_university(request.user,
domain=request.META['HTTP_HOST'])[org_id]
context = dict(courses=courses, org_id=org_id) context = dict(courses=courses, org_id=org_id)
template_file = "university_profile/{0}.html".format(org_id).lower() template_file = "university_profile/{0}.html".format(org_id).lower()
......
...@@ -49,6 +49,11 @@ MITX_FEATURES = { ...@@ -49,6 +49,11 @@ MITX_FEATURES = {
## Doing so will cause all courses to be released on production ## Doing so will cause all courses to be released on production
'DISABLE_START_DATES': False, # When True, all courses will be active, regardless of start date 'DISABLE_START_DATES': False, # When True, all courses will be active, regardless of start date
# When True, will only publicly list courses by the subdomain. Expects you
# to define COURSE_LISTINGS, a dictionary mapping subdomains to lists of
# course_ids (see dev_int.py for an example)
'SUBDOMAIN_COURSE_LISTINGS' : False,
'ENABLE_TEXTBOOK' : True, 'ENABLE_TEXTBOOK' : True,
'ENABLE_DISCUSSION' : True, 'ENABLE_DISCUSSION' : True,
...@@ -61,6 +66,7 @@ MITX_FEATURES = { ...@@ -61,6 +66,7 @@ MITX_FEATURES = {
'ACCESS_REQUIRE_STAFF_FOR_COURSE': False, 'ACCESS_REQUIRE_STAFF_FOR_COURSE': False,
'AUTH_USE_OPENID': False, 'AUTH_USE_OPENID': False,
'AUTH_USE_MIT_CERTIFICATES' : False, 'AUTH_USE_MIT_CERTIFICATES' : False,
} }
# Used for A/B testing # Used for A/B testing
......
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