|
11 | 11 | import pytz |
12 | 12 | from django.core.exceptions import PermissionDenied |
13 | 13 | from django.utils.translation import gettext as _ |
| 14 | +from openedx_authz.constants.roles import COURSE_STAFF |
14 | 15 | from search.api import perform_search |
15 | 16 |
|
16 | 17 | from cms.djangoapps.contentstore.courseware_index import CoursewareSearchIndexer, SearchIndexingError |
17 | | -from cms.djangoapps.contentstore.tests.utils import CourseTestCase |
| 18 | +from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient, CourseTestCase |
18 | 19 | from cms.djangoapps.contentstore.utils import reverse_course_url, reverse_usage_url |
19 | 20 | from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import VisibilityState, create_xblock_info |
20 | 21 | from common.djangoapps.student.tests.factories import UserFactory |
| 22 | +from openedx.core.djangoapps.authz.tests.mixins import CourseAuthoringAuthzTestMixin |
21 | 23 | from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES |
22 | 24 | from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order |
23 | 25 | from xmodule.modulestore.exceptions import ItemNotFoundError # lint-amnesty, pylint: disable=wrong-import-order |
@@ -541,3 +543,86 @@ def test_indexing_no_item(self, mock_get_course): |
541 | 543 | # Start manual reindex and check error in response |
542 | 544 | with self.assertRaises(SearchIndexingError): # noqa: PT027 |
543 | 545 | CoursewareSearchIndexer.do_course_reindex(modulestore(), self.course.id) |
| 546 | + |
| 547 | + |
| 548 | +class TestCourseReIndexAuthz(CourseAuthoringAuthzTestMixin, CourseTestCase): |
| 549 | + """ |
| 550 | + AuthZ-based tests for course reindex. |
| 551 | + """ |
| 552 | + |
| 553 | + MODULESTORE = TEST_DATA_SPLIT_MODULESTORE |
| 554 | + SUCCESSFUL_RESPONSE = _("Course has been successfully reindexed.") |
| 555 | + ENABLED_SIGNALS = ['course_published'] |
| 556 | + |
| 557 | + @mock.patch( |
| 558 | + 'cms.djangoapps.contentstore.signals.handlers.transaction.on_commit', |
| 559 | + new=mock.Mock(side_effect=lambda func: func()), |
| 560 | + ) |
| 561 | + def setUp(self): |
| 562 | + super().setUp() |
| 563 | + |
| 564 | + self.url = reverse_course_url('course_search_index_handler', self.course.id) |
| 565 | + |
| 566 | + self.non_staff_client = AjaxEnabledTestClient() |
| 567 | + self.non_staff_user, self.non_staff_password = self.create_non_staff_user() |
| 568 | + self.non_staff_client.login(username=self.non_staff_user.username, password=self.non_staff_password) |
| 569 | + |
| 570 | + self.course.start = datetime.datetime(2014, 1, 1, tzinfo=pytz.utc) |
| 571 | + modulestore().update_item(self.course, self.user.id) |
| 572 | + |
| 573 | + self.chapter = BlockFactory.create( |
| 574 | + parent_location=self.course.location, |
| 575 | + category='chapter', |
| 576 | + display_name="Week 1" |
| 577 | + ) |
| 578 | + self.sequential = BlockFactory.create( |
| 579 | + parent_location=self.chapter.location, |
| 580 | + category='sequential', |
| 581 | + display_name="Lesson 1" |
| 582 | + ) |
| 583 | + self.vertical = BlockFactory.create( |
| 584 | + parent_location=self.sequential.location, |
| 585 | + category='vertical', |
| 586 | + display_name='Subsection 1' |
| 587 | + ) |
| 588 | + self.video = BlockFactory.create( |
| 589 | + parent_location=self.vertical.location, |
| 590 | + category="video", |
| 591 | + display_name="My Video" |
| 592 | + ) |
| 593 | + self.html = BlockFactory.create( |
| 594 | + parent_location=self.vertical.location, |
| 595 | + category="html", |
| 596 | + display_name="My HTML", |
| 597 | + data="<div>This is my unique HTML content</div>", |
| 598 | + ) |
| 599 | + |
| 600 | + def test_staff_user_can_reindex(self): |
| 601 | + """ Verify that staff user can reindex the course. """ |
| 602 | + |
| 603 | + response = self.client.get(self.url, HTTP_ACCEPT='application/json') |
| 604 | + |
| 605 | + assert self.user.is_staff |
| 606 | + assert response.status_code == 200 |
| 607 | + assert self.SUCCESSFUL_RESPONSE in response.content.decode() |
| 608 | + |
| 609 | + def test_non_staff_user_cannot_reindex(self): |
| 610 | + """ Verify that non-staff user without course authoring permissions cannot reindex the course. """ |
| 611 | + response = self.non_staff_client.get(self.url, HTTP_ACCEPT='application/json') |
| 612 | + |
| 613 | + assert not self.non_staff_user.is_staff |
| 614 | + assert response.status_code == 403 |
| 615 | + |
| 616 | + def test_non_staff_user_can_reindex(self): |
| 617 | + """ Verify that non-staff user with course authoring permissions can reindex the course. """ |
| 618 | + |
| 619 | + # Grant access helper |
| 620 | + self.add_user_to_role_in_course( |
| 621 | + self.non_staff_user, |
| 622 | + COURSE_STAFF.external_key, |
| 623 | + self.course.id |
| 624 | + ) |
| 625 | + response = self.non_staff_client.get(self.url, HTTP_ACCEPT='application/json') |
| 626 | + assert not self.non_staff_user.is_staff |
| 627 | + assert response.status_code == 200 |
| 628 | + assert self.SUCCESSFUL_RESPONSE in response.content.decode() |
0 commit comments