From 91282b8af0b0b5ac2f8fd3eaae8b3888fb51c0d6 Mon Sep 17 00:00:00 2001 From: Nicholas D'Alfonso Date: Thu, 27 Aug 2020 13:48:49 -0400 Subject: [PATCH 1/2] AA-196 course celebration cert --- .../djangoapps/courseware_api/serializers.py | 4 +++ .../core/djangoapps/courseware_api/views.py | 30 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/openedx/core/djangoapps/courseware_api/serializers.py b/openedx/core/djangoapps/courseware_api/serializers.py index a674ebb006..ae0bfc51f2 100644 --- a/openedx/core/djangoapps/courseware_api/serializers.py +++ b/openedx/core/djangoapps/courseware_api/serializers.py @@ -4,6 +4,7 @@ Course API Serializers. Representing course catalog data from rest_framework import serializers +from lms.djangoapps.course_home_api.progress.v1.serializers import CertificateDataSerializer from openedx.core.lib.api.fields import AbsoluteURLField @@ -90,6 +91,9 @@ class CourseInfoSerializer(serializers.Serializer): # pylint: disable=abstract- notes = serializers.DictField() marketing_url = serializers.CharField() celebrations = serializers.DictField() + user_has_passing_grade = serializers.BooleanField() + course_completion_is_active = serializers.BooleanField() + certificate_data = CertificateDataSerializer() def __init__(self, *args, **kwargs): """ diff --git a/openedx/core/djangoapps/courseware_api/views.py b/openedx/core/djangoapps/courseware_api/views.py index eccecd4387..386c11de2c 100644 --- a/openedx/core/djangoapps/courseware_api/views.py +++ b/openedx/core/djangoapps/courseware_api/views.py @@ -26,13 +26,15 @@ from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access_response import ( CoursewareMicrofrontendDisabledAccessError, ) -from lms.djangoapps.courseware.courses import check_course_access, get_course_by_id +from lms.djangoapps.courseware.courses import check_course_access, get_course_by_id, get_course_with_access from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.module_render import get_module_by_usage_id from lms.djangoapps.courseware.tabs import get_course_tab_list -from lms.djangoapps.courseware.toggles import REDIRECT_TO_COURSEWARE_MICROFRONTEND +from lms.djangoapps.courseware.toggles import REDIRECT_TO_COURSEWARE_MICROFRONTEND, course_completion_is_active from lms.djangoapps.courseware.utils import can_show_verified_upgrade from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link +from lms.djangoapps.courseware.views.views import get_cert_data +from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG from openedx.features.content_type_gating.models import ContentTypeGatingConfig @@ -67,6 +69,7 @@ class CoursewareMeta: ) self.is_staff = has_access(user, 'staff', self.overview).has_access self.course_masquerade = course_masquerade + self.request = request def __getattr__(self, name): return getattr(self.overview, name) @@ -208,6 +211,25 @@ class CoursewareMeta: 'first_section': CourseEnrollmentCelebration.should_celebrate_first_section(self.enrollment_object), } + @property + def user_has_passing_grade(self): + course = get_course_by_id(self.course_key) + user_grade = CourseGradeFactory().read(self.request.user, course).percent + + return user_grade >= course.lowest_passing_grade + + @property + def course_completion_is_active(self): + return course_completion_is_active(self.course_key) + + @property + def certificate_data(self): + course = get_course_by_id(self.course_key) + enrollment_mode, _ = CourseEnrollment.enrollment_mode_for_user(self.request.user, self.course_key) + course_grade = CourseGradeFactory().read(self.request.user, course) + + return get_cert_data(self.request.user, course, enrollment_mode, course_grade) + class CoursewareInformation(RetrieveAPIView): """ @@ -252,6 +274,10 @@ class CoursewareInformation(RetrieveAPIView): * can_load_course: Whether the user can view the course (AccessResponse object) * is_staff: Whether the effective user has staff access to the course * original_user_is_staff: Whether the original user has staff access to the course + * user_has_passing_grade: Whether or not users grade is equal to or above the courses minimum passing grade + * course_completion_is_active: Flag for the learning mfe on whether or not the course completion page should + display + * certificate_data: data regarding the users certificate for the given course **Parameters:** From a96079f2d14189d468f6635d8d5683edd78c1227 Mon Sep 17 00:00:00 2001 From: Dillon Dumesnil Date: Fri, 18 Sep 2020 14:53:51 -0400 Subject: [PATCH 2/2] AA-196: Course Celebration for passing Verified Learners --- lms/djangoapps/certificates/api.py | 11 ++- lms/djangoapps/certificates/tests/test_api.py | 15 ++-- .../progress/v1/serializers.py | 9 +-- .../progress/v1/tests/test_views.py | 3 + lms/djangoapps/courseware/tests/test_views.py | 18 ++++- lms/djangoapps/courseware/toggles.py | 23 +++++++ lms/djangoapps/courseware/views/views.py | 15 ++++ .../djangoapps/courseware_api/serializers.py | 3 +- .../courseware_api/tests/test_views.py | 15 ++++ .../core/djangoapps/courseware_api/views.py | 68 ++++++++++++------- scripts/thresholds.sh | 2 +- 11 files changed, 136 insertions(+), 46 deletions(-) diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py index 56fd44bf89..60e0f63387 100644 --- a/lms/djangoapps/certificates/api.py +++ b/lms/djangoapps/certificates/api.py @@ -30,6 +30,7 @@ from lms.djangoapps.certificates.models import ( ) from lms.djangoapps.certificates.queue import XQueueCertInterface from lms.djangoapps.instructor.access import list_with_level +from openedx.core.djangoapps.certificates.api import certificates_viewable_for_course from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from util.organizations_helpers import get_course_organization_id from xmodule.modulestore.django import modulestore @@ -308,8 +309,16 @@ def certificate_downloadable_status(student, course_key): 'download_url': None, 'uuid': None, } - may_view_certificate = CourseOverview.get_from_id(course_key).may_certify() + course_overview = CourseOverview.get_from_id(course_key) + if ( + not certificates_viewable_for_course(course_overview) and + (current_status['status'] in CertificateStatuses.PASSED_STATUSES) and + course_overview.certificate_available_date + ): + response_data['earned_but_not_available'] = True + + may_view_certificate = course_overview.may_certify() if current_status['status'] == CertificateStatuses.downloadable and may_view_certificate: response_data['is_downloadable'] = True response_data['download_url'] = current_status['download_url'] or get_certificate_url( diff --git a/lms/djangoapps/certificates/tests/test_api.py b/lms/djangoapps/certificates/tests/test_api.py index ff7eb85645..1eb58fbf4f 100644 --- a/lms/djangoapps/certificates/tests/test_api.py +++ b/lms/djangoapps/certificates/tests/test_api.py @@ -206,13 +206,13 @@ class CertificateDownloadableStatusTests(WebCertificateTestMixin, ModuleStoreTes ) @ddt.data( - (False, timedelta(days=2), False), - (False, -timedelta(days=2), True), - (True, timedelta(days=2), True) + (False, timedelta(days=2), False, True), + (False, -timedelta(days=2), True, None), + (True, timedelta(days=2), True, None) ) @ddt.unpack @patch.dict(settings.FEATURES, {'CERTIFICATES_HTML_VIEW': True}) - def test_cert_api_return(self, self_paced, cert_avail_delta, cert_downloadable_status): + def test_cert_api_return(self, self_paced, cert_avail_delta, cert_downloadable_status, earned_but_not_available): """ Test 'downloadable status' """ @@ -226,10 +226,9 @@ class CertificateDownloadableStatusTests(WebCertificateTestMixin, ModuleStoreTes with mock_passing_grade(): certs_api.generate_user_certificates(self.student, self.course.id) - self.assertEqual( - certs_api.certificate_downloadable_status(self.student, self.course.id)['is_downloadable'], - cert_downloadable_status - ) + downloadable_status = certs_api.certificate_downloadable_status(self.student, self.course.id) + self.assertEqual(downloadable_status['is_downloadable'], cert_downloadable_status) + self.assertEqual(downloadable_status.get('earned_but_not_available'), earned_but_not_available) @ddt.ddt diff --git a/lms/djangoapps/course_home_api/progress/v1/serializers.py b/lms/djangoapps/course_home_api/progress/v1/serializers.py index 09283799b5..ca4bb108fd 100644 --- a/lms/djangoapps/course_home_api/progress/v1/serializers.py +++ b/lms/djangoapps/course_home_api/progress/v1/serializers.py @@ -52,19 +52,12 @@ class ChapterSerializer(serializers.Serializer): class CertificateDataSerializer(serializers.Serializer): + cert_status = serializers.CharField() cert_web_view_url = serializers.CharField() download_url = serializers.CharField() - is_downloadable = serializers.SerializerMethodField() - is_requestable = serializers.SerializerMethodField() msg = serializers.CharField() title = serializers.CharField() - def get_is_downloadable(self, cert_data): - return cert_data.cert_status == CertificateStatuses.downloadable and cert_data.download_url is not None - - def get_is_requestable(self, cert_data): - return cert_data.cert_status == CertificateStatuses.requesting and cert_data.request_cert_url is not None - class CreditRequirementSerializer(serializers.Serializer): """ diff --git a/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py b/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py index a30d34208e..93beb59191 100644 --- a/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py +++ b/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py @@ -46,6 +46,9 @@ class ProgressTabTestViews(BaseCourseHomeTests): ManualVerification.objects.create(user=self.user, status='approved') response = self.client.get(self.url) self.assertEqual(response.data['verification_data']['status'], 'approved') + self.assertIsNone(response.data['certificate_data']) + elif enrollment_mode == CourseMode.AUDIT: + self.assertEqual(response.data['certificate_data']['cert_status'], 'audit_passing') def test_get_authenticated_user_not_enrolled(self): response = self.client.get(self.url) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 39713c9579..b1b1eb946b 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -1759,6 +1759,20 @@ class ProgressPageTests(ProgressPageBaseTests): self.assertEqual(response.cert_status, 'requesting') self.assertEqual(response.title, "Congratulations, you qualified for a certificate!") + def test_earned_but_not_available_get_cert_data(self): + """ + Verify that earned but not available cert data is returned if cert has been earned, but isn't available. + """ + self.generate_certificate( + "http://www.example.com/certificate.pdf", "verified" + ) + with patch('lms.djangoapps.certificates.api.certificate_downloadable_status', + return_value=self.mock_certificate_downloadable_status(earned_but_not_available=True)): + response = views.get_cert_data(self.user, self.course, CourseMode.VERIFIED, MagicMock(passed=True)) + + self.assertEqual(response.cert_status, 'earned_but_not_available') + self.assertEqual(response.title, "Your certificate will be available soon!") + def assert_invalidate_certificate(self, certificate): """ Dry method to mark certificate as invalid. And assert the response. """ CertificateInvalidationFactory.create( @@ -1790,7 +1804,8 @@ class ProgressPageTests(ProgressPageBaseTests): return generated_certificate def mock_certificate_downloadable_status( - self, is_downloadable=False, is_generating=False, is_unverified=False, uuid=None, download_url=None + self, is_downloadable=False, is_generating=False, is_unverified=False, uuid=None, download_url=None, + earned_but_not_available=None, ): """Dry method to mock certificate downloadable status response.""" return { @@ -1799,6 +1814,7 @@ class ProgressPageTests(ProgressPageBaseTests): 'is_unverified': is_unverified, 'download_url': uuid, 'uuid': download_url, + 'earned_but_not_available': earned_but_not_available, } diff --git a/lms/djangoapps/courseware/toggles.py b/lms/djangoapps/courseware/toggles.py index a80eacaf00..d700a395fe 100644 --- a/lms/djangoapps/courseware/toggles.py +++ b/lms/djangoapps/courseware/toggles.py @@ -38,3 +38,26 @@ REDIRECT_TO_COURSEWARE_MICROFRONTEND = ExperimentWaffleFlag( COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW = CourseWaffleFlag( WAFFLE_FLAG_NAMESPACE, 'microfrontend_course_team_preview', __name__ ) + +# Waffle flag to enable the course exit page in the learning MFE. +# +# .. toggle_name: courseware.microfrontend_course_exit_page +# .. toggle_implementation: CourseWaffleFlag +# .. toggle_default: False +# .. toggle_description: Supports staged rollout of the new micro-frontend-based implementation of the course exit page. +# .. toggle_category: micro-frontend +# .. toggle_use_cases: incremental_release, open_edx +# .. toggle_creation_date: 2020-10-02 +# .. toggle_target_removal_date: n/a +# .. toggle_warnings: Also set settings.LEARNING_MICROFRONTEND_URL and ENABLE_COURSEWARE_MICROFRONTEND. +# .. toggle_tickets: AA-188 +COURSEWARE_MICROFRONTEND_COURSE_EXIT_PAGE = CourseWaffleFlag( + WAFFLE_FLAG_NAMESPACE, 'microfrontend_course_exit_page', __name__ +) + + +def course_exit_page_is_active(course_key): + return ( + REDIRECT_TO_COURSEWARE_MICROFRONTEND.is_enabled(course_key) and + COURSEWARE_MICROFRONTEND_COURSE_EXIT_PAGE.is_enabled(course_key) + ) diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 27857895b0..6baab743f0 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -144,6 +144,7 @@ REQUIREMENTS_DISPLAY_MODES = CourseMode.CREDIT_MODES + [CourseMode.VERIFIED] CertData = namedtuple( "CertData", ["cert_status", "title", "msg", "download_url", "cert_web_view_url"] ) +EARNED_BUT_NOT_AVAILABLE_CERT_STATUS = 'earned_but_not_available' AUDIT_PASSING_CERT_DATA = CertData( CertificateStatuses.audit_passing, @@ -204,6 +205,14 @@ UNVERIFIED_CERT_DATA = CertData( cert_web_view_url=None ) +EARNED_BUT_NOT_AVAILABLE_CERT_DATA = CertData( + EARNED_BUT_NOT_AVAILABLE_CERT_STATUS, + _('Your certificate will be available soon!'), + _('After this course officially ends, you will receive an email notification with your certificate.'), + download_url=None, + cert_web_view_url=None +) + def _downloadable_cert_data(download_url=None, cert_web_view_url=None): return CertData( @@ -1206,6 +1215,9 @@ def _certificate_message(student, course, enrollment_mode): cert_downloadable_status = certs_api.certificate_downloadable_status(student, course.id) + if cert_downloadable_status.get('earned_but_not_available'): + return EARNED_BUT_NOT_AVAILABLE_CERT_DATA + if cert_downloadable_status['is_generating']: return GENERATING_CERT_DATA @@ -1235,6 +1247,9 @@ def get_cert_data(student, course, enrollment_mode, course_grade=None): if not CourseMode.is_eligible_for_certificate(enrollment_mode, status=cert_data.cert_status): return INELIGIBLE_PASSING_CERT_DATA.get(enrollment_mode) + if cert_data.cert_status == EARNED_BUT_NOT_AVAILABLE_CERT_STATUS: + return cert_data + certificates_enabled_for_course = certs_api.cert_generation_enabled(course.id) if course_grade is None: course_grade = CourseGradeFactory().read(student, course) diff --git a/openedx/core/djangoapps/courseware_api/serializers.py b/openedx/core/djangoapps/courseware_api/serializers.py index ae0bfc51f2..b3396aaff5 100644 --- a/openedx/core/djangoapps/courseware_api/serializers.py +++ b/openedx/core/djangoapps/courseware_api/serializers.py @@ -92,8 +92,9 @@ class CourseInfoSerializer(serializers.Serializer): # pylint: disable=abstract- marketing_url = serializers.CharField() celebrations = serializers.DictField() user_has_passing_grade = serializers.BooleanField() - course_completion_is_active = serializers.BooleanField() + course_exit_page_is_active = serializers.BooleanField() certificate_data = CertificateDataSerializer() + verify_identity_url = AbsoluteURLField() def __init__(self, *args, **kwargs): """ diff --git a/openedx/core/djangoapps/courseware_api/tests/test_views.py b/openedx/core/djangoapps/courseware_api/tests/test_views.py index 0a5777138a..908a00086a 100644 --- a/openedx/core/djangoapps/courseware_api/tests/test_views.py +++ b/openedx/core/djangoapps/courseware_api/tests/test_views.py @@ -8,6 +8,7 @@ import ddt import mock from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing from django.conf import settings +from django.urls import reverse from lms.djangoapps.courseware.access_utils import ACCESS_DENIED, ACCESS_GRANTED from lms.djangoapps.courseware.tabs import ExternalLinkCourseTab @@ -105,6 +106,20 @@ class CourseApiTestViews(BaseCoursewareTests): if tab['url'] == 'http://zombo.com': found = True assert found, 'external link not in course tabs' + + assert not response.data['user_has_passing_grade'] + if enrollment_mode == 'audit': + # This message comes from AUDIT_PASSING_CERT_DATA in lms/djangoapps/courseware/views/views.py + expected_audit_message = ('You are enrolled in the audit track for this course. ' + 'The audit track does not include a certificate.') + assert response.data['certificate_data']['msg'] == expected_audit_message + assert response.data['verify_identity_url'] is None + else: + # Not testing certificate data for verified learner here. That is tested elsewhere + assert response.data['certificate_data'] is None + expected_verify_identity_url = reverse('verify_student_verify_now', args=[self.course.id]) + # The response contains an absolute URL so this is only checking the path of the final + assert expected_verify_identity_url in response.data['verify_identity_url'] elif enable_anonymous and not logged_in: # multiple checks use this handler check_public_access.assert_called() diff --git a/openedx/core/djangoapps/courseware_api/views.py b/openedx/core/djangoapps/courseware_api/views.py index 386c11de2c..9db64fdf5b 100644 --- a/openedx/core/djangoapps/courseware_api/views.py +++ b/openedx/core/djangoapps/courseware_api/views.py @@ -26,15 +26,16 @@ from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access_response import ( CoursewareMicrofrontendDisabledAccessError, ) -from lms.djangoapps.courseware.courses import check_course_access, get_course_by_id, get_course_with_access +from lms.djangoapps.courseware.courses import check_course_access, get_course_by_id from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.module_render import get_module_by_usage_id from lms.djangoapps.courseware.tabs import get_course_tab_list -from lms.djangoapps.courseware.toggles import REDIRECT_TO_COURSEWARE_MICROFRONTEND, course_completion_is_active +from lms.djangoapps.courseware.toggles import REDIRECT_TO_COURSEWARE_MICROFRONTEND, course_exit_page_is_active from lms.djangoapps.courseware.utils import can_show_verified_upgrade from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link from lms.djangoapps.courseware.views.views import get_cert_data -from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory +from lms.djangoapps.grades.api import CourseGradeFactory +from lms.djangoapps.verify_student.services import IDVerificationService from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG from openedx.features.content_type_gating.models import ContentTypeGatingConfig @@ -57,19 +58,16 @@ class CoursewareMeta: username or request.user.username, course_key, ) - self.effective_user = self.overview.effective_user self.original_user_is_staff = has_access(request.user, 'staff', self.overview).has_access self.course_key = course_key - self.enrollment_object = CourseEnrollment.get_enrollment(self.effective_user, self.course_key, - select_related=['celebration']) - course_masquerade, user = setup_masquerade( + self.course_masquerade, self.effective_user = setup_masquerade( request, course_key, staff_access=self.original_user_is_staff, ) - self.is_staff = has_access(user, 'staff', self.overview).has_access - self.course_masquerade = course_masquerade - self.request = request + self.is_staff = has_access(self.effective_user, 'staff', self.overview).has_access + self.enrollment_object = CourseEnrollment.get_enrollment(self.effective_user, self.course_key, + select_related=['celebration']) def __getattr__(self, name): return getattr(self.overview, name) @@ -107,14 +105,12 @@ class CoursewareMeta: """ Return enrollment information. """ - if self.effective_user.is_anonymous: + if self.effective_user.is_anonymous or not self.enrollment_object: mode = None is_active = False else: - mode, is_active = CourseEnrollment.enrollment_mode_for_user( - self.effective_user, - self.course_key - ) + mode = self.enrollment_object.mode + is_active = self.enrollment_object.is_active return {'mode': mode, 'is_active': is_active} @property @@ -213,22 +209,40 @@ class CoursewareMeta: @property def user_has_passing_grade(self): + """ Returns a boolean on if the effective_user has a passing grade in the course """ course = get_course_by_id(self.course_key) - user_grade = CourseGradeFactory().read(self.request.user, course).percent - + user_grade = CourseGradeFactory().read(self.effective_user, course).percent return user_grade >= course.lowest_passing_grade @property - def course_completion_is_active(self): - return course_completion_is_active(self.course_key) + def course_exit_page_is_active(self): + """ Returns a boolean on if the course exit page is active """ + return course_exit_page_is_active(self.course_key) @property def certificate_data(self): + """ + Returns certificate data if the effective_user is enrolled. + Note: certificate data can be None depending on learner and/or course state. + """ course = get_course_by_id(self.course_key) - enrollment_mode, _ = CourseEnrollment.enrollment_mode_for_user(self.request.user, self.course_key) - course_grade = CourseGradeFactory().read(self.request.user, course) + if self.enrollment_object: + return get_cert_data(self.effective_user, course, self.enrollment_object.mode) - return get_cert_data(self.request.user, course, enrollment_mode, course_grade) + @property + def verify_identity_url(self): + """ + Returns a String to the location to verify a learner's identity + Note: This might return an absolute URL (if the verification MFE is enabled) or a relative + URL. The serializer will make the relative URL absolute so any consumers can treat this + as a full URL. + """ + if self.enrollment_object and self.enrollment_object.mode in CourseMode.VERIFIED_MODES: + verification_status = IDVerificationService.user_status(self.effective_user)['status'] + if verification_status == 'must_reverify': + return IDVerificationService.get_verify_location('verify_student_reverify') + else: + return IDVerificationService.get_verify_location('verify_student_verify_now', self.course_key) class CoursewareInformation(RetrieveAPIView): @@ -274,10 +288,12 @@ class CoursewareInformation(RetrieveAPIView): * can_load_course: Whether the user can view the course (AccessResponse object) * is_staff: Whether the effective user has staff access to the course * original_user_is_staff: Whether the original user has staff access to the course - * user_has_passing_grade: Whether or not users grade is equal to or above the courses minimum passing grade - * course_completion_is_active: Flag for the learning mfe on whether or not the course completion page should - display - * certificate_data: data regarding the users certificate for the given course + * user_has_passing_grade: Whether or not the effective user's grade is equal to or above the courses minimum + passing grade + * course_exit_page_is_active: Flag for the learning mfe on whether or not the course exit page should display + * certificate_data: data regarding the effective user's certificate for the given course + * verify_identity_url: URL for a learner to verify their identity. Only returned for learners enrolled in a + verified mode. Will update to reverify URL if necessary. **Parameters:** diff --git a/scripts/thresholds.sh b/scripts/thresholds.sh index b286667852..52dac4f8b4 100755 --- a/scripts/thresholds.sh +++ b/scripts/thresholds.sh @@ -2,6 +2,6 @@ set -e export LOWER_PYLINT_THRESHOLD=1000 -export UPPER_PYLINT_THRESHOLD=2560 +export UPPER_PYLINT_THRESHOLD=2500 export ESLINT_THRESHOLD=5530 export STYLELINT_THRESHOLD=880