Commit 0455b87a by Awais Committed by Awais Qureshi

Update the mixin and pass the permission as param from the views.

Update the change state view so that permission view can be user to checking the
authentication.

Ecom-6687
parent 631dcef2
from rest_framework.permissions import BasePermission from rest_framework.permissions import BasePermission
from course_discovery.apps.publisher.mixins import check_user_course_access from course_discovery.apps.publisher.mixins import check_roles_access, check_course_organization_permission
from course_discovery.apps.publisher.models import OrganizationExtension
from course_discovery.apps.publisher.utils import is_internal_user from course_discovery.apps.publisher.utils import is_internal_user
class CanViewAssociatedCourse(BasePermission): class CanViewAssociatedCourse(BasePermission):
""" Permission class to check user can view a publisher course. """ """ Permission class to check user can view a publisher course or also if
user has view permission on organization.
"""
def has_object_permission(self, request, view, obj): def has_object_permission(self, request, view, obj):
return check_user_course_access(request.user, obj.course) user = request.user
return (
check_roles_access(user) or
check_course_organization_permission(user, obj.course, OrganizationExtension.VIEW_COURSE)
)
class InternalUserPermission(BasePermission): class InternalUserPermission(BasePermission):
......
...@@ -2,18 +2,21 @@ ...@@ -2,18 +2,21 @@
import json import json
import ddt import ddt
from mock import patch
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 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 guardian.shortcuts import assign_perm
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.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.models import CourseRun, OrganizationExtension
from course_discovery.apps.publisher.tests import factories, JSON_CONTENT_TYPE from course_discovery.apps.publisher.tests import factories, JSON_CONTENT_TYPE
...@@ -26,17 +29,17 @@ class CourseRoleAssignmentViewTests(TestCase): ...@@ -26,17 +29,17 @@ class CourseRoleAssignmentViewTests(TestCase):
# Create an internal user group and assign four users. # Create an internal user group and assign four users.
self.internal_user = UserFactory() self.internal_user = UserFactory()
internal_user_group = Group.objects.get(name=INTERNAL_USER_GROUP_NAME) self.internal_user_group = Group.objects.get(name=INTERNAL_USER_GROUP_NAME)
internal_user_group.user_set.add(self.internal_user) self.internal_user_group.user_set.add(self.internal_user)
self.other_internal_users = [] self.other_internal_users = []
for __ in range(3): for __ in range(3):
user = UserFactory() user = UserFactory()
self.other_internal_users.append(user) self.other_internal_users.append(user)
internal_user_group.user_set.add(user) self.internal_user_group.user_set.add(user)
organization_extension = factories.OrganizationExtensionFactory() self.organization_extension = factories.OrganizationExtensionFactory()
self.course.organizations.add(organization_extension.organization) self.course.organizations.add(self.organization_extension.organization)
# Create three internal user course roles for internal users against a course # Create three internal user course roles for internal users against a course
# so we can test change role assignment on these roles. # so we can test change role assignment on these roles.
...@@ -65,6 +68,63 @@ class CourseRoleAssignmentViewTests(TestCase): ...@@ -65,6 +68,63 @@ class CourseRoleAssignmentViewTests(TestCase):
) )
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
def test_role_assignment_with_view_permissions(self):
""" Verify user having permissions can change role assignments. """
# mocked the check_roles_access because it checks whether user is part of internal group
# or has org permissions. So if this method returns True then permission check by passes.
user = UserFactory()
user.groups.add(self.internal_user_group)
# assigning permission to the organization group
user.groups.add(self.organization_extension.group)
assign_perm(
OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension
)
self.client.logout()
self.client.login(username=user.username, password=USER_PASSWORD)
with patch('course_discovery.apps.publisher.api.permissions.check_roles_access') as mock_method:
mock_method.return_value = False
response = self.client.patch(
self.get_role_assignment_url(self.course.course_user_roles.first()),
data=json.dumps({'user': user.id}),
content_type=JSON_CONTENT_TYPE
)
self.assertEqual(response.status_code, 200)
def test_role_assignment_without_view_permissions(self):
""" Verify user having wrong permissions cannot change role assignments. """
# mocked the check_roles_access because it checks whether user is part of internal group
# or has org permissions. So if this method returns True then permission check by passes.
user = UserFactory()
user.groups.add(self.internal_user_group)
# assigning permission to the organization group
user.groups.add(self.organization_extension.group)
assign_perm(
OrganizationExtension.EDIT_COURSE_RUN, self.organization_extension.group, self.organization_extension
)
self.client.logout()
self.client.login(username=user.username, password=USER_PASSWORD)
with patch('course_discovery.apps.publisher.api.permissions.check_roles_access') as mock_method:
mock_method.return_value = False
response = self.client.patch(
self.get_role_assignment_url(self.course.course_user_roles.first()),
data=json.dumps({'user': user.id}),
content_type=JSON_CONTENT_TYPE
)
self.assertEqual(response.status_code, 403)
def get_user_course_roles(self): def get_user_course_roles(self):
return self.course.course_user_roles.all() return self.course.course_user_roles.all()
......
...@@ -2,12 +2,14 @@ from django.contrib.auth.decorators import login_required ...@@ -2,12 +2,14 @@ from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden, HttpResponseRedirect from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from course_discovery.apps.publisher.models import Course, Seat, OrganizationExtension from course_discovery.apps.publisher.models import Course, Seat
from course_discovery.apps.publisher.utils import is_publisher_admin, is_internal_user from course_discovery.apps.publisher.utils import is_publisher_admin, is_internal_user
class ViewPermissionMixin(object): class ViewPermissionMixin(object):
permission = None
def get_course(self): def get_course(self):
publisher_object = self.get_object() publisher_object = self.get_object()
if isinstance(publisher_object, Course): if isinstance(publisher_object, Course):
...@@ -19,15 +21,18 @@ class ViewPermissionMixin(object): ...@@ -19,15 +21,18 @@ class ViewPermissionMixin(object):
return None return None
def check_user(self, user): def has_user_access(self, user):
course = self.get_course() course = self.get_course()
return check_user_course_access(user, course) return (
check_roles_access(user) or
check_course_organization_permission(user, course, self.permission)
)
def permission_failed(self): def permission_failed(self):
return HttpResponseForbidden() return HttpResponseForbidden()
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not self.check_user(request.user): if not self.has_user_access(request.user):
return self.permission_failed() return self.permission_failed()
return super(ViewPermissionMixin, self).dispatch(request, *args, **kwargs) return super(ViewPermissionMixin, self).dispatch(request, *args, **kwargs)
...@@ -65,20 +70,14 @@ def check_roles_access(user): ...@@ -65,20 +70,14 @@ def check_roles_access(user):
return False return False
def check_course_organization_permission(user, course): def check_course_organization_permission(user, course, permission):
""" Return True if user has view permission on organization. """ """ Return True if user has view permission on organization. """
if not hasattr(course, 'organizations'): if not hasattr(course, 'organizations'):
return False return False
return any( return any(
[ [
user.has_perm(OrganizationExtension.VIEW_COURSE, org.organization_extension) user.has_perm(permission, org.organization_extension)
for org in course.organizations.all() 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)
...@@ -106,31 +106,31 @@ class CourseTests(TestCase): ...@@ -106,31 +106,31 @@ class CourseTests(TestCase):
def test_assign_permission_organization_extension(self): def test_assign_permission_organization_extension(self):
""" Verify that permission can be assigned using the organization extension. """ """ 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.user1, self.course, OrganizationExtension.VIEW_COURSE)
self.assert_user_cannot_view_course(self.user2, self.course2) self.assert_user_cannot_view_course(self.user2, self.course2, OrganizationExtension.VIEW_COURSE)
self.course.organizations.add(self.org_extension_1.organization) self.course.organizations.add(self.org_extension_1.organization)
self.course2.organizations.add(self.org_extension_2.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.org_extension_1.group, self.org_extension_1)
assign_perm(OrganizationExtension.VIEW_COURSE, self.user2, self.org_extension_2) assign_perm(OrganizationExtension.VIEW_COURSE, self.org_extension_2.group, self.org_extension_2)
self.assert_user_can_view_course(self.user1, self.course) self.assert_user_can_view_course(self.user1, self.course, OrganizationExtension.VIEW_COURSE)
self.assert_user_can_view_course(self.user2, self.course2) self.assert_user_can_view_course(self.user2, self.course2, OrganizationExtension.VIEW_COURSE)
self.assert_user_cannot_view_course(self.user1, self.course2) self.assert_user_cannot_view_course(self.user1, self.course2, OrganizationExtension.VIEW_COURSE)
self.assert_user_cannot_view_course(self.user2, self.course) self.assert_user_cannot_view_course(self.user2, self.course, OrganizationExtension.VIEW_COURSE)
self.assertEqual(self.course.organizations.first().organization_extension.group, self.org_extension_1.group) self.assertEqual(self.course.organizations.first().organization_extension.group, self.org_extension_1.group)
self.assertEqual(self.course2.organizations.first().organization_extension.group, self.org_extension_2.group) self.assertEqual(self.course2.organizations.first().organization_extension.group, self.org_extension_2.group)
def assert_user_cannot_view_course(self, user, course): def assert_user_cannot_view_course(self, user, course, permission):
""" Asserts the user can NOT view the course. """ """ Asserts the user can NOT view the course. """
self.assertFalse(check_course_organization_permission(user, course, )) self.assertFalse(check_course_organization_permission(user, course, permission))
def assert_user_can_view_course(self, user, course): def assert_user_can_view_course(self, user, course, permission):
""" Asserts the user can view the course. """ """ Asserts the user can view the course. """
self.assertTrue(check_course_organization_permission(user, course)) self.assertTrue(check_course_organization_permission(user, course, permission))
def test_get_course_users_emails(self): def test_get_course_users_emails(self):
""" Verify the method returns the email addresses of users who are """ Verify the method returns the email addresses of users who are
......
...@@ -7,9 +7,7 @@ from course_discovery.apps.core.tests.factories import UserFactory ...@@ -7,9 +7,7 @@ from course_discovery.apps.core.tests.factories import UserFactory
from course_discovery.apps.publisher.constants import ( from course_discovery.apps.publisher.constants import (
ADMIN_GROUP_NAME, INTERNAL_USER_GROUP_NAME, PARTNER_COORDINATOR_GROUP_NAME ADMIN_GROUP_NAME, INTERNAL_USER_GROUP_NAME, PARTNER_COORDINATOR_GROUP_NAME
) )
from course_discovery.apps.publisher.mixins import ( from course_discovery.apps.publisher.mixins import check_course_organization_permission, check_roles_access
check_roles_access, check_course_organization_permission, check_user_course_access
)
from course_discovery.apps.publisher.models import OrganizationExtension from course_discovery.apps.publisher.models import OrganizationExtension
from course_discovery.apps.publisher.tests import factories from course_discovery.apps.publisher.tests import factories
from course_discovery.apps.publisher.utils import ( from course_discovery.apps.publisher.utils import (
...@@ -113,30 +111,44 @@ class PublisherUtilsTests(TestCase): ...@@ -113,30 +111,44 @@ class PublisherUtilsTests(TestCase):
""" Verify the function returns a boolean indicating if the user has """ Verify the function returns a boolean indicating if the user has
organization permission on given course. organization permission on given course.
""" """
self.assertFalse(check_course_organization_permission(self.user, self.course)) self.assertFalse(
check_course_organization_permission(self.user, self.course, OrganizationExtension.VIEW_COURSE)
)
self.user.groups.add(self.organization_extension.group)
assign_perm( assign_perm(
OrganizationExtension.VIEW_COURSE, self.user, self.organization_extension OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension
)
self.assertTrue(
check_course_organization_permission(self.user, self.course, OrganizationExtension.VIEW_COURSE)
) )
self.assertTrue(check_course_organization_permission(self.user, self.course))
def test_check_user_access_with_roles(self): def test_check_user_access_with_roles(self):
""" Verify the function returns a boolean indicating if the user """ Verify the function returns a boolean indicating if the user
organization permission on given course or user is internal or admin user. organization permission on given course or user is internal or admin user.
""" """
self.assertFalse(check_user_course_access(self.user, self.course)) self.assertFalse(check_roles_access(self.user))
self.user.groups.add(self.admin_group) self.user.groups.add(self.admin_group)
self.assertTrue(check_user_course_access(self.user, self.course)) self.assertTrue(check_roles_access(self.user))
self.user.groups.remove(self.admin_group) self.user.groups.remove(self.admin_group)
self.assertFalse(check_user_course_access(self.user, self.course)) self.assertFalse(check_roles_access(self.user))
self.user.groups.add(self.internal_user_group) self.user.groups.add(self.internal_user_group)
self.assertTrue(check_user_course_access(self.user, self.course)) self.assertTrue(check_roles_access(self.user))
def test_check_user_access_with_permission(self): def test_check_user_access_with_permission(self):
""" Verify the function returns a boolean indicating if the user """ Verify the function returns a boolean indicating if the user
has view permission on organization has view permission on organization
""" """
self.assertFalse(check_course_organization_permission(self.user, self.course)) self.assertFalse(
check_course_organization_permission(self.user, self.course, OrganizationExtension.VIEW_COURSE)
)
self.user.groups.add(self.organization_extension.group)
assign_perm( assign_perm(
OrganizationExtension.VIEW_COURSE, self.user, self.organization_extension OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension
)
self.assertTrue(
check_course_organization_permission(self.user, self.course, OrganizationExtension.VIEW_COURSE)
) )
self.assertTrue(check_course_organization_permission(self.user, self.course))
...@@ -472,7 +472,9 @@ class CreateUpdateCourseRunViewTests(TestCase): ...@@ -472,7 +472,9 @@ class CreateUpdateCourseRunViewTests(TestCase):
} }
) )
self._pop_valuse_from_dict(post_data, ['id', 'course', 'course_run']) self._pop_valuse_from_dict(post_data, ['id', 'course', 'course_run'])
assign_perm(OrganizationExtension.VIEW_COURSE_RUN, self.user, self.organization_extension) assign_perm(
OrganizationExtension.VIEW_COURSE_RUN, self.organization_extension.group, self.organization_extension
)
response = self.client.post( response = self.client.post(
reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id}), reverse('publisher:publisher_course_runs_new', kwargs={'parent_course_id': self.course.id}),
post_data post_data
...@@ -633,9 +635,14 @@ class SeatsCreateUpdateViewTests(TestCase): ...@@ -633,9 +635,14 @@ class SeatsCreateUpdateViewTests(TestCase):
""" Verify that we can create a new seat. """ """ Verify that we can create a new seat. """
seat_price = 670.00 seat_price = 670.00
self.seat_dict['price'] = seat_price 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) 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) seat = Seat.objects.get(course_run=self.seat.course_run, price=seat_price)
self.user.groups.add(self.organization_extension.group)
# edit permission require on seat edit page only.
assign_perm(
OrganizationExtension.EDIT_COURSE_RUN, self.organization_extension.group, self.organization_extension
)
self.assertRedirects( self.assertRedirects(
response, response,
expected_url=reverse('publisher:publisher_seats_edit', kwargs={'pk': seat.id}), expected_url=reverse('publisher:publisher_seats_edit', kwargs={'pk': seat.id}),
...@@ -799,7 +806,9 @@ class CourseRunDetailTests(TestCase): ...@@ -799,7 +806,9 @@ class CourseRunDetailTests(TestCase):
available for that course-run. available for that course-run.
""" """
course_run = factories.CourseRunFactory(course=self.course) course_run = factories.CourseRunFactory(course=self.course)
assign_perm(OrganizationExtension.VIEW_COURSE_RUN, self.user, self.organization_extension) assign_perm(
OrganizationExtension.VIEW_COURSE_RUN, self.organization_extension.group, self.organization_extension
)
page_url = reverse('publisher:publisher_course_run_detail', args=[course_run.id]) page_url = reverse('publisher:publisher_course_run_detail', args=[course_run.id])
response = self.client.get(page_url) response = self.client.get(page_url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
...@@ -968,8 +977,6 @@ class CourseRunDetailTests(TestCase): ...@@ -968,8 +977,6 @@ class CourseRunDetailTests(TestCase):
internal_user_group.user_set.add(*(self.user, pc_user, marketing_user, publisher_user)) internal_user_group.user_set.add(*(self.user, pc_user, marketing_user, publisher_user))
assign_perm(OrganizationExtension.VIEW_COURSE_RUN, internal_user_group, self.organization_extension)
organization = OrganizationFactory() organization = OrganizationFactory()
self.course.organizations.add(organization) self.course.organizations.add(organization)
factories.OrganizationExtensionFactory(organization=organization) factories.OrganizationExtensionFactory(organization=organization)
...@@ -994,7 +1001,10 @@ class CourseRunDetailTests(TestCase): ...@@ -994,7 +1001,10 @@ class CourseRunDetailTests(TestCase):
# Create a user and assign course view permission. # Create a user and assign course view permission.
user = UserFactory() user = UserFactory()
assign_perm(OrganizationExtension.VIEW_COURSE, user, self.organization_extension) assign_perm(
OrganizationExtension.VIEW_COURSE_RUN, self.organization_extension.group, self.organization_extension
)
user.groups.add(self.organization_extension.group)
self.client.logout() self.client.logout()
self.client.login(username=user.username, password=USER_PASSWORD) self.client.login(username=user.username, password=USER_PASSWORD)
...@@ -1006,22 +1016,25 @@ class CourseRunDetailTests(TestCase): ...@@ -1006,22 +1016,25 @@ class CourseRunDetailTests(TestCase):
def test_details_page_with_edit_permission(self): def test_details_page_with_edit_permission(self):
""" Test that user can see edit button on course run detail page. """ """ Test that user can see edit button on course run detail page. """
user = self._create_user_and_login() user = self._create_user_and_login(OrganizationExtension.VIEW_COURSE_RUN)
organization = OrganizationFactory() organization = OrganizationFactory()
self.course.organizations.add(organization) self.course.organizations.add(organization)
organization_extension = factories.OrganizationExtensionFactory(organization=organization) organization_extension = factories.OrganizationExtensionFactory(organization=organization)
self.assert_can_edit_permission() self.assert_can_edit_permission()
assign_perm(OrganizationExtension.EDIT_COURSE_RUN, user, organization_extension) assign_perm(
OrganizationExtension.EDIT_COURSE_RUN, organization_extension.group, organization_extension
)
user.groups.add(organization_extension.group)
self.assert_can_edit_permission(can_edit=True) self.assert_can_edit_permission(can_edit=True)
def test_edit_permission_with_no_organization(self): def test_edit_permission_with_no_organization(self):
""" Test that user can't see edit button on course run detail page """ Test that user can't see edit button on course run detail page
if there is no organization in course. if there is no organization in course.
""" """
self._create_user_and_login() self._create_user_and_login(OrganizationExtension.VIEW_COURSE_RUN)
self.assert_can_edit_permission() self.assert_can_edit_permission()
...@@ -1031,12 +1044,13 @@ class CourseRunDetailTests(TestCase): ...@@ -1031,12 +1044,13 @@ class CourseRunDetailTests(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['can_edit'], can_edit) self.assertEqual(response.context['can_edit'], can_edit)
def _create_user_and_login(self): def _create_user_and_login(self, permission):
""" Create user and login, also assign view permission for course """ Create user and login, also assign view permission for course
and return the user. and return the user.
""" """
user = UserFactory() user = UserFactory()
assign_perm(OrganizationExtension.VIEW_COURSE, user, self.organization_extension) user.groups.add(self.organization_extension.group)
assign_perm(permission, self.organization_extension.group, self.organization_extension)
self.client.logout() self.client.logout()
self.client.login(username=user.username, password=USER_PASSWORD) self.client.login(username=user.username, password=USER_PASSWORD)
...@@ -1101,7 +1115,7 @@ class ChangeStateViewTests(TestCase): ...@@ -1101,7 +1115,7 @@ class ChangeStateViewTests(TestCase):
self.assertNotContains(response, State.PUBLISHED.title()) self.assertNotContains(response, State.PUBLISHED.title())
self.assertContains(response, 'There was an error in changing state.') self.assertContains(response, 'There was an error in changing state.')
def test_change_state_with_no_permissions(self): def test_change_state_with_no_roles(self):
""" Tests change state for non staff user. """ """ Tests change state for non staff user. """
non_staff_user, __ = 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) response = self.client.post(self.change_state_url, data={'state': State.NEEDS_REVIEW}, follow=True)
...@@ -1208,7 +1222,7 @@ class DashboardTests(TestCase): ...@@ -1208,7 +1222,7 @@ class DashboardTests(TestCase):
self.client.login(username=user.username, password=USER_PASSWORD) self.client.login(username=user.username, password=USER_PASSWORD)
self.organization_extension = factories.OrganizationExtensionFactory() self.organization_extension = factories.OrganizationExtensionFactory()
assign_perm(OrganizationExtension.VIEW_COURSE, user, self.organization_extension) assign_perm(OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension)
self.course_run_1.course.organizations.add(self.organization_extension.organization) 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) self.assert_dashboard_response(studio_count=0, published_count=0, progress_count=0, preview_count=0)
...@@ -1227,7 +1241,10 @@ class DashboardTests(TestCase): ...@@ -1227,7 +1241,10 @@ class DashboardTests(TestCase):
self.course_run_1.course.organizations.add(self.organization_extension.organization) self.course_run_1.course.organizations.add(self.organization_extension.organization)
self.course_run_2.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) user.groups.add(self.organization_extension.group)
assign_perm(
OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension
)
self.assert_dashboard_response(studio_count=0, published_count=0, progress_count=1, preview_count=1) self.assert_dashboard_response(studio_count=0, published_count=0, progress_count=1, preview_count=1)
...@@ -1398,7 +1415,9 @@ class CourseListViewTests(TestCase): ...@@ -1398,7 +1415,9 @@ class CourseListViewTests(TestCase):
""" Verify that user can see course with permission on course list page. """ """ Verify that user can see course with permission on course list page. """
organization_extension = factories.OrganizationExtensionFactory() organization_extension = factories.OrganizationExtensionFactory()
self.course.organizations.add(organization_extension.organization) self.course.organizations.add(organization_extension.organization)
assign_perm(OrganizationExtension.VIEW_COURSE, self.user, organization_extension) self.user.groups.add(organization_extension.group)
assign_perm(OrganizationExtension.VIEW_COURSE, organization_extension.group, organization_extension)
self.assert_course_list_page(course_count=1) self.assert_course_list_page(course_count=1)
...@@ -1437,7 +1456,8 @@ class CourseDetailViewTests(TestCase): ...@@ -1437,7 +1456,8 @@ class CourseDetailViewTests(TestCase):
""" """
Verify that user can access course detail page with view permission. Verify that user can access course detail page with view permission.
""" """
assign_perm(OrganizationExtension.VIEW_COURSE, self.user, self.organization_extension) self.user.groups.add(self.organization_extension.group)
assign_perm(OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension)
response = self.client.get(self.detail_page_url) response = self.client.get(self.detail_page_url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
...@@ -1457,14 +1477,15 @@ class CourseDetailViewTests(TestCase): ...@@ -1457,14 +1477,15 @@ class CourseDetailViewTests(TestCase):
response = self.client.get(self.detail_page_url) response = self.client.get(self.detail_page_url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_details_page_with_edit_permission(self): def test_details_page_with_permissions(self):
""" Test that user can see edit button on course detail page. """ """ Test that user can see edit button on course detail page. """
assign_perm(OrganizationExtension.VIEW_COURSE, self.user, self.organization_extension) self.user.groups.add(self.organization_extension.group)
assign_perm(OrganizationExtension.VIEW_COURSE, self.organization_extension.group, self.organization_extension)
# Verify that user cannot see edit button without edit permission. # Verify that user cannot see edit button without edit permission.
self.assert_can_edit_permission(can_edit=False) self.assert_can_edit_permission(can_edit=False)
assign_perm(OrganizationExtension.EDIT_COURSE, self.user, self.organization_extension) assign_perm(OrganizationExtension.EDIT_COURSE, self.organization_extension.group, self.organization_extension)
# Verify that user can see edit button with edit permission. # Verify that user can see edit button with edit permission.
self.assert_can_edit_permission(can_edit=True) self.assert_can_edit_permission(can_edit=True)
......
...@@ -20,8 +20,7 @@ urlpatterns = [ ...@@ -20,8 +20,7 @@ urlpatterns = [
url(r'^course_runs/(?P<pk>\d+)/$', views.CourseRunDetailView.as_view(), name='publisher_course_run_detail'), url(r'^course_runs/(?P<pk>\d+)/$', views.CourseRunDetailView.as_view(), name='publisher_course_run_detail'),
url(r'^course_runs/(?P<pk>\d+)/edit/$', views.UpdateCourseRunView.as_view(), name='publisher_course_runs_edit'), url(r'^course_runs/(?P<pk>\d+)/edit/$', views.UpdateCourseRunView.as_view(), name='publisher_course_runs_edit'),
url( url(
r'^course_runs/(?P<course_run_id>\d+)/change_state/$', r'^course_runs/(?P<pk>\d+)/change_state/$', views.ChangeStateView.as_view(),
views.ChangeStateView.as_view(),
name='publisher_change_state' name='publisher_change_state'
), ),
url(r'^seats/new/$', views.CreateSeatView.as_view(), name='publisher_seats_new'), url(r'^seats/new/$', views.CreateSeatView.as_view(), name='publisher_seats_new'),
......
...@@ -8,7 +8,7 @@ from datetime import datetime, timedelta ...@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
from django.http import HttpResponseRedirect, HttpResponseForbidden, JsonResponse from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from django.utils.translation import ugettext_lazy as _ 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
...@@ -59,7 +59,7 @@ class Dashboard(mixins.LoginRequiredMixin, ListView): ...@@ -59,7 +59,7 @@ class Dashboard(mixins.LoginRequiredMixin, ListView):
else: else:
organizations = get_objects_for_user( organizations = get_objects_for_user(
user, OrganizationExtension.VIEW_COURSE, OrganizationExtension, user, OrganizationExtension.VIEW_COURSE, OrganizationExtension,
use_groups=False, use_groups=True,
with_superuser=False with_superuser=False
).values_list('organization') ).values_list('organization')
course_runs = CourseRun.objects.filter( course_runs = CourseRun.objects.filter(
...@@ -113,6 +113,7 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, ...@@ -113,6 +113,7 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin,
""" Course Run Detail View.""" """ Course Run Detail View."""
model = CourseRun model = CourseRun
template_name = 'publisher/course_run_detail.html' template_name = 'publisher/course_run_detail.html'
permission = OrganizationExtension.VIEW_COURSE_RUN
def get_role_widgets_data(self, course_roles): def get_role_widgets_data(self, course_roles):
""" Create role widgets list for course user roles. """ """ Create role widgets list for course user roles. """
...@@ -134,9 +135,8 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, ...@@ -134,9 +135,8 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin,
course_run = CourseRunWrapper(self.get_object()) course_run = CourseRunWrapper(self.get_object())
context['object'] = course_run context['object'] = course_run
context['comment_object'] = course_run.course context['comment_object'] = course_run.course
context['can_edit'] = any( context['can_edit'] = mixins.check_course_organization_permission(
[user.has_perm(OrganizationExtension.EDIT_COURSE_RUN, org.organization_extension) self.request.user, course_run.course, OrganizationExtension.EDIT_COURSE_RUN
for org in course_run.course.organizations.all()]
) )
# Show role assignment widgets if user is an internal user. # Show role assignment widgets if user is an internal user.
...@@ -243,7 +243,7 @@ class UpdateCourseView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mi ...@@ -243,7 +243,7 @@ class UpdateCourseView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mi
""" Update Course View.""" """ Update Course View."""
model = Course model = Course
form_class = CourseForm form_class = CourseForm
permission_required = OrganizationExtension.VIEW_COURSE permission = OrganizationExtension.VIEW_COURSE
template_name = 'publisher/course_form.html' template_name = 'publisher/course_form.html'
success_url = 'publisher:publisher_courses_edit' success_url = 'publisher:publisher_courses_edit'
...@@ -260,16 +260,16 @@ class CourseDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, De ...@@ -260,16 +260,16 @@ class CourseDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, De
""" Course Detail View.""" """ Course Detail View."""
model = Course model = Course
template_name = 'publisher/view_course_form.html' template_name = 'publisher/view_course_form.html'
permission = OrganizationExtension.VIEW_COURSE
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CourseDetailView, self).get_context_data(**kwargs) context = super(CourseDetailView, self).get_context_data(**kwargs)
user = self.request.user
context['comment_object'] = self context['comment_object'] = self
context['can_edit'] = any( context['can_edit'] = mixins.check_course_organization_permission(
[user.has_perm(OrganizationExtension.EDIT_COURSE, org.organization_extension) self.request.user, self.object, OrganizationExtension.EDIT_COURSE
for org in self.object.organizations.all()]
) )
return context return context
...@@ -349,7 +349,7 @@ class UpdateCourseRunView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, ...@@ -349,7 +349,7 @@ class UpdateCourseRunView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin,
""" Update Course Run View.""" """ Update Course Run View."""
model = CourseRun model = CourseRun
form_class = CourseRunForm form_class = CourseRunForm
permission_required = OrganizationExtension.VIEW_COURSE permission = OrganizationExtension.VIEW_COURSE
template_name = 'publisher/course_run_form.html' template_name = 'publisher/course_run_form.html'
success_url = 'publisher:publisher_course_runs_edit' success_url = 'publisher:publisher_course_runs_edit'
change_state = True change_state = True
...@@ -386,7 +386,7 @@ class UpdateSeatView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mixi ...@@ -386,7 +386,7 @@ class UpdateSeatView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mixi
""" Update Seat View.""" """ Update Seat View."""
model = Seat model = Seat
form_class = SeatForm form_class = SeatForm
permission_required = OrganizationExtension.EDIT_COURSE_RUN permission = OrganizationExtension.EDIT_COURSE_RUN
template_name = 'publisher/seat_form.html' template_name = 'publisher/seat_form.html'
success_url = 'publisher:publisher_seats_edit' success_url = 'publisher:publisher_seats_edit'
...@@ -400,26 +400,25 @@ class UpdateSeatView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mixi ...@@ -400,26 +400,25 @@ class UpdateSeatView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mixi
return reverse(self.success_url, kwargs={'pk': self.object.id}) return reverse(self.success_url, kwargs={'pk': self.object.id})
class ChangeStateView(mixins.LoginRequiredMixin, View): class ChangeStateView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, UpdateView):
""" Change Workflow State View""" """ Change Workflow State View"""
def post(self, request, course_run_id): model = CourseRun
permission = OrganizationExtension.EDIT_COURSE_RUN
def post(self, request, **kwargs):
state = request.POST.get('state') state = request.POST.get('state')
course_run = self.get_object()
try: try:
course_run = CourseRun.objects.get(id=course_run_id)
if not mixins.check_user_course_access(request.user, course_run.course):
return HttpResponseForbidden()
course_run.change_state(target=state, user=self.request.user) course_run.change_state(target=state, user=self.request.user)
# pylint: disable=no-member # pylint: disable=no-member
messages.success( messages.success(
request, _('Content moved to `{state}` successfully.').format(state=course_run.current_state) request, _('Content moved to `{state}` successfully.').format(state=course_run.current_state)
) )
return HttpResponseRedirect(reverse('publisher:publisher_course_run_detail', kwargs={'pk': course_run_id})) return HttpResponseRedirect(reverse('publisher:publisher_course_run_detail', kwargs={'pk': course_run.id}))
except (CourseRun.DoesNotExist, TransitionNotAllowed): except (CourseRun.DoesNotExist, TransitionNotAllowed):
messages.error(request, _('There was an error in changing state.')) messages.error(request, _('There was an error in changing state.'))
return HttpResponseRedirect(reverse('publisher:publisher_course_run_detail', kwargs={'pk': course_run_id})) return HttpResponseRedirect(reverse('publisher:publisher_course_run_detail', kwargs={'pk': course_run.id}))
class ToggleEmailNotification(mixins.LoginRequiredMixin, View): class ToggleEmailNotification(mixins.LoginRequiredMixin, View):
...@@ -449,7 +448,7 @@ class CourseListView(mixins.LoginRequiredMixin, ListView): ...@@ -449,7 +448,7 @@ class CourseListView(mixins.LoginRequiredMixin, ListView):
user, user,
OrganizationExtension.VIEW_COURSE, OrganizationExtension.VIEW_COURSE,
OrganizationExtension, OrganizationExtension,
use_groups=False, use_groups=True,
with_superuser=False with_superuser=False
).values_list('organization') ).values_list('organization')
courses = Course.objects.filter(organizations__in=organizations) courses = Course.objects.filter(organizations__in=organizations)
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
{% endfor %} {% endfor %}
<div class="actions"> <div class="actions">
<form action="{% url 'publisher:publisher_change_state' course_run_id=object.id %}" method="post"> {% csrf_token %} <form action="{% url 'publisher:publisher_change_state' pk=object.id %}" method="post"> {% csrf_token %}
<button type="submit" value="{{ object.change_state_button.value }}" class="btn-brand btn-small btn-states" name="state">{{ object.change_state_button.text }}</button> <button type="submit" value="{{ object.change_state_button.value }}" class="btn-brand btn-small btn-states" name="state">{{ object.change_state_button.text }}</button>
</form> </form>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment