Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/verify-dunder-init.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on:
pull_request:
branches:
- master

jobs:

verify_dunder_init:

name: Verify __init__.py Files
runs-on: ubuntu-20.04

steps:

- name: Check out branch
uses: actions/checkout@v2

- name: Ensure git is installed
run: |
sudo apt-get update && sudo apt-get install git

- name: Verify __init__.py files exist
run: |
scripts/verify-dunder-init.sh
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def test_404_no_course_module(self):
class ProctoringExamSettingsGetTests(ProctoringExamSettingsTestMixin, ModuleStoreTestCase, APITestCase):
""" Tests for proctored exam settings GETs """
@classmethod
def get_expected_response_data(cls, course, user):
def get_expected_response_data(cls, course, user): # pylint: disable=unused-argument
return {
'proctored_exam_settings': {
'enable_proctored_exams': course.enable_proctored_exams,
Expand Down
7 changes: 5 additions & 2 deletions cms/djangoapps/contentstore/rest_api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,13 @@ def get(self, request, course_id):

def post(self, request, course_id):
""" POST handler """
serializer = ProctoredExamSettingsSerializer if request.user.is_staff else LimitedProctoredExamSettingsSerializer
serializer = ProctoredExamSettingsSerializer if request.user.is_staff \
else LimitedProctoredExamSettingsSerializer
exam_config = serializer(data=request.data.get('proctored_exam_settings', {}))
valid_request = exam_config.is_valid()
if not request.user.is_staff and valid_request and ProctoredExamSettingsSerializer(data=request.data.get('proctored_exam_settings', {})).is_valid():
if not request.user.is_staff and valid_request and ProctoredExamSettingsSerializer(
data=request.data.get('proctored_exam_settings', {})
).is_valid():
return Response(status=status.HTTP_403_FORBIDDEN)

with modulestore().bulk_operations(CourseKey.from_string(course_id)):
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from uuid import uuid4
from django.urls import reverse
from django.contrib.sites.models import Site
from django.contrib.auth.models import User
from django.utils.http import urlencode
from rest_framework import status
from rest_framework.test import APITestCase
Expand Down Expand Up @@ -69,7 +68,7 @@ def setUpTestData(cls):
slug='edxSideTest',
)

def setUp(self):
def setUp(self): # pylint: disable=super-method-not-called
set_jwt_cookie(self.client, self.user, [(ENTERPRISE_ADMIN_ROLE, ENTERPRISE_ID)])
self.client.force_authenticate(user=self.user)

Expand Down Expand Up @@ -147,7 +146,9 @@ def test_create_one_config(self):
assert provider_config.country == SINGLE_PROVIDER_CONFIG_2['country']

# check association has also been created
assert EnterpriseCustomerIdentityProvider.objects.filter(provider_id=convert_saml_slug_provider_id(provider_config.slug)).exists(), 'Cannot find EnterpriseCustomer-->SAMLProviderConfig association'
assert EnterpriseCustomerIdentityProvider.objects.filter(
provider_id=convert_saml_slug_provider_id(provider_config.slug)
).exists(), 'Cannot find EnterpriseCustomer-->SAMLProviderConfig association'

def test_create_one_config_fail_non_existent_enterprise_uuid(self):
"""
Expand All @@ -164,7 +165,9 @@ def test_create_one_config_fail_non_existent_enterprise_uuid(self):
assert SAMLProviderConfig.objects.count() == orig_count

# check association has NOT been created
assert not EnterpriseCustomerIdentityProvider.objects.filter(provider_id=convert_saml_slug_provider_id(SINGLE_PROVIDER_CONFIG_2['slug'])).exists(), 'Did not expect to find EnterpriseCustomer-->SAMLProviderConfig association'
assert not EnterpriseCustomerIdentityProvider.objects.filter(
provider_id=convert_saml_slug_provider_id(SINGLE_PROVIDER_CONFIG_2['slug'])
).exists(), 'Did not expect to find EnterpriseCustomer-->SAMLProviderConfig association'

def test_create_one_config_with_absent_enterprise_uuid(self):
"""
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# pylint: disable=missing-module-docstring
import copy
import pytz
from uuid import uuid4
from datetime import datetime
from django.contrib.sites.models import Site
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.http import urlencode
from rest_framework import status
Expand Down Expand Up @@ -72,7 +72,7 @@ def setUpTestData(cls):
enterprise_customer_id=ENTERPRISE_ID
)

def setUp(self):
def setUp(self): # pylint: disable=super-method-not-called
# a cookie with roles: [{enterprise_admin_role: ent_id}] will be
# needed to rbac to authorize access for this view
set_jwt_cookie(self.client, self.user, [(ENTERPRISE_ADMIN_ROLE, ENTERPRISE_ID)])
Expand Down Expand Up @@ -102,7 +102,9 @@ def test_create_one_provider_data_success(self):

assert response.status_code == status.HTTP_201_CREATED
assert SAMLProviderData.objects.count() == (orig_count + 1)
assert SAMLProviderData.objects.get(entity_id=SINGLE_PROVIDER_DATA_2['entity_id']).sso_url == SINGLE_PROVIDER_DATA_2['sso_url']
assert SAMLProviderData.objects.get(
entity_id=SINGLE_PROVIDER_DATA_2['entity_id']
).sso_url == SINGLE_PROVIDER_DATA_2['sso_url']

def test_create_one_data_with_absent_enterprise_uuid(self):
"""
Expand Down
Empty file added common/test/pacts/__init__.py
Empty file.
Empty file.
Empty file.
2 changes: 1 addition & 1 deletion lms/djangoapps/course_home_api/outline/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class CourseBlockSerializer(serializers.Serializer):
"""
blocks = serializers.SerializerMethodField()

def get_blocks(self, block):
def get_blocks(self, block): # pylint: disable=missing-function-docstring
block_key = block['id']
block_type = block['type']
children = block.get('children', []) if block_type != 'sequential' else [] # Don't descend past sequential
Expand Down
1 change: 0 additions & 1 deletion lms/djangoapps/course_home_api/outline/tests/test_goals.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from lms.djangoapps.course_goals.models import CourseGoal
from lms.djangoapps.course_goals.toggles import COURSE_GOALS_NUMBER_OF_DAYS_GOALS
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
from openedx.features.course_experience import ENABLE_COURSE_GOALS
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
Expand Down
19 changes: 14 additions & 5 deletions lms/djangoapps/course_home_api/outline/tests/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def test_welcome_message(self, welcome_message_is_dismissed):
user=self.user,
course_id=self.course.id,
key='view-welcome-message',
value=False if welcome_message_is_dismissed else True
value=not welcome_message_is_dismissed
)
welcome_message_html = self.client.get(self.url).data['welcome_message_html']
assert welcome_message_html == (None if welcome_message_is_dismissed else '<p>Welcome</p>')
Expand Down Expand Up @@ -354,7 +354,9 @@ def test_visibility(self, is_enrolled, is_staff, course_visibility):
self.course.course_visibility = course_visibility
self.course = self.update_course(self.course, self.user.id)

self.store.create_item(self.user.id, self.course.id, 'course_info', 'handouts', fields={'data': '<p>Handouts</p>'})
self.store.create_item(
self.user.id, self.course.id, 'course_info', 'handouts', fields={'data': '<p>Handouts</p>'}
)
self.store.create_item(self.user.id, self.course.id, 'course_info', 'updates', fields={
'items': [{
'content': '<p>Welcome</p>',
Expand Down Expand Up @@ -386,7 +388,14 @@ def test_verified_mode(self):
CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))

response = self.client.get(self.url)
assert response.data['verified_mode'] == {'access_expiration_date': (enrollment.created + MIN_DURATION), 'currency': 'USD', 'currency_symbol': '$', 'price': 149, 'sku': 'ABCD1234', 'upgrade_url': '/dashboard'}
assert response.data['verified_mode'] == {
'access_expiration_date': (enrollment.created + MIN_DURATION),
'currency': 'USD',
'currency_symbol': '$',
'price': 149,
'sku': 'ABCD1234',
'upgrade_url': '/dashboard'
}

def test_hide_learning_sequences(self):
"""
Expand Down Expand Up @@ -416,7 +425,7 @@ def test_hide_learning_sequences(self):
days_early_for_beta=None,
sections=[],
self_paced=False,
course_visibility=CourseVisibility.PRIVATE
course_visibility=CourseVisibility.PRIVATE # pylint: disable=protected-access
)
replace_course_outline(new_learning_seq_outline)
response = self.client.get(self.url)
Expand All @@ -425,7 +434,7 @@ def test_hide_learning_sequences(self):

def test_user_has_passing_grade(self):
CourseEnrollment.enroll(self.user, self.course.id)
self.course._grading_policy['GRADE_CUTOFFS']['Pass'] = 0
self.course._grading_policy['GRADE_CUTOFFS']['Pass'] = 0 # pylint: disable=protected-access
self.update_course(self.course, self.user.id)
CourseGradeFactory().update(self.user, self.course)
response = self.client.get(self.url)
Expand Down
Empty file.
14 changes: 7 additions & 7 deletions lms/djangoapps/course_home_api/outline/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,10 @@ class OutlineTabView(RetrieveAPIView):

serializer_class = OutlineTabSerializer

def get(self, request, *args, **kwargs):
def get(self, request, *args, **kwargs): # pylint: disable=too-many-statements
course_key_string = kwargs.get('course_key_string')
course_key = CourseKey.from_string(course_key_string)
course_usage_key = modulestore().make_course_usage_key(course_key)
course_usage_key = modulestore().make_course_usage_key(course_key) # pylint: disable=unused-variable

if course_home_legacy_is_active(course_key):
raise Http404
Expand Down Expand Up @@ -385,7 +385,7 @@ def finalize_response(self, request, response, *args, **kwargs):
@api_view(['POST'])
@authentication_classes((JwtAuthentication,))
@permission_classes((IsAuthenticated,))
def dismiss_welcome_message(request):
def dismiss_welcome_message(request): # pylint: disable=missing-function-docstring
course_id = request.data.get('course_id', None)

# If body doesn't contain 'course_id', return 400 to client.
Expand All @@ -402,14 +402,14 @@ def dismiss_welcome_message(request):
dismiss_current_update_for_user(request, course)
return Response({'message': _('Welcome message successfully dismissed.')})
except Exception:
raise UnableToDismissWelcomeMessage
raise UnableToDismissWelcomeMessage # pylint: disable=raise-missing-from


# Another version of this endpoint exists in ../course_goals/views.py
@api_view(['POST'])
@authentication_classes((JwtAuthentication, SessionAuthenticationAllowInactiveUser,))
@permission_classes((IsAuthenticated,))
def save_course_goal(request):
def save_course_goal(request): # pylint: disable=missing-function-docstring
course_id = request.data.get('course_id')
goal_key = request.data.get('goal_key')
days_per_week = request.data.get('days_per_week')
Expand All @@ -431,7 +431,7 @@ def save_course_goal(request):
'message': _('Course goal updated successfully.'),
})
except Exception:
raise UnableToSaveCourseGoal
raise UnableToSaveCourseGoal # pylint: disable=raise-missing-from

else:
# If body doesn't contain 'goal', return 400 to client.
Expand All @@ -445,7 +445,7 @@ def save_course_goal(request):
'message': _('Course goal updated successfully.'),
})
except Exception:
raise UnableToSaveCourseGoal
raise UnableToSaveCourseGoal # pylint: disable=raise-missing-from


@api_view(['POST'])
Expand Down
Empty file.
Empty file added lms/lib/tests/__init__.py
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pylint: disable=missing-module-docstring
import unittest
from unittest.mock import patch

Expand Down
Empty file.
1 change: 1 addition & 0 deletions openedx/core/djangoapps/course_apps/rest_api/v1/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pylint: disable=missing-module-docstring
import logging
from typing import Dict

Expand Down
Empty file.
Empty file.
38 changes: 26 additions & 12 deletions openedx/features/content_type_gating/tests/test_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from django.test.utils import override_settings
from django.urls import reverse
from django.utils import timezone
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from unittest.mock import patch, Mock
from pyquery import PyQuery as pq

Expand Down Expand Up @@ -51,6 +51,7 @@
CONTENT_GATING_PARTITION_ID: [CONTENT_TYPE_GATE_GROUP_IDS['full_access']]
}
}
User = get_user_model()


@patch("crum.get_current_request")
Expand Down Expand Up @@ -113,7 +114,7 @@ def _assert_block_is_gated(block, is_gated, user, course, request_factory, has_u
checkout_link = '#' if has_upgrade_link else None
for content_getter in (_get_content_from_fragment, _get_content_from_lms_index):
with patch.object(ContentTypeGatingPartition, '_get_checkout_link', return_value=checkout_link):
content = content_getter(block, user.id, course, request_factory)
content = content_getter(block, user.id, course, request_factory) # pylint: disable=no-value-for-parameter
if is_gated:
assert 'content-paywall' in content
if has_upgrade_link:
Expand Down Expand Up @@ -160,7 +161,7 @@ def _assert_block_is_empty(block, user_id, course, request_factory):
@override_settings(FIELD_OVERRIDE_PROVIDERS=(
'openedx.features.content_type_gating.field_override.ContentTypeGatingFieldOverride',
))
class TestProblemTypeAccess(SharedModuleStoreTestCase, MasqueradeMixin):
class TestProblemTypeAccess(SharedModuleStoreTestCase, MasqueradeMixin): # pylint: disable=missing-class-docstring

PROBLEM_TYPES = ['problem', 'openassessment', 'drag-and-drop-v2', 'done', 'edx_sga']
# 'html' is a component that just displays html, in these tests it is used to test that users who do not have access
Expand Down Expand Up @@ -800,9 +801,13 @@ def setUp(self):
self.student_audit_b = self.student_b

# Create verified students
self.student_verified_a = UserFactory.create(username='student_verified_a', email='student_verified_a@example.com')
self.student_verified_a = UserFactory.create(
username='student_verified_a', email='student_verified_a@example.com'
)
CourseEnrollmentFactory.create(user=self.student_verified_a, course_id=self.course.id, mode='verified')
self.student_verified_b = UserFactory.create(username='student_verified_b', email='student_verified_b@example.com')
self.student_verified_b = UserFactory.create(
username='student_verified_b', email='student_verified_b@example.com'
)
CourseEnrollmentFactory.create(user=self.student_verified_b, course_id=self.course.id, mode='verified')

# Put students into content gating groups
Expand Down Expand Up @@ -832,7 +837,8 @@ def setUp(self):

def test_access_based_on_conditional_content(self):
"""
If a user is enrolled as an audit user they should not have access to graded problems, including conditional content.
If a user is enrolled as an audit user they should not have access to graded problems,
including conditional content.
All paid type tracks should have access graded problems including conditional content.
"""

Expand Down Expand Up @@ -892,7 +898,7 @@ def setUp(self):
self.request_factory = RequestFactory()
ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))

def _create_course(self):
def _create_course(self): # pylint: disable=missing-function-docstring
course = CourseFactory.create(run='test', display_name='test')
CourseModeFactory.create(course_id=course.id, mode_slug='audit')
CourseModeFactory.create(course_id=course.id, mode_slug='verified')
Expand Down Expand Up @@ -1101,7 +1107,7 @@ def setUp(self):
self.request_factory = RequestFactory()
ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))

def _create_course(self):
def _create_course(self): # pylint: disable=missing-function-docstring
course = CourseFactory.create(run='test', display_name='test')
CourseModeFactory.create(course_id=course.id, mode_slug='audit')
CourseModeFactory.create(course_id=course.id, mode_slug='verified')
Expand Down Expand Up @@ -1150,10 +1156,14 @@ def test_content_type_gate_for_block(self):
)

# The method returns a content type gate for blocks that should be gated
assert 'content-paywall' in ContentTypeGatingService()._content_type_gate_for_block(self.user, blocks_dict['graded_1'], course['course'].id).content
assert 'content-paywall' in ContentTypeGatingService()._content_type_gate_for_block( # pylint: disable=protected-access
self.user, blocks_dict['graded_1'], course['course'].id
).content

# The method returns None for blocks that should not be gated
assert ContentTypeGatingService()._content_type_gate_for_block(self.user, blocks_dict['not_graded_1'], course['course'].id) is None
assert ContentTypeGatingService()._content_type_gate_for_block( # pylint: disable=protected-access
self.user, blocks_dict['not_graded_1'], course['course'].id
) is None

@patch.object(ContentTypeGatingService, '_get_user', return_value=UserFactory.build())
def test_check_children_for_content_type_gating_paywall(self, mocked_user): # pylint: disable=unused-argument
Expand All @@ -1173,7 +1183,9 @@ def test_check_children_for_content_type_gating_paywall(self, mocked_user): # p
)

# The method returns a content type gate for blocks that should be gated
assert ContentTypeGatingService().check_children_for_content_type_gating_paywall(blocks_dict['vertical'], course['course'].id) is None
assert ContentTypeGatingService().check_children_for_content_type_gating_paywall(
blocks_dict['vertical'], course['course'].id
) is None

blocks_dict['graded_1'] = ItemFactory.create(
parent=blocks_dict['vertical'],
Expand All @@ -1183,4 +1195,6 @@ def test_check_children_for_content_type_gating_paywall(self, mocked_user): # p
)

# The method returns None for blocks that should not be gated
assert 'content-paywall' in ContentTypeGatingService().check_children_for_content_type_gating_paywall(blocks_dict['vertical'], course['course'].id)
assert 'content-paywall' in ContentTypeGatingService().check_children_for_content_type_gating_paywall(
blocks_dict['vertical'], course['course'].id
)
Loading