Commit 59ffd6af by Awais Committed by Awais Qureshi

Decorator checking user is part of publisher app group.

Create a mixing using decorator so that It can be use in drf also.
Only authenticated users can access the create course page.

Ecom-6094
parent 0455b87a
from functools import wraps
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.utils import is_publisher_admin, is_internal_user
from course_discovery.apps.publisher.utils import (
is_publisher_admin, is_internal_user, is_publisher_user
)
class ViewPermissionMixin(object):
......@@ -81,3 +84,27 @@ def check_course_organization_permission(user, course, permission):
for org in course.organizations.all()
]
)
def publisher_user_required(func):
"""
View decorator that requires that the user is part any publisher group
permissions.
"""
@wraps(func)
def wrapped(request, *args, **kwargs): # pylint: disable=missing-docstring
if is_publisher_user(request.user):
return func(request, *args, **kwargs)
else:
return HttpResponseForbidden(u"Must be Publisher user to perform this action.")
return wrapped
class PublisherUserRequiredMixin(object):
"""
Mixin to view the user is part of any publisher app group.
"""
@method_decorator(publisher_user_required)
def dispatch(self, request, *args, **kwargs):
return super(PublisherUserRequiredMixin, self).dispatch(request, *args, **kwargs)
""" Tests publisher.utils"""
from django.contrib.auth.models import Group
from django.test import TestCase
from guardian.shortcuts import assign_perm
from django.test import TestCase, RequestFactory
from mock import Mock
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
REVIEWER_GROUP_NAME, ADMIN_GROUP_NAME, INTERNAL_USER_GROUP_NAME,
PARTNER_COORDINATOR_GROUP_NAME
)
from course_discovery.apps.publisher.mixins import (
check_course_organization_permission, check_roles_access,
publisher_user_required
)
from course_discovery.apps.publisher.mixins import check_course_organization_permission, check_roles_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,
get_internal_users, is_partner_coordinator_user
get_internal_users, is_partner_coordinator_user, is_publisher_user
)
......@@ -152,3 +157,39 @@ class PublisherUtilsTests(TestCase):
self.assertTrue(
check_course_organization_permission(self.user, self.course, OrganizationExtension.VIEW_COURSE)
)
def test_is_publisher_user(self):
""" Verify the function returns a boolean indicating if the user
is part of any publisher app group.
"""
self.assertFalse(is_publisher_user(self.user))
self.user.groups.add(Group.objects.get(name=REVIEWER_GROUP_NAME))
self.assertTrue(is_publisher_user(self.user))
def test_require_is_publisher_user_without_group(self):
"""
Verify that decorator returns the error message if user is not part
of any publisher group.
"""
func = Mock()
decorated_func = publisher_user_required(func)
request = RequestFactory()
request.user = self.user
response = decorated_func(request, self.user)
self.assertContains(response, "Must be Publisher user to perform this action.", status_code=403)
self.assertFalse(func.called)
def test_is_publisher_user_with_publisher_group(self):
"""
Verify that decorator works fine with user is part of publisher
app group.
"""
func = Mock()
decorated_func = publisher_user_required(func)
request = RequestFactory()
request.user = self.user
self.user.groups.add(self.internal_user_group)
decorated_func(request, self.user)
self.assertTrue(func.called)
......@@ -46,6 +46,9 @@ class CreateUpdateCourseViewTests(TestCase):
def setUp(self):
super(CreateUpdateCourseViewTests, self).setUp()
self.user = UserFactory()
self.internal_user_group = Group.objects.get(name=INTERNAL_USER_GROUP_NAME)
self.user.groups.add(self.internal_user_group)
self.organization_extension = factories.OrganizationExtensionFactory()
self.group = self.organization_extension.group
self.user.groups.add(self.group)
......@@ -83,6 +86,18 @@ class CreateUpdateCourseViewTests(TestCase):
target_status_code=302
)
def test_page_without_publisher_group_access(self):
"""
Verify that user can't access new course form page if user is not the
part of any group.
"""
self.client.logout()
self.client.login(username=UserFactory().username, password=USER_PASSWORD)
response = self.client.get(reverse('publisher:publisher_courses_new'))
self.assertContains(
response, "Must be Publisher user to perform this action.", status_code=403
)
def test_create_course_and_course_run_and_seat_with_errors(self):
""" Verify that without providing required data course and other
objects cannot be created.
......@@ -180,28 +195,12 @@ class CreateUpdateCourseViewTests(TestCase):
self.assertContains(response, 'Add new comment')
self.assertContains(response, comment.comment)
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)
course_dict['title'] = updated_course_title
self.assertNotEqual(self.course.title, updated_course_title)
response = self.client.get(
reverse('publisher:publisher_courses_edit', kwargs={'pk': self.course.id})
)
self.assertEqual(response.status_code, 403)
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_without_publisher_admin_rights(self):
""" Verify that non-admin users cannot update the course. """
self.client.logout()
user = UserFactory()
self.client.login(username=user.username, password=USER_PASSWORD)
def test_update_course_without_admin_rights(self):
""" Tests for update course with non staff user. """
course_dict = model_to_dict(self.course)
course_dict.pop('verification_deadline')
course_dict.pop('image')
......@@ -217,7 +216,7 @@ class CreateUpdateCourseViewTests(TestCase):
# verify that non staff user can't update course without permission
self.assertEqual(response.status_code, 403)
self.user.groups.add(Group.objects.get(name=ADMIN_GROUP_NAME))
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
......@@ -234,7 +233,7 @@ class CreateUpdateCourseViewTests(TestCase):
self.assertEqual(course.title, updated_course_title)
# add new and check the comment on edit page.
comment = CommentFactory(content_object=self.course, user=self.user, site=self.site)
comment = CommentFactory(content_object=self.course, user=user, site=self.site)
response = self.client.get(reverse('publisher:publisher_courses_edit', kwargs={'pk': self.course.id}))
self.assertContains(response, 'Total Comments 1')
self.assertContains(response, 'Add new comment')
......
......@@ -64,3 +64,15 @@ def is_partner_coordinator_user(user):
bool: True, if user is an PC user; otherwise, False.
"""
return user.groups.filter(name=PARTNER_COORDINATOR_GROUP_NAME).exists()
def is_publisher_user(user):
""" Returns True if the user is part of any group.
Arguments:
user (:obj:`User`): User whose permissions should be checked.
Returns:
bool: True, if user is an publisher user; otherwise, False.
"""
return user.groups.exists()
......@@ -149,7 +149,7 @@ class CourseRunDetailView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin,
# pylint: disable=attribute-defined-outside-init
class CreateCourseView(mixins.LoginRequiredMixin, CreateView):
class CreateCourseView(mixins.LoginRequiredMixin, mixins.PublisherUserRequiredMixin, CreateView):
""" Create Course View."""
model = Course
course_form = CustomCourseForm
......@@ -239,7 +239,7 @@ class CreateCourseView(mixins.LoginRequiredMixin, CreateView):
return render(request, self.template_name, ctx, status=400)
class UpdateCourseView(mixins.LoginRequiredMixin, mixins.ViewPermissionMixin, mixins.FormValidMixin, UpdateView):
class UpdateCourseView(mixins.ViewPermissionMixin, mixins.FormValidMixin, UpdateView):
""" Update Course View."""
model = Course
form_class = CourseForm
......
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