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
1106746f
Commit
1106746f
authored
Mar 23, 2017
by
Jesse Shapiro
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add consent declined banner to dashboard
parent
4c8dc904
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
258 additions
and
3 deletions
+258
-3
common/djangoapps/student/views.py
+4
-0
common/djangoapps/util/enterprise_helpers.py
+78
-2
common/djangoapps/util/tests/test_enterprise_helpers.py
+143
-0
common/templates/util/enterprise_consent_declined_notification.html
+12
-0
lms/static/sass/elements/_system-feedback.scss
+14
-0
lms/templates/dashboard.html
+6
-0
requirements/edx/base.txt
+1
-1
No files found.
common/djangoapps/student/views.py
View file @
1106746f
...
...
@@ -102,6 +102,7 @@ from util.milestones_helpers import (
)
from
util.password_policy_validators
import
validate_password_strength
from
util.enterprise_helpers
import
get_dashboard_consent_notification
import
third_party_auth
from
third_party_auth
import
pipeline
,
provider
from
student.helpers
import
(
...
...
@@ -684,6 +685,8 @@ def dashboard(request):
{
'email'
:
user
.
email
,
'platform_name'
:
platform_name
}
)
enterprise_message
=
get_dashboard_consent_notification
(
request
,
user
,
course_enrollments
)
# Global staff can see what courses errored on their dashboard
staff_access
=
False
errored_courses
=
{}
...
...
@@ -804,6 +807,7 @@ def dashboard(request):
display_sidebar_on_dashboard
=
len
(
order_history_list
)
or
verification_status
in
valid_verification_statuses
context
=
{
'enterprise_message'
:
enterprise_message
,
'enrollment_message'
:
enrollment_message
,
'redirect_message'
:
redirect_message
,
'course_enrollments'
:
course_enrollments
,
...
...
common/djangoapps/util/enterprise_helpers.py
View file @
1106746f
...
...
@@ -6,13 +6,16 @@ import logging
from
functools
import
wraps
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
from
django.core.cache
import
cache
from
django.core.urlresolvers
import
reverse
from
django.shortcuts
import
redirect
from
django.utils.http
import
urlencode
from
django.core.cache
import
cache
from
django.utils.translation
import
ugettext
as
_
from
edxmako.shortcuts
import
render_to_string
from
edx_rest_api_client.client
import
EdxRestApiClient
try
:
from
enterprise
import
utils
as
enterprise_utils
from
enterprise.models
import
EnterpriseCourseEnrollment
from
enterprise.utils
import
consent_necessary_for_course
except
ImportError
:
pass
...
...
@@ -23,6 +26,7 @@ import hashlib
import
six
CONSENT_FAILED_PARAMETER
=
'consent_failed'
ENTERPRISE_CUSTOMER_BRANDING_OVERRIDE_DETAILS
=
'enterprise_customer_branding_override_details'
LOGGER
=
logging
.
getLogger
(
"edx.enterprise_helpers"
)
...
...
@@ -249,7 +253,14 @@ def get_enterprise_consent_url(request, course_id, user=None, return_to=None):
url_params
=
{
'course_id'
:
course_id
,
'next'
:
request
.
build_absolute_uri
(
return_path
)
'next'
:
request
.
build_absolute_uri
(
return_path
),
'failure_url'
:
request
.
build_absolute_uri
(
reverse
(
'dashboard'
)
+
'?'
+
urlencode
(
{
CONSENT_FAILED_PARAMETER
:
course_id
}
)
),
}
querystring
=
urlencode
(
url_params
)
full_url
=
reverse
(
'grant_data_sharing_permissions'
)
+
'?'
+
querystring
...
...
@@ -366,3 +377,68 @@ def get_enterprise_learner_data(site, user):
enterprise_learner_data
=
EnterpriseApiClient
()
.
fetch_enterprise_learner_data
(
site
=
site
,
user
=
user
)
if
enterprise_learner_data
:
return
enterprise_learner_data
[
'results'
]
def
get_dashboard_consent_notification
(
request
,
user
,
course_enrollments
):
"""
If relevant to the request at hand, create a banner on the dashboard indicating consent failed.
Args:
request: The WSGIRequest object produced by the user browsing to the Dashboard page.
user: The logged-in user
course_enrollments: A list of the courses to be rendered on the Dashboard page.
Returns:
str: Either an empty string, or a string containing the HTML code for the notification banner.
"""
enrollment
=
None
enterprise_enrollment
=
None
course_id
=
request
.
GET
.
get
(
CONSENT_FAILED_PARAMETER
)
if
course_id
:
for
course_enrollment
in
course_enrollments
:
if
str
(
course_enrollment
.
course_id
)
==
course_id
:
enrollment
=
course_enrollment
break
try
:
enterprise_enrollment
=
EnterpriseCourseEnrollment
.
objects
.
get
(
course_id
=
course_id
,
enterprise_customer_user__user_id
=
user
.
id
,
)
except
EnterpriseCourseEnrollment
.
DoesNotExist
:
pass
if
enterprise_enrollment
and
enrollment
:
enterprise_customer
=
enterprise_enrollment
.
enterprise_customer_user
.
enterprise_customer
contact_info
=
getattr
(
enterprise_customer
,
'contact_email'
,
None
)
if
contact_info
is
None
:
message_template
=
_
(
'If you have concerns about sharing your data, please contact your administrator '
'at {enterprise_customer_name}.'
)
else
:
message_template
=
_
(
'If you have concerns about sharing your data, please contact your administrator '
'at {enterprise_customer_name} at {contact_info}.'
)
message
=
message_template
.
format
(
enterprise_customer_name
=
enterprise_customer
.
name
,
contact_info
=
contact_info
,
)
title
=
_
(
'Enrollment in {course_name} was not complete.'
)
.
format
(
course_name
=
enrollment
.
course_overview
.
display_name
,
)
return
render_to_string
(
'util/enterprise_consent_declined_notification.html'
,
{
'title'
:
title
,
'message'
:
message
,
}
)
return
''
common/djangoapps/util/tests/test_enterprise_helpers.py
View file @
1106746f
...
...
@@ -13,7 +13,9 @@ from util.enterprise_helpers import (
insert_enterprise_pipeline_elements
,
data_sharing_consent_required
,
set_enterprise_branding_filter_param
,
get_dashboard_consent_notification
,
get_enterprise_branding_filter_param
,
get_enterprise_consent_url
,
get_enterprise_customer_logo_url
)
...
...
@@ -192,3 +194,144 @@ class TestEnterpriseHelpers(unittest.TestCase):
mock_get_consent_url
.
assert_called_once
()
mock_enterprise_enabled
.
assert_called_once
()
mock_consent_necessary
.
assert_called_once
()
@mock.patch
(
'util.enterprise_helpers.consent_needed_for_course'
)
def
test_get_enterprise_consent_url
(
self
,
needed_for_course_mock
):
"""
Verify that get_enterprise_consent_url correctly builds URLs.
"""
needed_for_course_mock
.
return_value
=
True
request_mock
=
mock
.
MagicMock
(
user
=
None
,
build_absolute_uri
=
lambda
x
:
'http://localhost:8000'
+
x
# Don't do it like this in prod. Ever.
)
course_id
=
'course-v1:edX+DemoX+Demo_Course'
return_to
=
'info'
expected_url
=
(
'/enterprise/grant_data_sharing_permissions?course_id=course-v1
%3
AedX
%2
BDemoX
%2
BDemo_'
'Course&failure_url=http
%3
A
%2
F
%2
Flocalhost
%3
A8000
%2
Fdashboard
%3
Fconsent_failed
%3
Dcou'
'rse-v1
%253
AedX
%252
BDemoX
%252
BDemo_Course&next=http
%3
A
%2
F
%2
Flocalhost
%3
A8000
%2
Fcours'
'es
%2
Fcourse-v1
%3
AedX
%2
BDemoX
%2
BDemo_Course
%2
Finfo'
)
actual_url
=
get_enterprise_consent_url
(
request_mock
,
course_id
,
return_to
=
return_to
)
self
.
assertEqual
(
actual_url
,
expected_url
)
def
test_get_dashboard_consent_notification_no_param
(
self
):
"""
Test that the output of the consent notification renderer meets expectations.
"""
request
=
mock
.
MagicMock
(
GET
=
{}
)
notification_string
=
get_dashboard_consent_notification
(
request
,
None
,
None
)
self
.
assertEqual
(
notification_string
,
''
)
def
test_get_dashboard_consent_notification_no_enrollments
(
self
):
request
=
mock
.
MagicMock
(
GET
=
{
'consent_failed'
:
'course-v1:edX+DemoX+Demo_Course'
}
)
enrollments
=
[]
user
=
mock
.
MagicMock
(
id
=
1
)
notification_string
=
get_dashboard_consent_notification
(
request
,
user
,
enrollments
,
)
self
.
assertEqual
(
notification_string
,
''
)
def
test_get_dashboard_consent_notification_no_matching_enrollments
(
self
):
request
=
mock
.
MagicMock
(
GET
=
{
'consent_failed'
:
'course-v1:edX+DemoX+Demo_Course'
}
)
enrollments
=
[
mock
.
MagicMock
(
course_id
=
'other_course_id'
)]
user
=
mock
.
MagicMock
(
id
=
1
)
notification_string
=
get_dashboard_consent_notification
(
request
,
user
,
enrollments
,
)
self
.
assertEqual
(
notification_string
,
''
)
def
test_get_dashboard_consent_notification_no_matching_ece
(
self
):
request
=
mock
.
MagicMock
(
GET
=
{
'consent_failed'
:
'course-v1:edX+DemoX+Demo_Course'
}
)
enrollments
=
[
mock
.
MagicMock
(
course_id
=
'course-v1:edX+DemoX+Demo_Course'
)]
user
=
mock
.
MagicMock
(
id
=
1
)
notification_string
=
get_dashboard_consent_notification
(
request
,
user
,
enrollments
,
)
self
.
assertEqual
(
notification_string
,
''
)
@mock.patch
(
'util.enterprise_helpers.EnterpriseCourseEnrollment'
)
def
test_get_dashboard_consent_notification_no_contact_info
(
self
,
ece_mock
):
mock_get_ece
=
ece_mock
.
objects
.
get
ece_mock
.
DoesNotExist
=
Exception
mock_ece
=
mock_get_ece
.
return_value
mock_ece
.
enterprise_customer_user
=
mock
.
MagicMock
(
enterprise_customer
=
mock
.
MagicMock
(
contact_email
=
None
)
)
mock_ec
=
mock_ece
.
enterprise_customer_user
.
enterprise_customer
mock_ec
.
name
=
'Veridian Dynamics'
request
=
mock
.
MagicMock
(
GET
=
{
'consent_failed'
:
'course-v1:edX+DemoX+Demo_Course'
}
)
enrollments
=
[
mock
.
MagicMock
(
course_id
=
'course-v1:edX+DemoX+Demo_Course'
,
course_overview
=
mock
.
MagicMock
(
display_name
=
'edX Demo Course'
,
)
),
]
user
=
mock
.
MagicMock
(
id
=
1
)
notification_string
=
get_dashboard_consent_notification
(
request
,
user
,
enrollments
,
)
expected_message
=
(
'If you have concerns about sharing your data, please contact your '
'administrator at Veridian Dynamics.'
)
self
.
assertIn
(
expected_message
,
notification_string
)
expected_header
=
'Enrollment in edX Demo Course was not complete.'
self
.
assertIn
(
expected_header
,
notification_string
)
@mock.patch
(
'util.enterprise_helpers.EnterpriseCourseEnrollment'
)
def
test_get_dashboard_consent_notification_contact_info
(
self
,
ece_mock
):
mock_get_ece
=
ece_mock
.
objects
.
get
ece_mock
.
DoesNotExist
=
Exception
mock_ece
=
mock_get_ece
.
return_value
mock_ece
.
enterprise_customer_user
=
mock
.
MagicMock
(
enterprise_customer
=
mock
.
MagicMock
(
contact_email
=
'v.palmer@veridiandynamics.com'
)
)
mock_ec
=
mock_ece
.
enterprise_customer_user
.
enterprise_customer
mock_ec
.
name
=
'Veridian Dynamics'
request
=
mock
.
MagicMock
(
GET
=
{
'consent_failed'
:
'course-v1:edX+DemoX+Demo_Course'
}
)
enrollments
=
[
mock
.
MagicMock
(
course_id
=
'course-v1:edX+DemoX+Demo_Course'
,
course_overview
=
mock
.
MagicMock
(
display_name
=
'edX Demo Course'
,
)
),
]
user
=
mock
.
MagicMock
(
id
=
1
)
notification_string
=
get_dashboard_consent_notification
(
request
,
user
,
enrollments
,
)
expected_message
=
(
'If you have concerns about sharing your data, please contact your '
'administrator at Veridian Dynamics at v.palmer@veridiandynamics.com.'
)
self
.
assertIn
(
expected_message
,
notification_string
)
expected_header
=
'Enrollment in edX Demo Course was not complete.'
self
.
assertIn
(
expected_header
,
notification_string
)
common/templates/util/enterprise_consent_declined_notification.html
0 → 100644
View file @
1106746f
<
%
page
expression_filter=
"h"
/>
<div
class=
"wrapper-msg urgency-info"
>
<div
class=
"msg"
>
<span
class=
"msg-icon fa fa-info-circle"
aria-hidden=
"true"
></span>
<div
class=
"msg-content"
>
<h2
class=
"title"
>
${ title }
</h2>
<div
class=
"copy"
>
<p
class=
'consent-declined-message'
>
${ message }
</p>
</div>
</div>
</div>
</div>
lms/static/sass/elements/_system-feedback.scss
View file @
1106746f
...
...
@@ -118,6 +118,20 @@
}
}
&
.urgency-info
{
background
:
$msg-bg
;
.msg
{
color
:
$white
;
}
.msg-icon
{
font-size
:
2
.5em
;
padding
:
20px
;
}
.msg-content
{
max-width
:
80%
;
}
}
&
.alert
{
border-top
:
3px
solid
$alert-color
;
}
...
...
lms/templates/dashboard.html
View file @
1106746f
...
...
@@ -73,6 +73,12 @@ from openedx.core.djangolib.markup import HTML, Text
${enrollment_message | n, decode.utf8}
</div>
%endif
%if enterprise_message:
<div
class=
"dashboard-banner"
>
${ enterprise_message | n, decode.utf8 }
</div>
%endif
</div>
<main
id=
"main"
aria-label=
"Content"
tabindex=
"-1"
>
...
...
requirements/edx/base.txt
View file @
1106746f
...
...
@@ -52,7 +52,7 @@ edx-lint==0.4.3
astroid==1.3.8
edx-django-oauth2-provider==1.1.4
edx-django-sites-extensions==2.1.1
edx-enterprise==0.2
7.6
edx-enterprise==0.2
8.0
edx-oauth2-provider==1.2.0
edx-opaque-keys==0.4.0
edx-organizations==0.4.3
...
...
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