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
c9ccb22f
Commit
c9ccb22f
authored
Dec 28, 2016
by
Awais Qureshi
Committed by
GitHub
Dec 28, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #502 from edx/awais786/ECOM-6628-org-ext-permissions
Publisher app: Add/Remove Permissions.
parents
8d4cadfb
626ea12f
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
314 additions
and
193 deletions
+314
-193
course_discovery/apps/publisher/api/permissions.py
+2
-2
course_discovery/apps/publisher/api/tests/test_views.py
+6
-15
course_discovery/apps/publisher/emails.py
+2
-2
course_discovery/apps/publisher/forms.py
+2
-2
course_discovery/apps/publisher/migrations/0022_auto_20161222_2135.py
+19
-0
course_discovery/apps/publisher/mixins.py
+28
-4
course_discovery/apps/publisher/models.py
+7
-12
course_discovery/apps/publisher/tests/test_emails.py
+18
-8
course_discovery/apps/publisher/tests/test_model.py
+31
-29
course_discovery/apps/publisher/tests/test_utils.py
+59
-1
course_discovery/apps/publisher/tests/test_views.py
+110
-98
course_discovery/apps/publisher/views.py
+20
-10
course_discovery/apps/publisher_comments/emails.py
+1
-1
course_discovery/apps/publisher_comments/tests/test_emails.py
+9
-8
course_discovery/apps/publisher_comments/tests/test_views.py
+0
-1
No files found.
course_discovery/apps/publisher/api/permissions.py
View file @
c9ccb22f
from
rest_framework.permissions
import
BasePermission
from
course_discovery.apps.publisher.mixins
import
check_
view_permission
from
course_discovery.apps.publisher.mixins
import
check_
user_course_access
from
course_discovery.apps.publisher.utils
import
is_internal_user
...
...
@@ -8,7 +8,7 @@ class CanViewAssociatedCourse(BasePermission):
""" Permission class to check user can view a publisher course. """
def
has_object_permission
(
self
,
request
,
view
,
obj
):
return
check_
view_permission
(
request
.
user
,
obj
.
course
)
return
check_
user_course_access
(
request
.
user
,
obj
.
course
)
class
InternalUserPermission
(
BasePermission
):
...
...
course_discovery/apps/publisher/api/tests/test_views.py
View file @
c9ccb22f
...
...
@@ -5,13 +5,10 @@ import ddt
from
django.contrib.auth.models
import
Group
from
django.core.urlresolvers
import
reverse
from
django.test
import
TestCase
from
guardian.shortcuts
import
assign_perm
from
course_discovery.apps.core.tests.factories
import
UserFactory
,
USER_PASSWORD
from
course_discovery.apps.course_metadata.tests.factories
import
OrganizationFactory
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.constants
import
INTERNAL_USER_GROUP_NAME
from
course_discovery.apps.publisher.models
import
Course
from
course_discovery.apps.publisher.tests
import
factories
,
JSON_CONTENT_TYPE
...
...
@@ -33,10 +30,8 @@ class CourseRoleAssignmentViewTests(TestCase):
self
.
other_internal_users
.
append
(
user
)
internal_user_group
.
user_set
.
add
(
user
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
internal_user_group
,
self
.
course
)
organization
=
OrganizationFactory
()
self
.
course
.
organizations
.
add
(
organization
)
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course
.
organizations
.
add
(
organization_extension
.
organization
)
# Create three internal user course roles for internal users against a course
# so we can test change role assignment on these roles.
...
...
@@ -54,7 +49,6 @@ class CourseRoleAssignmentViewTests(TestCase):
""" Verify non-internal users cannot change role assignments. """
non_internal_user
=
UserFactory
()
assign_perm
(
Course
.
VIEW_PERMISSION
,
non_internal_user
,
self
.
course
)
self
.
client
.
logout
()
self
.
client
.
login
(
username
=
non_internal_user
.
username
,
password
=
USER_PASSWORD
)
...
...
@@ -103,15 +97,12 @@ class OrganizationGroupUserViewTests(TestCase):
user
=
UserFactory
.
create
(
username
=
"test_user"
,
password
=
USER_PASSWORD
)
self
.
client
.
login
(
username
=
user
.
username
,
password
=
USER_PASSWORD
)
# create group and add test users in the group
group
=
factories
.
GroupFactory
()
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
org_user1
=
UserFactory
.
create
(
full_name
=
"org user1"
)
self
.
org_user2
=
UserFactory
.
create
(
full_name
=
"org user2"
)
group
.
user_set
.
add
(
self
.
org_user1
)
group
.
user_set
.
add
(
self
.
org_user2
)
self
.
organization
=
OrganizationFactory
()
factories
.
OrganizationExtensionFactory
.
create
(
organization
=
self
.
organization
,
group
=
group
)
organization_extension
.
group
.
user_set
.
add
(
self
.
org_user1
)
organization_extension
.
group
.
user_set
.
add
(
self
.
org_user2
)
self
.
organization
=
organization_extension
.
organization
def
test_get_organization_user_group
(
self
):
""" Verify that view returns list of users associated with the group
...
...
course_discovery/apps/publisher/emails.py
View file @
c9ccb22f
...
...
@@ -22,7 +22,7 @@ def send_email_for_change_state(course_run):
txt_template
=
'publisher/email/change_state.txt'
html_template
=
'publisher/email/change_state.html'
to_addresses
=
course_run
.
course
.
get_
group
_users_emails
()
to_addresses
=
course_run
.
course
.
get_
course
_users_emails
()
from_address
=
settings
.
PUBLISHER_FROM_EMAIL
page_path
=
reverse
(
'publisher:publisher_course_run_detail'
,
kwargs
=
{
'pk'
:
course_run
.
id
})
context
=
{
...
...
@@ -61,7 +61,7 @@ def send_email_for_studio_instance_created(course_run):
object_path
=
reverse
(
'publisher:publisher_course_run_detail'
,
kwargs
=
{
'pk'
:
course_run
.
id
})
subject
=
_
(
'Studio instance created'
)
to_addresses
=
course_run
.
course
.
get_
group
_users_emails
()
to_addresses
=
course_run
.
course
.
get_
course
_users_emails
()
from_address
=
settings
.
PUBLISHER_FROM_EMAIL
context
=
{
...
...
course_discovery/apps/publisher/forms.py
View file @
c9ccb22f
...
...
@@ -53,7 +53,7 @@ class CustomCourseForm(CourseForm):
)
title
=
forms
.
CharField
(
label
=
_
(
'Course Title'
),
required
=
True
)
number
=
forms
.
CharField
(
label
=
_
(
'Course Number'
),
required
=
True
)
team_admin
=
forms
.
ModelChoiceField
(
queryset
=
User
.
objects
.
filter
(
is_staff
=
True
),
required
=
True
)
team_admin
=
forms
.
ModelChoiceField
(
queryset
=
User
.
objects
.
all
(
),
required
=
True
)
class
Meta
(
CourseForm
.
Meta
):
model
=
Course
...
...
@@ -69,7 +69,7 @@ class UpdateCourseForm(BaseCourseForm):
""" Course form to update specific fields for already created course. """
number
=
forms
.
CharField
(
label
=
_
(
'Course Number'
),
required
=
True
)
team_admin
=
forms
.
ModelChoiceField
(
queryset
=
User
.
objects
.
filter
(
is_staff
=
True
),
required
=
True
)
team_admin
=
forms
.
ModelChoiceField
(
queryset
=
User
.
objects
.
all
(
),
required
=
True
)
class
Meta
:
model
=
Course
...
...
course_discovery/apps/publisher/migrations/0022_auto_20161222_2135.py
0 → 100644
View file @
c9ccb22f
# -*- coding: utf-8 -*-
# Generated by Django 1.9.11 on 2016-12-22 21:35
from
__future__
import
unicode_literals
from
django.db
import
migrations
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'publisher'
,
'0021_auto_20161214_1356'
),
]
operations
=
[
migrations
.
AlterModelOptions
(
name
=
'organizationextension'
,
options
=
{
'get_latest_by'
:
'modified'
,
'ordering'
:
(
'-modified'
,
'-created'
),
'permissions'
:
((
'edit_course_run'
,
'Can edit course run'
),
(
'publisher_view_course'
,
'Can view course'
),
(
'publisher_view_course_run'
,
'Can view the course run'
))},
),
]
course_discovery/apps/publisher/mixins.py
View file @
c9ccb22f
...
...
@@ -2,7 +2,8 @@ from django.contrib.auth.decorators import login_required
from
django.http
import
HttpResponseForbidden
,
HttpResponseRedirect
from
django.utils.decorators
import
method_decorator
from
course_discovery.apps.publisher.models
import
Course
,
Seat
from
course_discovery.apps.publisher.models
import
Course
,
Seat
,
OrganizationExtension
from
course_discovery.apps.publisher.utils
import
is_publisher_admin
,
is_internal_user
class
ViewPermissionMixin
(
object
):
...
...
@@ -20,7 +21,7 @@ class ViewPermissionMixin(object):
def
check_user
(
self
,
user
):
course
=
self
.
get_course
()
return
check_
view_permission
(
user
,
course
)
return
check_
user_course_access
(
user
,
course
)
def
permission_failed
(
self
):
return
HttpResponseForbidden
()
...
...
@@ -56,5 +57,28 @@ class FormValidMixin(object):
return
HttpResponseRedirect
(
self
.
get_success_url
())
def
check_view_permission
(
user
,
course
):
return
user
.
is_staff
or
user
.
has_perm
(
Course
.
VIEW_PERMISSION
,
course
)
def
check_roles_access
(
user
):
""" Return True if user is part of a role that gives implicit access. """
if
is_publisher_admin
(
user
)
or
is_internal_user
(
user
):
return
True
return
False
def
check_course_organization_permission
(
user
,
course
):
""" Return True if user has view permission on organization. """
if
not
hasattr
(
course
,
'organizations'
):
return
False
return
any
(
[
user
.
has_perm
(
OrganizationExtension
.
VIEW_COURSE
,
org
.
organization_extension
)
for
org
in
course
.
organizations
.
all
()
]
)
def
check_user_course_access
(
user
,
course
):
""" Return True if user is admin/internal user or has access permission. """
return
check_roles_access
(
user
)
or
check_course_organization_permission
(
user
,
course
)
course_discovery/apps/publisher/models.py
View file @
c9ccb22f
...
...
@@ -8,7 +8,6 @@ from django.dispatch import receiver
from
django.utils.translation
import
ugettext_lazy
as
_
from
django_extensions.db.models
import
TimeStampedModel
from
django_fsm
import
FSMField
,
transition
from
guardian.shortcuts
import
assign_perm
,
get_users_with_perms
from
simple_history.models
import
HistoricalRecords
from
sortedm2m.fields
import
SortedManyToManyField
from
stdimage.models
import
StdImageField
...
...
@@ -85,7 +84,6 @@ class State(TimeStampedModel, ChangedByMixin):
class
Course
(
TimeStampedModel
,
ChangedByMixin
):
""" Publisher Course model. It contains fields related to the course intake form."""
VIEW_PERMISSION
=
'view_course'
title
=
models
.
CharField
(
max_length
=
255
,
default
=
None
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Course title'
))
number
=
models
.
CharField
(
max_length
=
50
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Course number'
))
...
...
@@ -152,21 +150,14 @@ class Course(TimeStampedModel, ChangedByMixin):
(
'view_course'
,
'Can view course'
),
)
def
assign_permission_by_group
(
self
,
group
):
""" Assigns permission on the course against the group. """
assign_perm
(
self
.
VIEW_PERMISSION
,
group
,
self
)
def
get_group_users_emails
(
self
):
def
get_course_users_emails
(
self
):
""" Returns the list of users emails with enable email notifications
against a course
group
. By default if attribute value does not exists
against a course. By default if attribute value does not exists
then user will be eligible for emails.
Also get users from course-user-role table.
"""
users_list_perms
=
get_users_with_perms
(
self
)
users_list_roles
=
[
obj
.
user
for
obj
in
self
.
course_user_roles
.
all
()]
users_list
=
set
(
list
(
users_list_perms
)
+
list
(
users_list_roles
))
emails
=
[
user
.
email
for
user
in
users_list
if
is_email_notification_enabled
(
user
)]
emails
=
[
user
.
email
for
user
in
users_list_roles
if
is_email_notification_enabled
(
user
)]
return
emails
...
...
@@ -416,6 +407,8 @@ class CourseUserRole(TimeStampedModel, ChangedByMixin):
class
OrganizationExtension
(
TimeStampedModel
):
""" Organization-Extension relation model. """
EDIT_COURSE_RUN
=
'edit_course_run'
VIEW_COURSE
=
'publisher_view_course'
VIEW_COURSE_RUN
=
'publisher_view_course_run'
organization
=
models
.
OneToOneField
(
Organization
,
related_name
=
'organization_extension'
)
group
=
models
.
OneToOneField
(
Group
,
related_name
=
'organization_extension'
)
...
...
@@ -425,6 +418,8 @@ class OrganizationExtension(TimeStampedModel):
class
Meta
(
TimeStampedModel
.
Meta
):
permissions
=
(
(
'edit_course_run'
,
'Can edit course run'
),
(
'publisher_view_course'
,
'Can view course'
),
(
'publisher_view_course_run'
,
'Can view the course run'
),
)
def
__str__
(
self
):
...
...
course_discovery/apps/publisher/tests/test_emails.py
View file @
c9ccb22f
...
...
@@ -6,7 +6,6 @@ from django.contrib.sites.models import Site
from
django.core.urlresolvers
import
reverse
from
django.test
import
TestCase
from
django.core
import
mail
from
guardian.shortcuts
import
assign_perm
import
pytz
import
mock
from
testfixtures
import
LogCapture
...
...
@@ -14,7 +13,8 @@ from testfixtures import LogCapture
from
course_discovery.apps.core.tests.factories
import
UserFactory
from
course_discovery.apps.course_metadata.tests
import
toggle_switch
from
course_discovery.apps.publisher
import
emails
from
course_discovery.apps.publisher.models
import
State
,
Course
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.models
import
State
,
CourseUserRole
from
course_discovery.apps.publisher.tests
import
factories
from
course_discovery.apps.publisher.tests.factories
import
UserAttributeFactory
...
...
@@ -42,7 +42,16 @@ class StateChangeEmailTests(TestCase):
cls
.
course_run
=
cls
.
seat
.
course_run
cls
.
course
=
cls
.
course_run
.
course
assign_perm
(
Course
.
VIEW_PERMISSION
,
cls
.
group
,
cls
.
course
)
# add user in course-user-role table
factories
.
CourseUserRoleFactory
(
course
=
cls
.
course
,
role
=
PublisherUserRole
.
PartnerCoordinator
,
user
=
cls
.
user
)
factories
.
CourseUserRoleFactory
(
course
=
cls
.
course
,
role
=
PublisherUserRole
.
MarketingReviewer
,
user
=
cls
.
user_2
)
factories
.
CourseUserRoleFactory
(
course
=
cls
.
course
,
role
=
PublisherUserRole
.
Publisher
,
user
=
cls
.
user_3
)
# NOTE: We intentionally do NOT create an attribute for user_2.
# By default this user WILL receive email notifications.
...
...
@@ -94,10 +103,8 @@ class StateChangeEmailTests(TestCase):
State
.
FINALIZED
,
State
.
PUBLISHED
,
State
.
DRAFT
)
def
test_email_without_group
(
self
,
target_state
):
""" Verify that no email send if course group has no users. """
self
.
user
.
groups
.
remove
(
self
.
group
)
self
.
user_2
.
groups
.
remove
(
self
.
group
)
self
.
user_3
.
groups
.
remove
(
self
.
group
)
""" Verify that no email send if course user role has no users. """
CourseUserRole
.
objects
.
all
()
.
delete
()
self
.
course_run
.
change_state
(
target
=
target_state
)
self
.
assertEqual
(
len
(
mail
.
outbox
),
0
)
...
...
@@ -138,7 +145,10 @@ class StudioInstanceCreatedEmailTests(TestCase):
self
.
course_run
=
factories
.
CourseRunFactory
()
assign_perm
(
Course
.
VIEW_PERMISSION
,
self
.
group
,
self
.
course_run
.
course
)
# add user in course-user-role table
factories
.
CourseUserRoleFactory
(
course
=
self
.
course_run
.
course
,
role
=
PublisherUserRole
.
PartnerCoordinator
,
user
=
self
.
user
)
UserAttributeFactory
(
user
=
self
.
user
,
enable_email_notification
=
True
)
...
...
course_discovery/apps/publisher/tests/test_model.py
View file @
c9ccb22f
...
...
@@ -4,12 +4,13 @@ from django.db import IntegrityError
from
django.core.urlresolvers
import
reverse
from
django.test
import
TestCase
from
django_fsm
import
TransitionNotAllowed
from
guardian.shortcuts
import
get_groups_with_perms
from
guardian.shortcuts
import
assign_perm
from
course_discovery.apps.core.tests.factories
import
UserFactory
from
course_discovery.apps.publisher.choices
import
PublisherUserRole
from
course_discovery.apps.publisher.mixins
import
check_course_organization_permission
from
course_discovery.apps.publisher.models
import
(
State
,
Course
,
Course
UserRole
,
OrganizationExtension
,
OrganizationUserRole
State
,
CourseUserRole
,
OrganizationExtension
,
OrganizationUserRole
)
from
course_discovery.apps.publisher.tests
import
factories
...
...
@@ -80,6 +81,19 @@ class CourseTests(TestCase):
self
.
course
.
organizations
.
add
(
self
.
org_extension_1
.
organization
)
self
.
course2
.
organizations
.
add
(
self
.
org_extension_2
.
organization
)
# add user in course-user-role table
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
role
=
PublisherUserRole
.
PartnerCoordinator
,
user
=
self
.
user1
)
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
role
=
PublisherUserRole
.
MarketingReviewer
,
user
=
self
.
user2
)
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
role
=
PublisherUserRole
.
Publisher
,
user
=
self
.
user3
)
def
test_str
(
self
):
""" Verify casting an instance to a string returns a string containing the course title. """
self
.
assertEqual
(
str
(
self
.
course
),
self
.
course
.
title
)
...
...
@@ -90,13 +104,16 @@ class CourseTests(TestCase):
reverse
(
'publisher:publisher_courses_edit'
,
kwargs
=
{
'pk'
:
self
.
course
.
id
})
)
def
test_assign_permission_
by_group
(
self
):
""" Verify that permission can be assigned using the
group
. """
def
test_assign_permission_
organization_extension
(
self
):
""" Verify that permission can be assigned using the
organization extension
. """
self
.
assert_user_cannot_view_course
(
self
.
user1
,
self
.
course
)
self
.
assert_user_cannot_view_course
(
self
.
user2
,
self
.
course2
)
self
.
course
.
assign_permission_by_group
(
self
.
org_extension_1
.
group
)
self
.
course2
.
assign_permission_by_group
(
self
.
org_extension_2
.
group
)
self
.
course
.
organizations
.
add
(
self
.
org_extension_1
.
organization
)
self
.
course2
.
organizations
.
add
(
self
.
org_extension_2
.
organization
)
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
self
.
user1
,
self
.
org_extension_1
)
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
self
.
user2
,
self
.
org_extension_2
)
self
.
assert_user_can_view_course
(
self
.
user1
,
self
.
course
)
self
.
assert_user_can_view_course
(
self
.
user2
,
self
.
course2
)
...
...
@@ -109,39 +126,24 @@ class CourseTests(TestCase):
def
assert_user_cannot_view_course
(
self
,
user
,
course
):
""" Asserts the user can NOT view the course. """
self
.
assertFalse
(
user
.
has_perm
(
Course
.
VIEW_PERMISSION
,
course
))
self
.
assertFalse
(
check_course_organization_permission
(
user
,
course
,
))
def
assert_user_can_view_course
(
self
,
user
,
course
):
""" Asserts the user can view the course. """
self
.
assertTrue
(
user
.
has_perm
(
Course
.
VIEW_PERMISSION
,
course
))
self
.
assertTrue
(
check_course_organization_permission
(
user
,
course
))
def
test_group_by_permission
(
self
):
""" Verify the method returns groups permitted to access the course."""
self
.
assertFalse
(
get_groups_with_perms
(
self
.
course
))
self
.
course
.
assign_permission_by_group
(
self
.
org_extension_1
.
group
)
self
.
assertEqual
(
get_groups_with_perms
(
self
.
course
)[
0
],
self
.
org_extension_1
.
group
)
def
test_get_group_users_emails
(
self
):
def
test_get_course_users_emails
(
self
):
""" Verify the method returns the email addresses of users who are
permitted to access the course AND have not disabled email notifications.
"""
self
.
user3
.
groups
.
add
(
self
.
org_extension_1
.
group
)
self
.
course
.
assign_permission_by_group
(
self
.
org_extension_1
.
group
)
self
.
assertListEqual
(
self
.
course
.
get_group_users_emails
(),
[
self
.
user1
.
email
,
self
.
user3
.
email
])
# add user in course-user-role table
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
role
=
PublisherUserRole
.
PartnerCoordinator
,
user
=
self
.
user2
)
self
.
assertListEqual
(
self
.
course
.
get_
group
_users_emails
(),
self
.
course
.
get_
course
_users_emails
(),
[
self
.
user1
.
email
,
self
.
user2
.
email
,
self
.
user3
.
email
]
)
# The email addresses of users who have disabled email notifications should NOT be returned.
factories
.
UserAttributeFactory
(
user
=
self
.
user1
,
enable_email_notification
=
False
)
self
.
assertListEqual
(
self
.
course
.
get_
group
_users_emails
(),
[
self
.
user2
.
email
,
self
.
user3
.
email
])
self
.
assertListEqual
(
self
.
course
.
get_
course
_users_emails
(),
[
self
.
user2
.
email
,
self
.
user3
.
email
])
def
test_keywords_data
(
self
):
""" Verify that the property returns the keywords as comma separated string. """
...
...
@@ -155,13 +157,13 @@ class CourseTests(TestCase):
def
test_partner_coordinator
(
self
):
""" Verify that the partner_coordinator property returns user if exist. """
self
.
assertIsNone
(
self
.
course
.
partner_coordinator
)
self
.
assertIsNone
(
self
.
course
2
.
partner_coordinator
)
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
user
=
self
.
user1
,
role
=
PublisherUserRole
.
PartnerCoordinator
course
=
self
.
course
2
,
user
=
self
.
user1
,
role
=
PublisherUserRole
.
PartnerCoordinator
)
self
.
assertEqual
(
self
.
user1
,
self
.
course
.
partner_coordinator
)
self
.
assertEqual
(
self
.
user1
,
self
.
course
2
.
partner_coordinator
)
class
SeatTests
(
TestCase
):
...
...
course_discovery/apps/publisher/tests/test_utils.py
View file @
c9ccb22f
""" Tests publisher.utils"""
from
django.contrib.auth.models
import
Group
from
django.test
import
TestCase
from
guardian.shortcuts
import
assign_perm
from
course_discovery.apps.core.tests.factories
import
UserFactory
from
course_discovery.apps.publisher.constants
import
(
ADMIN_GROUP_NAME
,
INTERNAL_USER_GROUP_NAME
,
PARTNER_COORDINATOR_GROUP_NAME
)
from
course_discovery.apps.publisher.mixins
import
(
check_roles_access
,
check_course_organization_permission
,
check_user_course_access
)
from
course_discovery.apps.publisher.models
import
OrganizationExtension
from
course_discovery.apps.publisher.tests
import
factories
from
course_discovery.apps.publisher.utils
import
(
is_email_notification_enabled
,
is_publisher_admin
,
is_internal_user
,
...
...
@@ -18,7 +23,12 @@ class PublisherUtilsTests(TestCase):
def
setUp
(
self
):
super
(
PublisherUtilsTests
,
self
)
.
setUp
()
self
.
user
=
UserFactory
(
is_staff
=
True
,
is_superuser
=
True
)
self
.
user
=
UserFactory
()
self
.
course
=
factories
.
CourseFactory
()
self
.
admin_group
=
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
)
self
.
internal_user_group
=
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
)
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
def
test_email_notification_enabled_by_default
(
self
):
""" Test email notification is enabled for the user by default."""
...
...
@@ -82,3 +92,51 @@ class PublisherUtilsTests(TestCase):
partner_coordinator_group
=
Group
.
objects
.
get
(
name
=
PARTNER_COORDINATOR_GROUP_NAME
)
self
.
user
.
groups
.
add
(
partner_coordinator_group
)
self
.
assertTrue
(
is_partner_coordinator_user
(
self
.
user
))
def
test_check_roles_access_with_admin
(
self
):
""" Verify the function returns a boolean indicating if the user
access role wise.
"""
self
.
assertFalse
(
check_roles_access
(
self
.
user
))
self
.
user
.
groups
.
add
(
self
.
admin_group
)
self
.
assertTrue
(
check_roles_access
(
self
.
user
))
def
test_check_roles_access_with_internal_user
(
self
):
""" Verify the function returns a boolean indicating if the user
access role wise.
"""
self
.
assertFalse
(
check_roles_access
(
self
.
user
))
self
.
user
.
groups
.
add
(
self
.
internal_user_group
)
self
.
assertTrue
(
check_roles_access
(
self
.
user
))
def
test_check_organization_permission_without_org
(
self
):
""" Verify the function returns a boolean indicating if the user has
organization permission on given course.
"""
self
.
assertFalse
(
check_course_organization_permission
(
self
.
user
,
self
.
course
))
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
self
.
user
,
self
.
organization_extension
)
self
.
assertTrue
(
check_course_organization_permission
(
self
.
user
,
self
.
course
))
def
test_check_user_access_with_roles
(
self
):
""" Verify the function returns a boolean indicating if the user
organization permission on given course or user is internal or admin user.
"""
self
.
assertFalse
(
check_user_course_access
(
self
.
user
,
self
.
course
))
self
.
user
.
groups
.
add
(
self
.
admin_group
)
self
.
assertTrue
(
check_user_course_access
(
self
.
user
,
self
.
course
))
self
.
user
.
groups
.
remove
(
self
.
admin_group
)
self
.
assertFalse
(
check_user_course_access
(
self
.
user
,
self
.
course
))
self
.
user
.
groups
.
add
(
self
.
internal_user_group
)
self
.
assertTrue
(
check_user_course_access
(
self
.
user
,
self
.
course
))
def
test_check_user_access_with_permission
(
self
):
""" Verify the function returns a boolean indicating if the user
has view permission on organization
"""
self
.
assertFalse
(
check_course_organization_permission
(
self
.
user
,
self
.
course
))
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
self
.
user
,
self
.
organization_extension
)
self
.
assertTrue
(
check_course_organization_permission
(
self
.
user
,
self
.
course
))
course_discovery/apps/publisher/tests/test_views.py
View file @
c9ccb22f
...
...
@@ -43,7 +43,7 @@ class CreateUpdateCourseViewTests(TestCase):
def
setUp
(
self
):
super
(
CreateUpdateCourseViewTests
,
self
)
.
setUp
()
self
.
user
=
UserFactory
(
is_staff
=
True
,
is_superuser
=
True
)
self
.
user
=
UserFactory
()
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
group
=
self
.
organization_extension
.
group
...
...
@@ -51,7 +51,7 @@ class CreateUpdateCourseViewTests(TestCase):
self
.
course_run
=
factories
.
CourseRunFactory
(
course
=
self
.
course
)
self
.
seat
=
factories
.
SeatFactory
(
course_run
=
self
.
course_run
,
type
=
Seat
.
VERIFIED
,
price
=
2
)
self
.
user
.
groups
.
add
(
self
.
organization_extension
.
group
)
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
site
=
Site
.
objects
.
get
(
pk
=
settings
.
SITE_ID
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
self
.
start_date_time
=
datetime
.
now
()
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
...
...
@@ -90,6 +90,7 @@ class CreateUpdateCourseViewTests(TestCase):
""" Verify that new course, course run and seat can be created
with different data sets.
"""
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
self
.
_assert_records
(
1
)
course_dict
=
self
.
_post_data
(
data
,
self
.
course
,
self
.
course_run
,
self
.
seat
)
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_courses_new'
),
course_dict
,
files
=
data
[
'image'
])
...
...
@@ -107,15 +108,16 @@ class CreateUpdateCourseViewTests(TestCase):
self
.
_assert_records
(
1
)
data
=
{
'number'
:
'course_2'
,
'image'
:
make_image_file
(
'test_banner.jpg'
)}
course_dict
=
self
.
_post_data
(
data
,
self
.
course
,
self
.
course_run
,
self
.
seat
)
with
patch
.
object
(
Course
,
"
assign_permission_by_group
"
)
as
mock_method
:
with
patch
.
object
(
Course
,
"
save
"
)
as
mock_method
:
mock_method
.
side_effect
=
IntegrityError
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_courses_new'
),
course_dict
,
files
=
data
[
'image'
])
self
.
assertEqual
(
response
.
status_code
,
400
)
self
.
_assert_records
(
1
)
def
test_update_course_with_staff
(
self
):
""" Verify that staff user can update an existing course. """
def
test_update_course_with_admin
(
self
):
""" Verify that publisher admin can update an existing course. """
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
course_dict
=
model_to_dict
(
self
.
course
)
course_dict
.
pop
(
'verification_deadline'
)
course_dict
.
pop
(
'image'
)
...
...
@@ -149,9 +151,8 @@ class CreateUpdateCourseViewTests(TestCase):
self
.
assertContains
(
response
,
'Add new comment'
)
self
.
assertContains
(
response
,
comment
.
comment
)
def
test_course_edit_page_with_non_staff
(
self
):
""" Verify that non staff user can't access course edit page without permission. """
non_staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
def
test_course_edit_page_without_admin_rights
(
self
):
""" Verify that non publisher admin user can't access course edit page without rights. """
course_dict
=
model_to_dict
(
self
.
course
)
updated_course_title
=
'Updated {}'
.
format
(
self
.
course
.
title
)
...
...
@@ -163,19 +164,15 @@ class CreateUpdateCourseViewTests(TestCase):
self
.
assertEqual
(
response
.
status_code
,
403
)
# assign user a group and assign view permission on that group
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course
)
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
response
=
self
.
client
.
get
(
reverse
(
'publisher:publisher_courses_edit'
,
kwargs
=
{
'pk'
:
self
.
course
.
id
})
)
self
.
assertEqual
(
response
.
status_code
,
200
)
def
test_update_course_with
_non_staff
(
self
):
def
test_update_course_with
out_admin_rights
(
self
):
""" Tests for update course with non staff user. """
non_staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
course_dict
=
model_to_dict
(
self
.
course
)
course_dict
.
pop
(
'verification_deadline'
)
course_dict
.
pop
(
'image'
)
...
...
@@ -192,10 +189,7 @@ class CreateUpdateCourseViewTests(TestCase):
# verify that non staff user can't update course without permission
self
.
assertEqual
(
response
.
status_code
,
403
)
# assign user a group and assign view permission on that group
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course
)
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_courses_edit'
,
kwargs
=
{
'pk'
:
self
.
course
.
id
}),
course_dict
...
...
@@ -238,6 +232,7 @@ class CreateUpdateCourseViewTests(TestCase):
@ddt.data
(
Seat
.
AUDIT
,
Seat
.
HONOR
)
def
test_create_course_without_price_with_success
(
self
,
seat_type
):
""" Verify that if seat type is honor/audit then price is not required. """
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
self
.
_assert_records
(
1
)
data
=
{
'number'
:
'course_1'
,
'image'
:
''
}
course_dict
=
self
.
_post_data
(
data
,
self
.
course
,
self
.
course_run
,
self
.
seat
)
...
...
@@ -290,7 +285,6 @@ class CreateUpdateCourseViewTests(TestCase):
)
self
.
assertEqual
(
course
.
organizations
.
first
(),
self
.
organization_extension
.
organization
)
self
.
assertEqual
(
course
.
team_admin
,
self
.
user
)
self
.
assertTrue
(
self
.
user
.
has_perm
(
Course
.
VIEW_PERMISSION
,
course
))
course_run
=
course
.
publisher_course_runs
.
all
()[
0
]
self
.
assertEqual
(
self
.
course_run
.
language
,
course_run
.
language
)
self
.
assertEqual
(
course_run
.
start
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
),
self
.
start_date_time
)
...
...
@@ -311,9 +305,11 @@ class CreateUpdateCourseRunViewTests(TestCase):
def
setUp
(
self
):
super
(
CreateUpdateCourseRunViewTests
,
self
)
.
setUp
()
self
.
user
=
UserFactory
(
is_staff
=
True
,
is_superuser
=
True
)
self
.
user
=
UserFactory
()
self
.
course
=
factories
.
CourseFactory
(
team_admin
=
self
.
user
)
self
.
course_run
=
factories
.
CourseRunFactory
()
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
course_run_dict
=
model_to_dict
(
self
.
course_run
)
self
.
course_run_dict
.
update
(
{
'number'
:
self
.
course
.
number
,
'team_admin'
:
self
.
course
.
team_admin
.
id
,
'is_self_paced'
:
True
}
...
...
@@ -398,6 +394,7 @@ class CreateUpdateCourseRunViewTests(TestCase):
def
test_create_course_run_and_seat
(
self
):
""" Verify that we can create a new course run with seat. """
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
updated_course_number
=
'{number}.2'
.
format
(
number
=
self
.
course
.
number
)
new_price
=
450
post_data
=
self
.
course_run_dict
...
...
@@ -411,7 +408,7 @@ class CreateUpdateCourseRunViewTests(TestCase):
}
)
self
.
_pop_valuse_from_dict
(
post_data
,
[
'id'
,
'course'
,
'course_run'
])
assign_perm
(
OrganizationExtension
.
VIEW_COURSE_RUN
,
self
.
user
,
self
.
organization_extension
)
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_course_runs_new'
,
kwargs
=
{
'parent_course_id'
:
self
.
course
.
id
}),
post_data
...
...
@@ -436,13 +433,14 @@ class CreateUpdateCourseRunViewTests(TestCase):
# Verify that number is updated for parent course
self
.
assertEqual
(
self
.
course
.
number
,
updated_course_number
)
def
test_update_course_run_with_
staff
(
self
):
""" Verify that
staff
user can update an existing course run. """
def
test_update_course_run_with_
internal_user
(
self
):
""" Verify that
internal
user can update an existing course run. """
updated_lms_course_id
=
'course-v1:testX+AS121+2018_q1'
self
.
course_run_dict
[
'lms_course_id'
]
=
updated_lms_course_id
self
.
assertNotEqual
(
self
.
course_run
.
lms_course_id
,
updated_lms_course_id
)
self
.
assertNotEqual
(
self
.
course_run
.
changed_by
,
self
.
user
)
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_course_runs_edit'
,
kwargs
=
{
'pk'
:
self
.
course_run
.
id
}),
self
.
course_run_dict
...
...
@@ -467,9 +465,9 @@ class CreateUpdateCourseRunViewTests(TestCase):
self
.
assertContains
(
response
,
'Add new comment'
)
self
.
assertContains
(
response
,
comment
.
comment
)
def
test_edit_course_run_page_with_non_
staff
(
self
):
""" Verify that non
staff
user can't access course run edit page without permission. """
non_
staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
def
test_edit_course_run_page_with_non_
internal
(
self
):
""" Verify that non
internal
user can't access course run edit page without permission. """
non_
internal_user
,
__
=
create_non_staff_user_and_login
(
self
)
updated_lms_course_id
=
'course-v1:testX+AS121+2018_q1'
self
.
course_run_dict
[
'lms_course_id'
]
=
updated_lms_course_id
...
...
@@ -481,9 +479,7 @@ class CreateUpdateCourseRunViewTests(TestCase):
self
.
assertEqual
(
response
.
status_code
,
403
)
# assign user a group and assign view permission on that group
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course_run
.
course
)
non_internal_user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
response
=
self
.
client
.
get
(
reverse
(
'publisher:publisher_course_runs_edit'
,
kwargs
=
{
'pk'
:
self
.
course_run
.
id
})
...
...
@@ -491,9 +487,9 @@ class CreateUpdateCourseRunViewTests(TestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
def
test_update_course_run_with_non_
staff
(
self
):
""" Test for course run with non
staff
user. """
non_
staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
def
test_update_course_run_with_non_
internal_user
(
self
):
""" Test for course run with non
internal
user. """
non_
internal_user
,
__
=
create_non_staff_user_and_login
(
self
)
updated_lms_course_id
=
'course-v1:testX+AS121+2018_q1'
self
.
course_run_dict
[
'lms_course_id'
]
=
updated_lms_course_id
...
...
@@ -504,12 +500,10 @@ class CreateUpdateCourseRunViewTests(TestCase):
self
.
course_run_dict
)
# verify that non
staff
user can't update course run without permission
# verify that non
internal
user can't update course run without permission
self
.
assertEqual
(
response
.
status_code
,
403
)
# assign user a group and assign view permission on that group
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course_run
.
course
)
non_internal_user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_course_runs_edit'
,
kwargs
=
{
'pk'
:
self
.
course_run
.
id
}),
...
...
@@ -541,9 +535,11 @@ class SeatsCreateUpdateViewTests(TestCase):
def
setUp
(
self
):
super
(
SeatsCreateUpdateViewTests
,
self
)
.
setUp
()
self
.
seat
=
factories
.
SeatFactory
(
type
=
Seat
.
PROFESSIONAL
,
credit_hours
=
0
)
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
seat
.
course_run
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
seat_dict
=
model_to_dict
(
self
.
seat
)
self
.
seat_dict
.
pop
(
'upgrade_deadline'
)
self
.
user
=
UserFactory
(
is_staff
=
True
,
is_superuser
=
True
)
self
.
user
=
UserFactory
()
self
.
site
=
Site
.
objects
.
get
(
pk
=
settings
.
SITE_ID
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
self
.
seat_edit_url
=
reverse
(
'publisher:publisher_seats_edit'
,
kwargs
=
{
'pk'
:
self
.
seat
.
id
})
...
...
@@ -573,6 +569,7 @@ class SeatsCreateUpdateViewTests(TestCase):
""" Verify that we can create a new seat. """
seat_price
=
670.00
self
.
seat_dict
[
'price'
]
=
seat_price
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
self
.
user
,
self
.
organization_extension
)
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_seats_new'
),
self
.
seat_dict
)
seat
=
Seat
.
objects
.
get
(
course_run
=
self
.
seat
.
course_run
,
price
=
seat_price
)
self
.
assertRedirects
(
...
...
@@ -584,8 +581,9 @@ class SeatsCreateUpdateViewTests(TestCase):
self
.
assertEqual
(
seat
.
price
,
seat_price
)
def
test_update_seat_with_staff
(
self
):
""" Verify that staff user can update an existing seat. """
def
test_update_seat_with_admin
(
self
):
""" Verify that publisher admin can update an existing seat. """
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
self
.
assertEqual
(
self
.
seat
.
type
,
Seat
.
PROFESSIONAL
)
updated_seat_price
=
470.00
self
.
seat_dict
[
'price'
]
=
updated_seat_price
...
...
@@ -631,22 +629,20 @@ class SeatsCreateUpdateViewTests(TestCase):
self
.
assertContains
(
response
,
comment
.
comment
)
def
test_edit_seat_page_with_non_staff
(
self
):
""" Verify that non
staff
user can't access seat edit page without permission. """
non_
staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
""" Verify that non
internal
user can't access seat edit page without permission. """
non_
internal_user
,
__
=
create_non_staff_user_and_login
(
self
)
response
=
self
.
client
.
get
(
reverse
(
'publisher:publisher_seats_edit'
,
kwargs
=
{
'pk'
:
self
.
seat
.
id
}))
self
.
assertEqual
(
response
.
status_code
,
403
)
# assign user a group and assign view permission on that group
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
seat
.
course_run
.
course
)
non_internal_user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
response
=
self
.
client
.
get
(
reverse
(
'publisher:publisher_seats_edit'
,
kwargs
=
{
'pk'
:
self
.
seat
.
id
}))
self
.
assertEqual
(
response
.
status_code
,
200
)
def
test_update_seat_with_
non_staff
(
self
):
""" Tests update seat for
non staff
user. """
non_
staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
def
test_update_seat_with_
internal_user
(
self
):
""" Tests update seat for
internal
user. """
non_
internal_user
,
__
=
create_non_staff_user_and_login
(
self
)
self
.
assertEqual
(
self
.
seat
.
type
,
Seat
.
PROFESSIONAL
)
updated_seat_price
=
470.00
...
...
@@ -659,12 +655,10 @@ class SeatsCreateUpdateViewTests(TestCase):
self
.
seat_dict
)
# verify that non
staff
user can't update course seat without permission
# verify that non
internal
user can't update course seat without permission
self
.
assertEqual
(
response
.
status_code
,
403
)
# assign user a group and assign view permission on that group
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
seat
.
course_run
.
course
)
non_internal_user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
response
=
self
.
client
.
post
(
reverse
(
'publisher:publisher_seats_edit'
,
kwargs
=
{
'pk'
:
self
.
seat
.
id
}),
...
...
@@ -707,9 +701,14 @@ class CourseRunDetailTests(TestCase):
def
setUp
(
self
):
super
(
CourseRunDetailTests
,
self
)
.
setUp
()
self
.
course
=
factories
.
CourseFactory
()
self
.
user
=
UserFactory
(
is_staff
=
True
)
self
.
user
=
UserFactory
()
self
.
user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
))
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
self
.
course_run
=
factories
.
CourseRunFactory
(
course
=
self
.
course
)
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
_generate_seats
([
Seat
.
AUDIT
,
Seat
.
HONOR
,
Seat
.
VERIFIED
,
Seat
.
PROFESSIONAL
])
self
.
_generate_credit_seat
()
self
.
page_url
=
reverse
(
'publisher:publisher_course_run_detail'
,
args
=
[
self
.
course_run
.
id
])
...
...
@@ -731,11 +730,12 @@ class CourseRunDetailTests(TestCase):
target_status_code
=
302
)
def
test_page_without_data
_staff
(
self
):
""" Verify that
staff
user can access detail page without any data
def
test_page_without_data
(
self
):
""" Verify that user can access detail page without any data
available for that course-run.
"""
course_run
=
factories
.
CourseRunFactory
(
course
=
self
.
course
)
assign_perm
(
OrganizationExtension
.
VIEW_COURSE_RUN
,
self
.
user
,
self
.
organization_extension
)
page_url
=
reverse
(
'publisher:publisher_course_run_detail'
,
args
=
[
course_run
.
id
])
response
=
self
.
client
.
get
(
page_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
...
...
@@ -746,20 +746,6 @@ class CourseRunDetailTests(TestCase):
response
=
self
.
client
.
get
(
page_url
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_details_page_non_staff
(
self
):
""" Verify that non staff user can't access detail page. """
non_staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
response
=
self
.
client
.
get
(
self
.
page_url
)
self
.
assertEqual
(
response
.
status_code
,
403
)
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course
)
response
=
self
.
client
.
get
(
self
.
page_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
def
_generate_seats
(
self
,
modes
):
""" Helper method to add seats for a course-run. """
for
mode
in
modes
:
...
...
@@ -771,7 +757,7 @@ class CourseRunDetailTests(TestCase):
def
test_course_run_detail_page_staff
(
self
):
""" Verify that detail page contains all the data for drupal, studio and
cat with
staff
user.
cat with
publisher admin
user.
"""
response
=
self
.
client
.
get
(
self
.
page_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
...
...
@@ -881,10 +867,11 @@ class CourseRunDetailTests(TestCase):
""" Verify that detail page contains all the data along with comments
for course.
"""
user
=
UserFactory
(
is_staff
=
True
,
is_superuser
=
True
)
self
.
client
.
logout
()
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
site
=
Site
.
objects
.
get
(
pk
=
settings
.
SITE_ID
)
comment
=
CommentFactory
(
content_object
=
self
.
course
,
user
=
user
,
site
=
site
)
comment
=
CommentFactory
(
content_object
=
self
.
course
,
user
=
self
.
user
,
site
=
site
)
response
=
self
.
client
.
get
(
self
.
page_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
_assert_credits_seats
(
response
,
self
.
wrapped_course_run
.
credit_seat
)
...
...
@@ -917,7 +904,7 @@ class CourseRunDetailTests(TestCase):
internal_user_group
.
user_set
.
add
(
*
(
self
.
user
,
pc_user
,
marketing_user
,
publisher_user
))
assign_perm
(
Course
.
VIEW_PERMISSION
,
internal_user_group
,
self
.
course
)
assign_perm
(
OrganizationExtension
.
VIEW_COURSE_RUN
,
internal_user_group
,
self
.
organization_extension
)
organization
=
OrganizationFactory
()
self
.
course
.
organizations
.
add
(
organization
)
...
...
@@ -939,14 +926,14 @@ class CourseRunDetailTests(TestCase):
self
.
assertEqual
(
list
(
response
.
context
[
'user_list'
]),
list
(
get_internal_users
()))
def
test_detail_page_role_assignment_with_non_internal_user
(
self
):
""" Verify that
non internal user can't see change role assignment widget
. """
""" Verify that
user can't see change role assignment widget without permissions
. """
# Create a
non internal
user and assign course view permission.
non_internal_
user
=
UserFactory
()
assign_perm
(
Course
.
VIEW_PERMISSION
,
non_internal_user
,
self
.
course
)
# Create a user and assign course view permission.
user
=
UserFactory
()
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
user
,
self
.
organization_extension
)
self
.
client
.
logout
()
self
.
client
.
login
(
username
=
non_internal_
user
.
username
,
password
=
USER_PASSWORD
)
self
.
client
.
login
(
username
=
user
.
username
,
password
=
USER_PASSWORD
)
response
=
self
.
client
.
get
(
self
.
page_url
)
...
...
@@ -970,7 +957,7 @@ class CourseRunDetailTests(TestCase):
""" Test that user can't see edit button on course run detail page
if there is no organization in course.
"""
_
=
self
.
_create_user_and_login
()
self
.
_create_user_and_login
()
self
.
assert_can_edit_permission
()
...
...
@@ -985,7 +972,7 @@ class CourseRunDetailTests(TestCase):
and return the user.
"""
user
=
UserFactory
()
assign_perm
(
Course
.
VIEW_PERMISSION
,
user
,
self
.
course
)
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
user
,
self
.
organization_extension
)
self
.
client
.
logout
()
self
.
client
.
login
(
username
=
user
.
username
,
password
=
USER_PASSWORD
)
...
...
@@ -999,7 +986,14 @@ class ChangeStateViewTests(TestCase):
def
setUp
(
self
):
super
(
ChangeStateViewTests
,
self
)
.
setUp
()
self
.
course
=
factories
.
CourseFactory
()
self
.
user
=
UserFactory
(
is_staff
=
True
)
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
user
=
UserFactory
()
self
.
publisher_admin_group
=
Group
.
objects
.
get
(
name
=
ADMIN_GROUP_NAME
)
self
.
user
.
groups
.
add
(
self
.
publisher_admin_group
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
self
.
course_run
=
factories
.
CourseRunFactory
(
course
=
self
.
course
)
self
.
page_url
=
reverse
(
'publisher:publisher_course_run_detail'
,
args
=
[
self
.
course_run
.
id
])
...
...
@@ -1020,8 +1014,9 @@ class ChangeStateViewTests(TestCase):
target_status_code
=
302
)
def
test_change_state_with_staff
(
self
):
""" Verify that staff user can change workflow state from detail page. """
def
test_change_state
(
self
):
""" Verify that user can change workflow state from detail page. """
response
=
self
.
client
.
get
(
self
.
page_url
)
self
.
assertContains
(
response
,
'Status:'
)
self
.
assertContains
(
response
,
State
.
DRAFT
.
title
())
...
...
@@ -1031,8 +1026,8 @@ class ChangeStateViewTests(TestCase):
# assert that state is changed to `NEEDS_REVIEW`
self
.
assertContains
(
response
,
State
.
NEEDS_REVIEW
.
title
()
.
replace
(
'_'
,
' '
))
def
test_change_state_not_allowed
_with_staff
(
self
):
""" Verify that
staff
user can't change workflow state from `DRAFT` to `PUBLISHED`. """
def
test_change_state_not_allowed
(
self
):
""" Verify that user can't change workflow state from `DRAFT` to `PUBLISHED`. """
response
=
self
.
client
.
get
(
self
.
page_url
)
self
.
assertContains
(
response
,
'Status:'
)
self
.
assertContains
(
response
,
State
.
DRAFT
.
title
())
...
...
@@ -1042,17 +1037,16 @@ class ChangeStateViewTests(TestCase):
self
.
assertNotContains
(
response
,
State
.
PUBLISHED
.
title
())
self
.
assertContains
(
response
,
'There was an error in changing state.'
)
def
test_change_state_with_no_
staff
(
self
):
def
test_change_state_with_no_
permissions
(
self
):
""" Tests change state for non staff user. """
non_staff_user
,
group
=
create_non_staff_user_and_login
(
self
)
non_staff_user
,
__
=
create_non_staff_user_and_login
(
self
)
response
=
self
.
client
.
post
(
self
.
change_state_url
,
data
=
{
'state'
:
State
.
NEEDS_REVIEW
},
follow
=
True
)
# verify that non staff user can't change workflow state without permission
self
.
assertEqual
(
response
.
status_code
,
403
)
# assign user a group and assign view permission on that group
non_staff_user
.
groups
.
add
(
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course
)
# assign user a group
non_staff_user
.
groups
.
add
(
Group
.
objects
.
get
(
name
=
INTERNAL_USER_GROUP_NAME
))
response
=
self
.
client
.
get
(
self
.
page_url
)
self
.
assertContains
(
response
,
'Status:'
)
...
...
@@ -1064,6 +1058,7 @@ class ChangeStateViewTests(TestCase):
self
.
assertContains
(
response
,
State
.
NEEDS_REVIEW
.
title
()
.
replace
(
'_'
,
' '
))
# pylint: disable=attribute-defined-outside-init
class
DashboardTests
(
TestCase
):
""" Tests for the `Dashboard`. """
...
...
@@ -1147,7 +1142,11 @@ class DashboardTests(TestCase):
self
.
client
.
logout
()
user
=
UserFactory
()
self
.
client
.
login
(
username
=
user
.
username
,
password
=
USER_PASSWORD
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
factories
.
GroupFactory
(),
self
.
course_run_1
.
course
)
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
user
,
self
.
organization_extension
)
self
.
course_run_1
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
assert_dashboard_response
(
studio_count
=
0
,
published_count
=
0
,
progress_count
=
0
,
preview_count
=
0
)
def
test_with_permissions_with_data
(
self
):
...
...
@@ -1156,12 +1155,16 @@ class DashboardTests(TestCase):
"""
self
.
client
.
logout
()
user
=
UserFactory
()
group
=
factories
.
GroupFactory
()
user
.
groups
.
add
(
group
)
self
.
client
.
login
(
username
=
user
.
username
,
password
=
USER_PASSWORD
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course_run_1
.
course
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
group
,
self
.
course_run_2
.
course
)
self
.
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course_run_1
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
course_run_2
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
user
,
self
.
organization_extension
)
self
.
assert_dashboard_response
(
studio_count
=
0
,
published_count
=
0
,
progress_count
=
1
,
preview_count
=
1
)
def
test_studio_request_course_runs_as_pc
(
self
):
...
...
@@ -1305,18 +1308,25 @@ class UpdateCourseKeyViewTests(TestCase):
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
.
user
.
groups
.
add
(
self
.
organization_extension
.
group
)
assign_perm
(
Course
.
VIEW_PERMISSION
,
self
.
organization_extension
.
group
,
self
.
course_run
.
course
)
self
.
course_run
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
USER_PASSWORD
)
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."""
...
...
@@ -1405,7 +1415,9 @@ class CourseListViewTests(TestCase):
def
test_courses_with_permission
(
self
):
""" Verify that user can see course with permission on course list page. """
assign_perm
(
Course
.
VIEW_PERMISSION
,
self
.
user
,
self
.
course
)
organization_extension
=
factories
.
OrganizationExtensionFactory
()
self
.
course
.
organizations
.
add
(
organization_extension
.
organization
)
assign_perm
(
OrganizationExtension
.
VIEW_COURSE
,
self
.
user
,
organization_extension
)
self
.
assert_course_list_page
(
course_count
=
1
)
...
...
course_discovery/apps/publisher/views.py
View file @
c9ccb22f
...
...
@@ -59,9 +59,14 @@ class Dashboard(mixins.LoginRequiredMixin, ListView):
internal_user_courses
=
Course
.
objects
.
filter
(
course_user_roles__user
=
user
)
course_runs
=
CourseRun
.
objects
.
filter
(
course__in
=
internal_user_courses
)
.
select_related
(
'course'
)
.
all
()
else
:
# in future we will change permission from course to OrganizationExtension model
courses
=
get_objects_for_user
(
user
,
Course
.
VIEW_PERMISSION
,
Course
)
course_runs
=
CourseRun
.
objects
.
filter
(
course__in
=
courses
)
.
select_related
(
'course'
)
.
all
()
organizations
=
get_objects_for_user
(
user
,
OrganizationExtension
.
VIEW_COURSE
,
OrganizationExtension
,
use_groups
=
False
,
with_superuser
=
False
)
.
values_list
(
'organization'
)
course_runs
=
CourseRun
.
objects
.
filter
(
course__organizations__in
=
organizations
)
.
select_related
(
'course'
)
.
all
()
return
course_runs
...
...
@@ -201,8 +206,6 @@ class CreateCourseView(mixins.LoginRequiredMixin, CreateView):
OrganizationExtension
,
organization
=
course_form
.
data
[
'organization'
]
)
course
.
organizations
.
add
(
organization_extension
.
organization
)
# assign guardian permission.
course
.
assign_permission_by_group
(
organization_extension
.
group
)
messages
.
success
(
request
,
_
(
'Course created successfully.'
)
...
...
@@ -226,7 +229,7 @@ class UpdateCourseView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mi
""" Update Course View."""
model
=
Course
form_class
=
CourseForm
permission_required
=
Course
.
VIEW_PERMISSION
permission_required
=
OrganizationExtension
.
VIEW_COURSE
template_name
=
'publisher/course_form.html'
success_url
=
'publisher:publisher_courses_edit'
...
...
@@ -324,7 +327,7 @@ class UpdateCourseRunView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin,
""" Update Course Run View."""
model
=
CourseRun
form_class
=
CourseRunForm
permission_required
=
Course
.
VIEW_PERMISSION
permission_required
=
OrganizationExtension
.
VIEW_COURSE
template_name
=
'publisher/course_run_form.html'
success_url
=
'publisher:publisher_course_runs_edit'
change_state
=
True
...
...
@@ -361,7 +364,7 @@ class UpdateSeatView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mixi
""" Update Seat View."""
model
=
Seat
form_class
=
SeatForm
permission_required
=
Course
.
VIEW_PERMISSIO
N
permission_required
=
OrganizationExtension
.
EDIT_COURSE_RU
N
template_name
=
'publisher/seat_form.html'
success_url
=
'publisher:publisher_seats_edit'
...
...
@@ -383,7 +386,7 @@ class ChangeStateView(mixins.LoginRequiredMixin, View):
try
:
course_run
=
CourseRun
.
objects
.
get
(
id
=
course_run_id
)
if
not
mixins
.
check_
view_permission
(
request
.
user
,
course_run
.
course
):
if
not
mixins
.
check_
user_course_access
(
request
.
user
,
course_run
.
course
):
return
HttpResponseForbidden
()
course_run
.
change_state
(
target
=
state
,
user
=
self
.
request
.
user
)
...
...
@@ -425,6 +428,13 @@ class CourseListView(mixins.LoginRequiredMixin, ListView):
elif
is_internal_user
(
user
):
courses
=
Course
.
objects
.
filter
(
course_user_roles__user
=
user
)
.
distinct
()
else
:
courses
=
get_objects_for_user
(
user
,
Course
.
VIEW_PERMISSION
,
Course
)
organizations
=
get_objects_for_user
(
user
,
OrganizationExtension
.
VIEW_COURSE
,
OrganizationExtension
,
use_groups
=
False
,
with_superuser
=
False
)
.
values_list
(
'organization'
)
courses
=
Course
.
objects
.
filter
(
organizations__in
=
organizations
)
return
courses
course_discovery/apps/publisher_comments/emails.py
View file @
c9ccb22f
...
...
@@ -53,7 +53,7 @@ def send_email_for_comment(comment, created=False):
title
=
course
.
title
)
to_addresses
=
course
.
get_
group
_users_emails
()
to_addresses
=
course
.
get_
course
_users_emails
()
from_address
=
settings
.
PUBLISHER_FROM_EMAIL
context
=
{
...
...
course_discovery/apps/publisher_comments/tests/test_emails.py
View file @
c9ccb22f
...
...
@@ -34,23 +34,24 @@ class CommentsEmailTests(TestCase):
self
.
course_run
=
self
.
seat
.
course_run
self
.
course
=
self
.
course_run
.
course
# assign the role against a course
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
# NOTE: We intentionally do NOT create an attribute for user_2.
# By default this user WILL receive email notifications.
# add user in course-user-role table
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
role
=
PublisherUserRole
.
MarketingReviewe
r
,
user
=
self
.
user
course
=
self
.
course
,
role
=
PublisherUserRole
.
PartnerCoordinato
r
,
user
=
self
.
user
)
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
role
=
PublisherUserRole
.
PartnerCoordinator
,
user
=
self
.
user_2
)
factories
.
CourseUserRoleFactory
(
course
=
self
.
course
,
role
=
PublisherUserRole
.
P
ublishe
r
,
user
=
self
.
user_3
course
=
self
.
course
,
role
=
PublisherUserRole
.
P
artnerCoordinato
r
,
user
=
self
.
user_3
)
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
# NOTE: We intentionally do NOT create an attribute for user_2.
# By default this user WILL receive email notifications.
UserAttributeFactory
(
user
=
self
.
user
,
enable_email_notification
=
True
)
UserAttributeFactory
(
user
=
self
.
user_3
,
enable_email_notification
=
False
)
toggle_switch
(
'enable_publisher_email_notifications'
,
True
)
...
...
course_discovery/apps/publisher_comments/tests/test_views.py
View file @
c9ccb22f
...
...
@@ -31,7 +31,6 @@ class CommentsTests(TestCase):
self
.
seat
=
factories
.
SeatFactory
(
type
=
Seat
.
PROFESSIONAL
,
credit_hours
=
0
)
self
.
course_run
=
self
.
seat
.
course_run
self
.
course
=
self
.
course_run
.
course
self
.
course
.
organizations
.
add
(
self
.
organization_extension
.
organization
)
# assign the role against a course
...
...
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