diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py index 2ce7519885..537318b393 100644 --- a/lms/djangoapps/certificates/api.py +++ b/lms/djangoapps/certificates/api.py @@ -29,6 +29,7 @@ from lms.djangoapps.certificates.models import ( certificate_status_for_student ) from lms.djangoapps.certificates.queue import XQueueCertInterface +from lms.djangoapps.instructor.access import list_with_level 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 @@ -172,13 +173,21 @@ def generate_user_certificates(student, course_key, course=None, insecure=False, forced_grade - a string indicating to replace grade parameter. if present grading will be skipped. """ - xqueue = XQueueCertInterface() - if insecure: - xqueue.use_https = False if not course: course = modulestore().get_course(course_key, depth=0) + beta_testers_queryset = list_with_level(course, u'beta') + + if beta_testers_queryset.filter(username=student.username): + message = u'Cancelling course certificate generation for user [{}] against course [{}], user is a Beta Tester.' + log.info(message.format(course_key, student.username)) + return + + xqueue = XQueueCertInterface() + if insecure: + xqueue.use_https = False + generate_pdf = not has_html_certificates_enabled(course) cert = xqueue.add_cert( diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 0c76a6e4af..e623632bb6 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -24,12 +24,15 @@ from django.test import RequestFactory, TestCase from django.test.utils import override_settings from django.urls import reverse as django_reverse from django.utils.translation import ugettext as _ +from edx_when.api import get_overrides_for_user +from edx_when.signals import extract_dates from mock import Mock, NonCallableMock, patch from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import UsageKey from pytz import UTC from six import text_type, unichr # pylint: disable=redefined-builtin from six.moves import range, zip +from testfixtures import LogCapture from bulk_email.models import BulkEmailFlag, CourseEmail, CourseEmailTemplate from course_modes.models import CourseMode @@ -43,8 +46,7 @@ from courseware.tests.factories import ( UserProfileFactory ) from courseware.tests.helpers import LoginEnrollmentTestCase -from edx_when.api import get_overrides_for_user -from edx_when.signals import extract_dates +from lms.djangoapps.certificates.api import generate_user_certificates from lms.djangoapps.certificates.models import CertificateStatuses from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory from lms.djangoapps.instructor.tests.utils import FakeContentTask, FakeEmail, FakeEmailInfo @@ -2011,6 +2013,18 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll # (comment because pylint C0103(invalid-name)) # self.maxDiff = None + def test_beta_tester_must_not_earn_cert(self): + """ + Test to ensure that beta tester must not earn certificate in a course + in which he/she is a beta-tester. + """ + with LogCapture() as capture: + message = u'Cancelling course certificate generation for user [{}] against course [{}], ' \ + u'user is a Beta Tester.' + message = message.format(self.course.id, self.beta_tester.username) + generate_user_certificates(self.beta_tester, self.course.id, self.course) + capture.check_present(('edx.certificate', 'INFO', message)) + def test_missing_params(self): """ Test missing all query parameters. """ url = reverse('bulk_beta_modify_access', kwargs={'course_id': text_type(self.course.id)}) diff --git a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py index 1bf308fda9..8a29c442d8 100644 --- a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py +++ b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py @@ -16,9 +16,6 @@ from contextlib import contextmanager from datetime import datetime, timedelta import ddt -from six import text_type -from six.moves.urllib.parse import quote # pylint: disable=import-error -from six.moves import range, zip import unicodecsv from django.conf import settings from django.test.utils import override_settings @@ -27,17 +24,20 @@ from edx_django_utils.cache import RequestCache from freezegun import freeze_time from mock import ANY, MagicMock, Mock, patch from pytz import UTC +from six import text_type +from six.moves import range, zip +from six.moves.urllib.parse import quote # pylint: disable=import-error import openedx.core.djangoapps.user_api.course_tag.api as course_tag_api from capa.tests.response_xml_factory import MultipleChoiceResponseXMLFactory from course_modes.models import CourseMode from course_modes.tests.factories import CourseModeFactory from courseware.tests.factories import InstructorFactory -from lms.djangoapps.instructor_analytics.basic import UNAVAILABLE, list_problem_responses from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate from lms.djangoapps.certificates.tests.factories import CertificateWhitelistFactory, GeneratedCertificateFactory from lms.djangoapps.grades.models import PersistentCourseGrade from lms.djangoapps.grades.transformer import GradesTransformer +from lms.djangoapps.instructor_analytics.basic import UNAVAILABLE, list_problem_responses from lms.djangoapps.instructor_task.tasks_helper.certs import generate_students_certificates from lms.djangoapps.instructor_task.tasks_helper.enrollments import ( upload_enrollment_report, @@ -2175,7 +2175,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase): 'failed': 3, 'skipped': 2 } - with self.assertNumQueries(122): + with self.assertNumQueries(130): self.assertCertificatesGenerated(task_input, expected_results) expected_results = {