Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
course-discovery
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
course-discovery
Commits
9d3a782b
Commit
9d3a782b
authored
Jan 02, 2017
by
Waheed Ahmed
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed/Moved UpdateCourseKeyView to API directory.
ECOM-6692
parent
17b1f519
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
184 additions
and
186 deletions
+184
-186
course_discovery/apps/publisher/api/serializers.py
+38
-2
course_discovery/apps/publisher/api/tests/test_serializers.py
+36
-2
course_discovery/apps/publisher/api/tests/test_views.py
+92
-0
course_discovery/apps/publisher/api/urls.py
+4
-1
course_discovery/apps/publisher/api/views.py
+10
-2
course_discovery/apps/publisher/serializers.py
+0
-40
course_discovery/apps/publisher/tests/test_serializers.py
+0
-40
course_discovery/apps/publisher/tests/test_views.py
+1
-86
course_discovery/apps/publisher/views.py
+0
-10
course_discovery/static/js/publisher/views/dashboard.js
+2
-2
course_discovery/templates/publisher/dashboard/_studio_requests.html
+1
-1
No files found.
course_discovery/apps/publisher/api/serializers.py
View file @
9d3a782b
"""Publisher API Serializers"""
"""Publisher API Serializers"""
import
waffle
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.keys
import
CourseKey
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.publisher.models
import
CourseUserRole
from
course_discovery.apps.publisher.emails
import
send_email_for_studio_instance_created
from
course_discovery.apps.publisher.models
import
CourseUserRole
,
CourseRun
class
CourseUserRoleSerializer
(
serializers
.
ModelSerializer
):
class
CourseUserRoleSerializer
(
serializers
.
ModelSerializer
):
...
@@ -30,3 +33,36 @@ class GroupUserSerializer(serializers.ModelSerializer):
...
@@ -30,3 +33,36 @@ class GroupUserSerializer(serializers.ModelSerializer):
class
Meta
:
class
Meta
:
model
=
User
model
=
User
fields
=
(
'id'
,
'full_name'
,
)
fields
=
(
'id'
,
'full_name'
,
)
class
UpdateCourseKeySerializer
(
serializers
.
ModelSerializer
):
"""
Serializer for the `CourseRun` model to update 'lms_course_id'.
"""
class
Meta
:
model
=
CourseRun
fields
=
(
'lms_course_id'
,
'changed_by'
,)
def
validate
(
self
,
data
):
validated_values
=
super
(
UpdateCourseKeySerializer
,
self
)
.
validate
(
data
)
lms_course_id
=
validated_values
.
get
(
'lms_course_id'
)
try
:
CourseKey
.
from_string
(
lms_course_id
)
except
InvalidKeyError
:
raise
serializers
.
ValidationError
(
'Invalid course key [{}]'
.
format
(
lms_course_id
))
request
=
self
.
context
.
get
(
'request'
)
if
request
:
validated_values
.
update
({
'changed_by'
:
request
.
user
})
return
validated_values
def
update
(
self
,
instance
,
validated_data
):
instance
=
super
(
UpdateCourseKeySerializer
,
self
)
.
update
(
instance
,
validated_data
)
if
waffle
.
switch_is_active
(
'enable_publisher_email_notifications'
):
send_email_for_studio_instance_created
(
instance
)
return
instance
course_discovery/apps/publisher/api/tests/test_serializers.py
View file @
9d3a782b
...
@@ -2,10 +2,13 @@
...
@@ -2,10 +2,13 @@
from
unittest
import
TestCase
from
unittest
import
TestCase
from
django.test
import
RequestFactory
from
django.test
import
RequestFactory
from
rest_framework.exceptions
import
ValidationError
from
course_discovery.apps.core.tests.factories
import
UserFactory
from
course_discovery.apps.core.tests.factories
import
UserFactory
from
course_discovery.apps.publisher.api.serializers
import
CourseUserRoleSerializer
,
GroupUserSerializer
from
course_discovery.apps.publisher.api.serializers
import
(
from
course_discovery.apps.publisher.tests.factories
import
CourseUserRoleFactory
CourseUserRoleSerializer
,
GroupUserSerializer
,
UpdateCourseKeySerializer
)
from
course_discovery.apps.publisher.tests.factories
import
CourseUserRoleFactory
,
CourseRunFactory
class
CourseUserRoleSerializerTests
(
TestCase
):
class
CourseUserRoleSerializerTests
(
TestCase
):
...
@@ -39,3 +42,34 @@ class GroupUserSerializerTests(TestCase):
...
@@ -39,3 +42,34 @@ class GroupUserSerializerTests(TestCase):
serializer
=
GroupUserSerializer
(
user
)
serializer
=
GroupUserSerializer
(
user
)
self
.
assertDictEqual
(
serializer
.
data
,
{
'id'
:
user
.
id
,
'full_name'
:
user
.
full_name
})
self
.
assertDictEqual
(
serializer
.
data
,
{
'id'
:
user
.
id
,
'full_name'
:
user
.
full_name
})
class
UpdateCourseKeySerializerTests
(
TestCase
):
serializer_class
=
UpdateCourseKeySerializer
def
setUp
(
self
):
super
(
UpdateCourseKeySerializerTests
,
self
)
.
setUp
()
self
.
course_run
=
CourseRunFactory
()
self
.
request
=
RequestFactory
()
self
.
user
=
UserFactory
()
self
.
request
.
user
=
self
.
user
def
get_expected_data
(
self
):
return
{
'lms_course_id'
:
self
.
course_run
.
lms_course_id
,
'changed_by'
:
self
.
user
}
def
test_validation
(
self
):
self
.
course_run
.
lms_course_id
=
'course-v1:edxTest+TC101+2016_Q1'
self
.
course_run
.
save
()
# pylint: disable=no-member
serializer
=
self
.
serializer_class
(
self
.
course_run
,
context
=
{
'request'
:
self
.
request
})
expected
=
serializer
.
validate
(
serializer
.
data
)
self
.
assertEqual
(
self
.
get_expected_data
(),
expected
)
def
test_validation_error
(
self
):
self
.
course_run
.
lms_course_id
=
'invalid-course-id'
self
.
course_run
.
save
()
# pylint: disable=no-member
serializer
=
self
.
serializer_class
(
self
.
course_run
)
with
self
.
assertRaises
(
ValidationError
):
serializer
.
validate
(
serializer
.
data
)
course_discovery/apps/publisher/api/tests/test_views.py
View file @
9d3a782b
...
@@ -2,13 +2,18 @@
...
@@ -2,13 +2,18 @@
import
json
import
json
import
ddt
import
ddt
from
django.conf
import
settings
from
django.contrib.auth.models
import
Group
from
django.contrib.auth.models
import
Group
from
django.contrib.sites.models
import
Site
from
django.core
import
mail
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.test
import
TestCase
from
django.test
import
TestCase
from
course_discovery.apps.core.tests.factories
import
UserFactory
,
USER_PASSWORD
from
course_discovery.apps.core.tests.factories
import
UserFactory
,
USER_PASSWORD
from
course_discovery.apps.course_metadata.tests
import
toggle_switch
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.constants
import
INTERNAL_USER_GROUP_NAME
from
course_discovery.apps.publisher.constants
import
INTERNAL_USER_GROUP_NAME
from
course_discovery.apps.publisher.models
import
CourseRun
from
course_discovery.apps.publisher.tests
import
factories
,
JSON_CONTENT_TYPE
from
course_discovery.apps.publisher.tests
import
factories
,
JSON_CONTENT_TYPE
...
@@ -137,3 +142,90 @@ class OrganizationGroupUserViewTests(TestCase):
...
@@ -137,3 +142,90 @@ class OrganizationGroupUserViewTests(TestCase):
return
reverse
(
return
reverse
(
'publisher:api:organization_group_users'
,
kwargs
=
{
'pk'
:
org_id
}
'publisher:api:organization_group_users'
,
kwargs
=
{
'pk'
:
org_id
}
)
)
class
UpdateCourseKeyViewTests
(
TestCase
):
def
setUp
(
self
):
super
(
UpdateCourseKeyViewTests
,
self
)
.
setUp
()
self
.
course_run
=
factories
.
CourseRunFactory
()
self
.
user
=
UserFactory
()
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course_run
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
update_course_key_url
=
reverse
(
'publisher:api:update_course_key'
,
kwargs
=
{
'pk'
:
self
.
course_run
.
id
}
)
factories
.
CourseUserRoleFactory
(
role
=
PublisherUserRole
.
PartnerCoordinator
,
course
=
self
.
course_run
.
course
,
user
=
self
.
user
)
factories
.
UserAttributeFactory
(
user
=
self
.
user
,
enable_email_notification
=
True
)
toggle_switch
(
'enable_publisher_email_notifications'
,
True
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
def
test_update_course_key_with_errors
(
self
):
"""
Test that api returns error with invalid course key.
"""
invalid_course_id
=
'invalid-course-key'
response
=
self
.
client
.
patch
(
self
.
update_course_key_url
,
data
=
json
.
dumps
({
'lms_course_id'
:
invalid_course_id
}),
content_type
=
JSON_CONTENT_TYPE
)
self
.
assertEqual
(
response
.
status_code
,
400
)
self
.
assertEqual
(
response
.
data
.
get
(
'non_field_errors'
),
[
'Invalid course key [{}]'
.
format
(
invalid_course_id
)]
)
def
test_update_course_key
(
self
):
"""
Test that internal user can update `lms_course_id` for a course run.
"""
# Verify that `lms_course_id` and `changed_by` are None
self
.
assert_course_key_and_changed_by
()
lms_course_id
=
'course-v1:edxTest+TC12+2050Q1'
response
=
self
.
client
.
patch
(
self
.
update_course_key_url
,
data
=
json
.
dumps
({
'lms_course_id'
:
lms_course_id
}),
content_type
=
JSON_CONTENT_TYPE
)
self
.
assertEqual
(
response
.
status_code
,
200
)
# Verify that `lms_course_id` and `changed_by` are not None
self
.
assert_course_key_and_changed_by
(
lms_course_id
=
lms_course_id
,
changed_by
=
self
.
user
)
# Assert email sent
self
.
assert_email_sent
(
reverse
(
'publisher:publisher_course_run_detail'
,
kwargs
=
{
'pk'
:
self
.
course_run
.
id
}),
'Studio instance created'
,
'Studio instance created for the following course run'
)
def
assert_course_key_and_changed_by
(
self
,
lms_course_id
=
None
,
changed_by
=
None
):
self
.
course_run
=
CourseRun
.
objects
.
get
(
id
=
self
.
course_run
.
id
)
self
.
assertEqual
(
self
.
course_run
.
lms_course_id
,
lms_course_id
)
self
.
assertEqual
(
self
.
course_run
.
changed_by
,
changed_by
)
def
assert_email_sent
(
self
,
object_path
,
subject
,
expected_body
):
"""
DRY method to assert sent email data.
"""
self
.
assertEqual
(
len
(
mail
.
outbox
),
1
)
self
.
assertEqual
([
settings
.
PUBLISHER_FROM_EMAIL
],
mail
.
outbox
[
0
]
.
to
)
self
.
assertEqual
([
self
.
user
.
email
],
mail
.
outbox
[
0
]
.
bcc
)
self
.
assertEqual
(
str
(
mail
.
outbox
[
0
]
.
subject
),
subject
)
body
=
mail
.
outbox
[
0
]
.
body
.
strip
()
self
.
assertIn
(
expected_body
,
body
)
page_url
=
'https://{host}{path}'
.
format
(
host
=
Site
.
objects
.
get_current
()
.
domain
.
strip
(
'/'
),
path
=
object_path
)
self
.
assertIn
(
page_url
,
body
)
course_discovery/apps/publisher/api/urls.py
View file @
9d3a782b
""" Publisher API URLs. """
""" Publisher API URLs. """
from
django.conf.urls
import
url
from
django.conf.urls
import
url
from
course_discovery.apps.publisher.api.views
import
CourseRoleAssignmentView
,
OrganizationGroupUserView
from
course_discovery.apps.publisher.api.views
import
(
CourseRoleAssignmentView
,
OrganizationGroupUserView
,
UpdateCourseKeyView
)
urlpatterns
=
[
urlpatterns
=
[
url
(
r'^course_role_assignments/(?P<pk>\d+)/$'
,
CourseRoleAssignmentView
.
as_view
(),
name
=
'course_role_assignments'
),
url
(
r'^course_role_assignments/(?P<pk>\d+)/$'
,
CourseRoleAssignmentView
.
as_view
(),
name
=
'course_role_assignments'
),
url
(
r'^admins/organizations/(?P<pk>\d+)/users/$'
,
OrganizationGroupUserView
.
as_view
(),
url
(
r'^admins/organizations/(?P<pk>\d+)/users/$'
,
OrganizationGroupUserView
.
as_view
(),
name
=
'organization_group_users'
),
name
=
'organization_group_users'
),
url
(
r'^course_runs/(?P<pk>\d+)/$'
,
UpdateCourseKeyView
.
as_view
(),
name
=
'update_course_key'
),
]
]
course_discovery/apps/publisher/api/views.py
View file @
9d3a782b
...
@@ -2,9 +2,11 @@ from rest_framework.generics import UpdateAPIView, ListAPIView, get_object_or_40
...
@@ -2,9 +2,11 @@ from rest_framework.generics import UpdateAPIView, ListAPIView, get_object_or_40
from
rest_framework.permissions
import
IsAuthenticated
from
rest_framework.permissions
import
IsAuthenticated
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.publisher.models
import
CourseUserRole
,
OrganizationExtension
from
course_discovery.apps.publisher.models
import
CourseUserRole
,
OrganizationExtension
,
CourseRun
from
course_discovery.apps.publisher.api.permissions
import
CanViewAssociatedCourse
,
InternalUserPermission
from
course_discovery.apps.publisher.api.permissions
import
CanViewAssociatedCourse
,
InternalUserPermission
from
course_discovery.apps.publisher.api.serializers
import
CourseUserRoleSerializer
,
GroupUserSerializer
from
course_discovery.apps.publisher.api.serializers
import
(
CourseUserRoleSerializer
,
GroupUserSerializer
,
UpdateCourseKeySerializer
)
class
CourseRoleAssignmentView
(
UpdateAPIView
):
class
CourseRoleAssignmentView
(
UpdateAPIView
):
...
@@ -21,3 +23,9 @@ class OrganizationGroupUserView(ListAPIView):
...
@@ -21,3 +23,9 @@ class OrganizationGroupUserView(ListAPIView):
org_extension
=
get_object_or_404
(
OrganizationExtension
,
organization
=
self
.
kwargs
.
get
(
'pk'
))
org_extension
=
get_object_or_404
(
OrganizationExtension
,
organization
=
self
.
kwargs
.
get
(
'pk'
))
queryset
=
User
.
objects
.
filter
(
groups__name
=
org_extension
.
group
)
queryset
=
User
.
objects
.
filter
(
groups__name
=
org_extension
.
group
)
return
queryset
return
queryset
class
UpdateCourseKeyView
(
UpdateAPIView
):
permission_classes
=
(
IsAuthenticated
,
InternalUserPermission
,)
queryset
=
CourseRun
.
objects
.
all
()
serializer_class
=
UpdateCourseKeySerializer
course_discovery/apps/publisher/serializers.py
deleted
100644 → 0
View file @
17b1f519
"""Publisher Serializers"""
import
waffle
from
opaque_keys
import
InvalidKeyError
from
opaque_keys.edx.keys
import
CourseKey
from
rest_framework
import
serializers
from
course_discovery.apps.publisher.emails
import
send_email_for_studio_instance_created
from
course_discovery.apps.publisher.models
import
CourseRun
class
UpdateCourseKeySerializer
(
serializers
.
ModelSerializer
):
"""Serializer for the `CourseRun` model to update 'lms_course_id'. """
class
Meta
:
model
=
CourseRun
fields
=
(
'lms_course_id'
,
'changed_by'
,)
def
validate
(
self
,
data
):
validated_values
=
super
(
UpdateCourseKeySerializer
,
self
)
.
validate
(
data
)
lms_course_id
=
validated_values
.
get
(
'lms_course_id'
)
try
:
CourseKey
.
from_string
(
lms_course_id
)
except
InvalidKeyError
:
raise
serializers
.
ValidationError
(
'Invalid course key [{}]'
.
format
(
lms_course_id
))
request
=
self
.
context
.
get
(
'request'
)
if
request
:
validated_values
.
update
({
'changed_by'
:
request
.
user
})
return
validated_values
def
update
(
self
,
instance
,
validated_data
):
instance
=
super
(
UpdateCourseKeySerializer
,
self
)
.
update
(
instance
,
validated_data
)
if
waffle
.
switch_is_active
(
'enable_publisher_email_notifications'
):
send_email_for_studio_instance_created
(
instance
)
return
instance
course_discovery/apps/publisher/tests/test_serializers.py
deleted
100644 → 0
View file @
17b1f519
"""Tests Publisher Serializers."""
from
unittest
import
TestCase
from
django.test
import
RequestFactory
from
rest_framework.exceptions
import
ValidationError
from
course_discovery.apps.core.tests.factories
import
UserFactory
from
course_discovery.apps.publisher.serializers
import
UpdateCourseKeySerializer
from
course_discovery.apps.publisher.tests.factories
import
CourseRunFactory
class
UpdateCourseKeySerializerTests
(
TestCase
):
serializer_class
=
UpdateCourseKeySerializer
def
setUp
(
self
):
super
(
UpdateCourseKeySerializerTests
,
self
)
.
setUp
()
self
.
course_run
=
CourseRunFactory
()
self
.
request
=
RequestFactory
()
self
.
user
=
UserFactory
()
self
.
request
.
user
=
self
.
user
def
get_expected_data
(
self
):
return
{
'lms_course_id'
:
self
.
course_run
.
lms_course_id
,
'changed_by'
:
self
.
user
}
def
test_validation
(
self
):
self
.
course_run
.
lms_course_id
=
'course-v1:edxTest+TC101+2016_Q1'
self
.
course_run
.
save
()
# pylint: disable=no-member
serializer
=
self
.
serializer_class
(
self
.
course_run
,
context
=
{
'request'
:
self
.
request
})
expected
=
serializer
.
validate
(
serializer
.
data
)
self
.
assertEqual
(
self
.
get_expected_data
(),
expected
)
def
test_validation_error
(
self
):
self
.
course_run
.
lms_course_id
=
'wrong-course-id'
self
.
course_run
.
save
()
# pylint: disable=no-member
serializer
=
self
.
serializer_class
(
self
.
course_run
)
with
self
.
assertRaises
(
ValidationError
):
serializer
.
validate
(
serializer
.
data
)
course_discovery/apps/publisher/tests/test_views.py
View file @
9d3a782b
...
@@ -10,7 +10,6 @@ from django.db import IntegrityError
...
@@ -10,7 +10,6 @@ from django.db import IntegrityError
from
django.conf
import
settings
from
django.conf
import
settings
from
django.contrib.auth.models
import
Group
from
django.contrib.auth.models
import
Group
from
django.contrib.sites.models
import
Site
from
django.contrib.sites.models
import
Site
from
django.core
import
mail
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.forms
import
model_to_dict
from
django.forms
import
model_to_dict
from
django.test
import
TestCase
from
django.test
import
TestCase
...
@@ -20,14 +19,13 @@ from testfixtures import LogCapture
...
@@ -20,14 +19,13 @@ from testfixtures import LogCapture
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.core.tests.factories
import
UserFactory
,
USER_PASSWORD
from
course_discovery.apps.core.tests.factories
import
UserFactory
,
USER_PASSWORD
from
course_discovery.apps.core.tests.helpers
import
make_image_file
from
course_discovery.apps.core.tests.helpers
import
make_image_file
from
course_discovery.apps.course_metadata.tests
import
toggle_switch
from
course_discovery.apps.course_metadata.tests.factories
import
OrganizationFactory
from
course_discovery.apps.course_metadata.tests.factories
import
OrganizationFactory
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.constants
import
(
from
course_discovery.apps.publisher.constants
import
(
INTERNAL_USER_GROUP_NAME
,
ADMIN_GROUP_NAME
,
PARTNER_COORDINATOR_GROUP_NAME
,
REVIEWER_GROUP_NAME
INTERNAL_USER_GROUP_NAME
,
ADMIN_GROUP_NAME
,
PARTNER_COORDINATOR_GROUP_NAME
,
REVIEWER_GROUP_NAME
)
)
from
course_discovery.apps.publisher.models
import
Course
,
CourseRun
,
Seat
,
State
,
OrganizationExtension
from
course_discovery.apps.publisher.models
import
Course
,
CourseRun
,
Seat
,
State
,
OrganizationExtension
from
course_discovery.apps.publisher.tests
import
factories
,
JSON_CONTENT_TYPE
from
course_discovery.apps.publisher.tests
import
factories
from
course_discovery.apps.publisher.tests.utils
import
create_non_staff_user_and_login
from
course_discovery.apps.publisher.tests.utils
import
create_non_staff_user_and_login
from
course_discovery.apps.publisher.utils
import
is_email_notification_enabled
,
get_internal_users
from
course_discovery.apps.publisher.utils
import
is_email_notification_enabled
,
get_internal_users
from
course_discovery.apps.publisher.views
import
(
from
course_discovery.apps.publisher.views
import
(
...
@@ -1346,89 +1344,6 @@ class ToggleEmailNotificationTests(TestCase):
...
@@ -1346,89 +1344,6 @@ class ToggleEmailNotificationTests(TestCase):
self
.
assertEqual
(
is_email_notification_enabled
(
user
),
is_enabled
)
self
.
assertEqual
(
is_email_notification_enabled
(
user
),
is_enabled
)
class
UpdateCourseKeyViewTests
(
TestCase
):
""" Tests for `UpdateCourseKeyView` """
def
setUp
(
self
):
super
(
UpdateCourseKeyViewTests
,
self
)
.
setUp
()
self
.
course_run
=
factories
.
CourseRunFactory
()
self
.
user
=
UserFactory
(
is_staff
=
True
,
is_superuser
=
True
)
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course_run
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
update_course_key_url
=
reverse
(
'publisher:publisher_course_run_detail'
,
kwargs
=
{
'pk'
:
self
.
course_run
.
id
}
)
# emails send using user course roles
factories
.
CourseUserRoleFactory
(
role
=
PublisherUserRole
.
PartnerCoordinator
,
course
=
self
.
course_run
.
course
,
user
=
self
.
user
)
factories
.
UserAttributeFactory
(
user
=
self
.
user
,
enable_email_notification
=
True
)
toggle_switch
(
'enable_publisher_email_notifications'
,
True
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
def
test_update_course_key_with_errors
(
self
):
""" Test that api returns error with invalid course key."""
invalid_course_id
=
'invalid-course-key'
response
=
self
.
client
.
patch
(
self
.
update_course_key_url
,
data
=
json
.
dumps
({
'lms_course_id'
:
invalid_course_id
}),
content_type
=
JSON_CONTENT_TYPE
)
self
.
assertEqual
(
response
.
status_code
,
400
)
self
.
assertEqual
(
response
.
data
.
get
(
'non_field_errors'
),
[
'Invalid course key [{}]'
.
format
(
invalid_course_id
)]
)
def
test_update_course_key
(
self
):
""" Test that user can update `lms_course_id` for a course run."""
# Verify that `lms_course_id` and `changed_by` are None
self
.
assert_course_key_and_changed_by
()
lms_course_id
=
'course-v1:edxTest+TC12+2050Q1'
response
=
self
.
client
.
patch
(
self
.
update_course_key_url
,
data
=
json
.
dumps
({
'lms_course_id'
:
lms_course_id
}),
content_type
=
JSON_CONTENT_TYPE
)
self
.
assertEqual
(
response
.
status_code
,
200
)
# Verify that `lms_course_id` and `changed_by` are not None
self
.
assert_course_key_and_changed_by
(
lms_course_id
=
lms_course_id
,
changed_by
=
self
.
user
)
# assert email sent
self
.
assert_email_sent
(
reverse
(
'publisher:publisher_course_run_detail'
,
kwargs
=
{
'pk'
:
self
.
course_run
.
id
}),
'Studio instance created'
,
'Studio instance created for the following course run'
)
def
assert_course_key_and_changed_by
(
self
,
lms_course_id
=
None
,
changed_by
=
None
):
self
.
course_run
=
CourseRun
.
objects
.
get
(
id
=
self
.
course_run
.
id
)
self
.
assertEqual
(
self
.
course_run
.
lms_course_id
,
lms_course_id
)
self
.
assertEqual
(
self
.
course_run
.
changed_by
,
changed_by
)
def
assert_email_sent
(
self
,
object_path
,
subject
,
expected_body
):
""" DRY method to assert sent email data"""
self
.
assertEqual
(
len
(
mail
.
outbox
),
1
)
self
.
assertEqual
([
settings
.
PUBLISHER_FROM_EMAIL
],
mail
.
outbox
[
0
]
.
to
)
self
.
assertEqual
([
self
.
user
.
email
],
mail
.
outbox
[
0
]
.
bcc
)
self
.
assertEqual
(
str
(
mail
.
outbox
[
0
]
.
subject
),
subject
)
body
=
mail
.
outbox
[
0
]
.
body
.
strip
()
self
.
assertIn
(
expected_body
,
body
)
page_url
=
'https://{host}{path}'
.
format
(
host
=
Site
.
objects
.
get_current
()
.
domain
.
strip
(
'/'
),
path
=
object_path
)
self
.
assertIn
(
page_url
,
body
)
class
CourseListViewTests
(
TestCase
):
class
CourseListViewTests
(
TestCase
):
""" Tests for `CourseListView` """
""" Tests for `CourseListView` """
...
...
course_discovery/apps/publisher/views.py
View file @
9d3a782b
...
@@ -14,7 +14,6 @@ from django.utils.translation import ugettext_lazy as _
...
@@ -14,7 +14,6 @@ from django.utils.translation import ugettext_lazy as _
from
django.views.generic
import
View
,
CreateView
,
UpdateView
,
DetailView
,
ListView
from
django.views.generic
import
View
,
CreateView
,
UpdateView
,
DetailView
,
ListView
from
django_fsm
import
TransitionNotAllowed
from
django_fsm
import
TransitionNotAllowed
from
guardian.shortcuts
import
get_objects_for_user
from
guardian.shortcuts
import
get_objects_for_user
from
rest_framework.generics
import
UpdateAPIView
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.core.models
import
User
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
...
@@ -26,7 +25,6 @@ from course_discovery.apps.publisher import mixins
...
@@ -26,7 +25,6 @@ from course_discovery.apps.publisher import mixins
from
course_discovery.apps.publisher.models
import
(
from
course_discovery.apps.publisher.models
import
(
Course
,
CourseRun
,
Seat
,
State
,
UserAttributes
,
Course
,
CourseRun
,
Seat
,
State
,
UserAttributes
,
OrganizationExtension
,
CourseUserRole
)
OrganizationExtension
,
CourseUserRole
)
from
course_discovery.apps.publisher.serializers
import
UpdateCourseKeySerializer
from
course_discovery.apps.publisher.utils
import
(
from
course_discovery.apps.publisher.utils
import
(
is_internal_user
,
get_internal_users
,
is_publisher_admin
,
is_internal_user
,
get_internal_users
,
is_publisher_admin
,
is_partner_coordinator_user
is_partner_coordinator_user
...
@@ -149,9 +147,6 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin,
...
@@ -149,9 +147,6 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin,
return
context
return
context
def
patch
(
self
,
*
args
,
**
kwargs
):
return
UpdateCourseKeyView
.
as_view
()(
self
.
request
,
*
args
,
**
kwargs
)
# pylint: disable=attribute-defined-outside-init
# pylint: disable=attribute-defined-outside-init
class
CreateCourseView
(
mixins
.
LoginRequiredMixin
,
CreateView
):
class
CreateCourseView
(
mixins
.
LoginRequiredMixin
,
CreateView
):
...
@@ -430,11 +425,6 @@ class ToggleEmailNotification(mixins.LoginRequiredMixin, View):
...
@@ -430,11 +425,6 @@ class ToggleEmailNotification(mixins.LoginRequiredMixin, View):
return
JsonResponse
({
'is_enabled'
:
is_enabled
})
return
JsonResponse
({
'is_enabled'
:
is_enabled
})
class
UpdateCourseKeyView
(
mixins
.
LoginRequiredMixin
,
mixins
.
ViewPermissionMixin
,
UpdateAPIView
):
queryset
=
CourseRun
.
objects
.
all
()
serializer_class
=
UpdateCourseKeySerializer
class
CourseListView
(
mixins
.
LoginRequiredMixin
,
ListView
):
class
CourseListView
(
mixins
.
LoginRequiredMixin
,
ListView
):
""" Course List View."""
""" Course List View."""
template_name
=
'publisher/courses.html'
template_name
=
'publisher/courses.html'
...
...
course_discovery/static/js/publisher/views/dashboard.js
View file @
9d3a782b
...
@@ -13,7 +13,7 @@ $(document).ready(function() {
...
@@ -13,7 +13,7 @@ $(document).ready(function() {
return
;
return
;
}
}
var
courseRunPageURL
=
$
(
this
).
data
(
'courseRunU
rl'
),
var
updateCourseKeyURL
=
$
(
this
).
data
(
'update-course-key-u
rl'
),
courseKeyValue
=
courseKeyInput
.
val
().
trim
(),
courseKeyValue
=
courseKeyInput
.
val
().
trim
(),
courseTitleTag
=
$courseRunParentTag
.
find
(
"#course-title"
).
html
().
trim
(),
courseTitleTag
=
$courseRunParentTag
.
find
(
"#course-title"
).
html
().
trim
(),
startDateTag
=
$courseRunParentTag
.
find
(
"#course-start"
).
html
().
trim
(),
startDateTag
=
$courseRunParentTag
.
find
(
"#course-start"
).
html
().
trim
(),
...
@@ -29,7 +29,7 @@ $(document).ready(function() {
...
@@ -29,7 +29,7 @@ $(document).ready(function() {
e
.
preventDefault
();
e
.
preventDefault
();
$
.
ajax
({
$
.
ajax
({
url
:
courseRunPage
URL
,
url
:
updateCourseKey
URL
,
type
:
"PATCH"
,
type
:
"PATCH"
,
data
:
JSON
.
stringify
({
lms_course_id
:
courseKeyValue
}),
data
:
JSON
.
stringify
({
lms_course_id
:
courseKeyValue
}),
contentType
:
"application/json"
,
contentType
:
"application/json"
,
...
...
course_discovery/templates/publisher/dashboard/_studio_requests.html
View file @
9d3a782b
...
@@ -44,7 +44,7 @@
...
@@ -44,7 +44,7 @@
</td>
</td>
<td
class=
"form-group"
>
<td
class=
"form-group"
>
<input
type=
"text"
class=
"field-input input-text small"
aria-labelledby=
"course-title-{{ course_run.title }} column-title"
/>
<input
type=
"text"
class=
"field-input input-text small"
aria-labelledby=
"course-title-{{ course_run.title }} column-title"
/>
<button
data-
course-run-url=
"{{ run_page_url }
}"
class=
"btn-inline btn-add-course-key"
>
{% trans "Add" %}
</button>
<button
data-
update-course-key-url=
"{% url 'publisher:api:update_course_key' course_run.id %
}"
class=
"btn-inline btn-add-course-key"
>
{% trans "Add" %}
</button>
</td>
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
...
...
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