Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
58f0154e
Commit
58f0154e
authored
Feb 04, 2017
by
Douglas Hall
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for multi-org sites
WL-926
parent
66267257
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
77 additions
and
71 deletions
+77
-71
common/djangoapps/student/views.py
+10
-11
common/djangoapps/util/views.py
+5
-5
lms/djangoapps/branding/__init__.py
+11
-13
lms/djangoapps/branding/views.py
+0
-19
lms/djangoapps/shoppingcart/api.py
+3
-3
lms/lib/courseware_search/lms_filter_generator.py
+2
-2
lms/lib/courseware_search/test/test_lms_filter_generator.py
+2
-2
openedx/core/djangoapps/content/course_overviews/models.py
+5
-5
openedx/core/djangoapps/content/course_overviews/tests.py
+6
-6
openedx/core/djangoapps/site_configuration/helpers.py
+15
-0
openedx/core/djangoapps/site_configuration/models.py
+6
-5
openedx/core/djangoapps/site_configuration/tests/test_helpers.py
+12
-0
No files found.
common/djangoapps/student/views.py
View file @
58f0154e
...
...
@@ -286,14 +286,14 @@ def reverification_info(statuses):
return
reverifications
def
get_course_enrollments
(
user
,
org_to_include
,
orgs_to_exclude
):
def
get_course_enrollments
(
user
,
org
s
_to_include
,
orgs_to_exclude
):
"""
Given a user, return a filtered set of his or her course enrollments.
Arguments:
user (User): the user in question.
org
_to_include (str): If not None, ONLY courses of this org
will be returned.
orgs_to_exclude (list[str]): If org_to_include is not None, this
org
s_to_include (list[str]): If not None, ONLY courses of these orgs
will be returned.
orgs_to_exclude (list[str]): If org
s
_to_include is not None, this
argument is ignored. Else, courses of this org will be excluded.
Returns:
...
...
@@ -312,8 +312,8 @@ def get_course_enrollments(user, org_to_include, orgs_to_exclude):
)
continue
# Filter out anything that is not attributed to the
current ORG
.
if
org
_to_include
and
course_overview
.
location
.
org
!=
org
_to_include
:
# Filter out anything that is not attributed to the
orgs to include
.
if
org
s_to_include
and
course_overview
.
location
.
org
not
in
orgs
_to_include
:
continue
# Conversely, filter out any enrollments with courses attributed to current ORG.
...
...
@@ -600,17 +600,16 @@ def dashboard(request):
settings
.
FEATURES
.
get
(
'DISPLAY_COURSE_MODES_ON_DASHBOARD'
,
True
)
)
# we want to filter and only show enrollments for courses within
# the 'ORG' defined in configuration.
course_org_filter
=
configuration_helpers
.
get_value
(
'course_org_filter'
)
# Let's filter out any courses in an "org" that has been declared to be
# in a configuration
org_filter_out_set
=
configuration_helpers
.
get_all_orgs
()
# remove our current org from the "filter out" list, if applicable
# Remove current site orgs from the "filter out" list, if applicable.
# We want to filter and only show enrollments for courses within
# the organizations defined in configuration for the current site.
course_org_filter
=
configuration_helpers
.
get_current_site_orgs
()
if
course_org_filter
:
org_filter_out_set
.
remove
(
course_org_filter
)
org_filter_out_set
=
org_filter_out_set
-
set
(
course_org_filter
)
# Build our (course, enrollment) list for the user, but ignore any courses that no
# longer exist (because the course IDs have changed). Still, we don't delete those
...
...
common/djangoapps/util/views.py
View file @
58f0154e
...
...
@@ -295,11 +295,11 @@ def _record_feedback_in_zendesk(
# Tag all issues with LMS to distinguish channel in Zendesk; requested by student support team
zendesk_tags
=
list
(
tags
.
values
())
+
[
"LMS"
]
# Per edX support, we would like to be able to route
white label feedback items
# via tagging
white_label_org
=
configuration_helpers
.
get_value
(
'course_org_filter'
)
if
white_label_org
:
zendesk_tags
=
zendesk_tags
+
[
"whitelabel_{org}"
.
format
(
org
=
white_label_org
)]
# Per edX support, we would like to be able to route
feedback items by site via tagging
current_site_orgs
=
configuration_helpers
.
get_current_site_orgs
()
if
current_site_orgs
:
for
org
in
current_site_orgs
:
zendesk_tags
.
append
(
"whitelabel_{org}"
.
format
(
org
=
org
))
new_ticket
=
{
"ticket"
:
{
...
...
lms/djangoapps/branding/__init__.py
View file @
58f0154e
...
...
@@ -27,25 +27,23 @@ def get_visible_courses(org=None, filter_=None):
filter_ (dict): Optional parameter that allows custom filtering by
fields on the course.
"""
current_site_org
=
configuration_helpers
.
get_value
(
'course_org_filter'
)
courses
=
[]
current_site_orgs
=
configuration_helpers
.
get_current_site_orgs
()
if
org
and
current_site_org
:
# Return an empty result if the org passed by the caller does not match the designated site org.
courses
=
CourseOverview
.
get_all_courses
(
org
=
org
,
filter_
=
filter_
,
)
if
org
==
current_site_org
else
[]
if
org
:
# Check the current site's orgs to make sure the org's courses should be displayed
if
not
current_site_orgs
or
org
in
current_site_orgs
:
courses
=
CourseOverview
.
get_all_courses
(
orgs
=
[
org
],
filter_
=
filter_
)
elif
current_site_orgs
:
# Only display courses that should be displayed on this site
courses
=
CourseOverview
.
get_all_courses
(
orgs
=
current_site_orgs
,
filter_
=
filter_
)
else
:
# We only make it to this point if one of org or current_site_org is defined.
# If both org and current_site_org were defined, the code would have fallen into the
# first branch of the conditional above, wherein an equality check is performed.
target_org
=
org
or
current_site_org
courses
=
CourseOverview
.
get_all_courses
(
org
=
target_org
,
filter_
=
filter_
)
courses
=
CourseOverview
.
get_all_courses
(
filter_
=
filter_
)
courses
=
sorted
(
courses
,
key
=
lambda
course
:
course
.
number
)
# Filtering can stop here.
if
current_site_org
:
if
current_site_org
s
:
return
courses
# See if we have filtered course listings in this domain
...
...
lms/djangoapps/branding/views.py
View file @
58f0154e
...
...
@@ -14,7 +14,6 @@ from django.contrib.staticfiles.storage import staticfiles_storage
from
edxmako.shortcuts
import
render_to_response
import
student.views
from
student.models
import
CourseEnrollment
import
courseware.views.views
from
edxmako.shortcuts
import
marketing_link
from
util.cache
import
cache_if_anonymous
...
...
@@ -25,24 +24,6 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
log
=
logging
.
getLogger
(
__name__
)
def
get_course_enrollments
(
user
):
"""
Returns the course enrollments for the passed in user within the context of current org, that
is filtered by course_org_filter
"""
enrollments
=
CourseEnrollment
.
enrollments_for_user
(
user
)
course_org
=
configuration_helpers
.
get_value
(
'course_org_filter'
)
if
course_org
:
site_enrollments
=
[
enrollment
for
enrollment
in
enrollments
if
enrollment
.
course_id
.
org
==
course_org
]
else
:
site_enrollments
=
[
enrollment
for
enrollment
in
enrollments
]
return
site_enrollments
@ensure_csrf_cookie
@cache_if_anonymous
()
def
index
(
request
):
...
...
lms/djangoapps/shoppingcart/api.py
View file @
58f0154e
...
...
@@ -11,8 +11,8 @@ def order_history(user, **kwargs):
Returns the list of previously purchased orders for a user. Only the orders with
PaidCourseRegistration and CourseRegCodeItem are returned.
Params:
course_org_filter:
Current Microsite's ORG
.
org_filter_out_set: A list of all other
Microsites' ORG
s.
course_org_filter:
A list of the current Site's orgs
.
org_filter_out_set: A list of all other
Sites' org
s.
"""
course_org_filter
=
kwargs
[
'course_org_filter'
]
if
'course_org_filter'
in
kwargs
else
None
org_filter_out_set
=
kwargs
[
'org_filter_out_set'
]
if
'org_filter_out_set'
in
kwargs
else
[]
...
...
@@ -27,7 +27,7 @@ def order_history(user, **kwargs):
# not attributed (by ORG) to any Microsite.
order_item_course_id
=
getattr
(
order_item
,
'course_id'
,
None
)
if
order_item_course_id
:
if
(
course_org_filter
and
course_org_filter
==
order_item_course_id
.
org
)
or
\
if
(
course_org_filter
and
order_item_course_id
.
org
in
course_org_filter
)
or
\
(
course_org_filter
is
None
and
order_item_course_id
.
org
not
in
org_filter_out_set
):
order_history_list
.
append
({
'order_id'
:
order_item
.
order
.
id
,
...
...
lms/lib/courseware_search/lms_filter_generator.py
View file @
58f0154e
...
...
@@ -34,7 +34,7 @@ class LmsSearchFilterGenerator(SearchFilterGenerator):
field_dictionary
[
'course'
]
=
[
unicode
(
enrollment
.
course_id
)
for
enrollment
in
user_enrollments
]
# if we have an org filter, only include results for this org filter
course_org_filter
=
configuration_helpers
.
get_
value
(
'course_org_filter'
)
course_org_filter
=
configuration_helpers
.
get_
current_site_orgs
(
)
if
course_org_filter
:
field_dictionary
[
'org'
]
=
course_org_filter
...
...
@@ -45,7 +45,7 @@ class LmsSearchFilterGenerator(SearchFilterGenerator):
Exclude any courses defined outside the current org.
"""
exclude_dictionary
=
super
(
LmsSearchFilterGenerator
,
self
)
.
exclude_dictionary
(
**
kwargs
)
course_org_filter
=
configuration_helpers
.
get_
value
(
'course_org_filter'
)
course_org_filter
=
configuration_helpers
.
get_
current_site_orgs
(
)
# If we have a course filter we are ensuring that we only get those courses above
if
not
course_org_filter
:
org_filter_out_set
=
configuration_helpers
.
get_all_orgs
()
...
...
lms/lib/courseware_search/test/test_lms_filter_generator.py
View file @
58f0154e
...
...
@@ -109,7 +109,7 @@ class LmsSearchFilterGeneratorTestCase(ModuleStoreTestCase):
field_dictionary
,
_
,
exclude_dictionary
=
LmsSearchFilterGenerator
.
generate_field_filters
(
user
=
self
.
user
)
self
.
assertNotIn
(
'org'
,
exclude_dictionary
)
self
.
assertIn
(
'org'
,
field_dictionary
)
self
.
assertEqual
(
'TestSiteX'
,
field_dictionary
[
'org'
])
self
.
assertEqual
(
[
'TestSiteX'
]
,
field_dictionary
[
'org'
])
@patch
(
'openedx.core.djangoapps.site_configuration.helpers.get_all_orgs'
,
...
...
@@ -134,4 +134,4 @@ class LmsSearchFilterGeneratorTestCase(ModuleStoreTestCase):
field_dictionary
,
_
,
exclude_dictionary
=
LmsSearchFilterGenerator
.
generate_field_filters
(
user
=
self
.
user
)
self
.
assertNotIn
(
'org'
,
exclude_dictionary
)
self
.
assertIn
(
'org'
,
field_dictionary
)
self
.
assertEqual
(
'TestSite3'
,
field_dictionary
[
'org'
])
self
.
assertEqual
(
[
'TestSite3'
]
,
field_dictionary
[
'org'
])
openedx/core/djangoapps/content/course_overviews/models.py
View file @
58f0154e
...
...
@@ -446,12 +446,12 @@ class CourseOverview(TimeStampedModel):
return
course_overviews
@classmethod
def
get_all_courses
(
cls
,
org
=
None
,
filter_
=
None
):
def
get_all_courses
(
cls
,
org
s
=
None
,
filter_
=
None
):
"""
Returns all CourseOverview objects in the database.
Arguments:
org
(string
): Optional parameter that allows case-insensitive
org
s (list[string]
): Optional parameter that allows case-insensitive
filtering by organization.
filter_ (dict): Optional parameter that allows custom filtering.
"""
...
...
@@ -460,11 +460,11 @@ class CourseOverview(TimeStampedModel):
# created. For tests using CourseFactory, use emit_signals=True.
course_overviews
=
CourseOverview
.
objects
.
all
()
if
org
:
if
org
s
:
# In rare cases, courses belonging to the same org may be accidentally assigned
# an org code with a different casing (e.g., Harvardx as opposed to HarvardX).
# Case-insensitive
exact
matching allows us to deal with this kind of dirty data.
course_overviews
=
course_overviews
.
filter
(
org__i
exact
=
org
)
# Case-insensitive matching allows us to deal with this kind of dirty data.
course_overviews
=
course_overviews
.
filter
(
org__i
regex
=
r'('
+
'|'
.
join
(
orgs
)
+
')'
)
if
filter_
:
course_overviews
=
course_overviews
.
filter
(
**
filter_
)
...
...
openedx/core/djangoapps/content/course_overviews/tests.py
View file @
58f0154e
...
...
@@ -470,7 +470,7 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
def
test_get_all_courses_by_org
(
self
):
org_courses
=
[]
# list of lists of courses
for
index
in
range
(
2
):
for
index
in
range
(
3
):
org_courses
.
append
([
CourseFactory
.
create
(
org
=
'test_org_'
+
unicode
(
index
),
emit_signals
=
True
)
for
__
in
range
(
3
)
...
...
@@ -478,18 +478,18 @@ class CourseOverviewTestCase(ModuleStoreTestCase):
self
.
assertEqual
(
{
c
.
id
for
c
in
CourseOverview
.
get_all_courses
()},
{
c
.
id
for
c
in
org_courses
[
0
]
+
org_courses
[
1
]},
{
c
.
id
for
c
in
org_courses
[
0
]
+
org_courses
[
1
]
+
org_courses
[
2
]
},
)
self
.
assertEqual
(
{
c
.
id
for
c
in
CourseOverview
.
get_all_courses
(
org
=
'test_org_1'
)},
{
c
.
id
for
c
in
org_courses
[
1
]},
{
c
.
id
for
c
in
CourseOverview
.
get_all_courses
(
org
s
=
[
'test_org_1'
,
'test_org_2'
]
)},
{
c
.
id
for
c
in
org_courses
[
1
]
+
org_courses
[
2
]
},
)
# Test case-insensitivity.
self
.
assertEqual
(
{
c
.
id
for
c
in
CourseOverview
.
get_all_courses
(
org
=
'TEST_ORG_1'
)},
{
c
.
id
for
c
in
org_courses
[
1
]},
{
c
.
id
for
c
in
CourseOverview
.
get_all_courses
(
org
s
=
[
'TEST_ORG_1'
,
'TEST_ORG_2'
]
)},
{
c
.
id
for
c
in
org_courses
[
1
]
+
org_courses
[
2
]
},
)
def
test_get_all_courses_by_mobile_available
(
self
):
...
...
openedx/core/djangoapps/site_configuration/helpers.py
View file @
58f0154e
...
...
@@ -188,6 +188,21 @@ def get_value_for_org(org, val_name, default=None):
return
microsite
.
get_value_for_org
(
org
,
val_name
,
default
)
def
get_current_site_orgs
():
"""
This returns the orgs configured in site configuration or microsite configuration for the current site.
Returns:
list: A list of organization names.
"""
course_org_filter
=
get_value
(
'course_org_filter'
)
# Make sure we have a list
if
course_org_filter
and
not
isinstance
(
course_org_filter
,
list
):
course_org_filter
=
[
course_org_filter
]
return
course_org_filter
def
get_all_orgs
():
"""
This returns all of the orgs that are considered in site configurations or microsite configuration,
...
...
openedx/core/djangoapps/site_configuration/models.py
View file @
58f0154e
...
...
@@ -77,8 +77,8 @@ class SiteConfiguration(models.Model):
Configuration value for the given key.
"""
for
configuration
in
cls
.
objects
.
filter
(
values__contains
=
org
,
enabled
=
True
)
.
all
():
org_filter
=
configuration
.
get_value
(
'course_org_filter'
,
None
)
if
org
_filter
==
org
:
course_
org_filter
=
configuration
.
get_value
(
'course_org_filter'
,
None
)
if
org
in
course_org_filter
:
return
configuration
.
get_value
(
name
,
default
)
return
default
...
...
@@ -94,9 +94,10 @@ class SiteConfiguration(models.Model):
org_filter_set
=
set
()
for
configuration
in
cls
.
objects
.
filter
(
values__contains
=
'course_org_filter'
,
enabled
=
True
)
.
all
():
org_filter
=
configuration
.
get_value
(
'course_org_filter'
,
None
)
if
org_filter
:
org_filter_set
.
add
(
org_filter
)
course_org_filter
=
configuration
.
get_value
(
'course_org_filter'
,
[])
if
not
isinstance
(
course_org_filter
,
list
):
course_org_filter
=
[
course_org_filter
]
org_filter_set
.
update
(
course_org_filter
)
return
org_filter_set
@classmethod
...
...
openedx/core/djangoapps/site_configuration/tests/test_helpers.py
View file @
58f0154e
...
...
@@ -36,6 +36,10 @@ test_config = { # pylint: disable=invalid-name
},
}
test_config_multi_org
=
{
# pylint: disable=invalid-name
"course_org_filter"
:
[
"FooOrg"
,
"BarOrg"
,
"FooBarOrg"
]
}
class
TestHelpers
(
TestCase
):
"""
...
...
@@ -189,3 +193,11 @@ class TestHelpers(TestCase):
list
(
configuration_helpers
.
get_all_orgs
()),
test_orgs
,
)
@with_site_configuration
(
configuration
=
test_config_multi_org
)
def
test_get_current_site_orgs
(
self
):
test_orgs
=
test_config_multi_org
[
'course_org_filter'
]
self
.
assertItemsEqual
(
list
(
configuration_helpers
.
get_current_site_orgs
()),
test_orgs
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment