diff --git a/lms/djangoapps/certificates/models.py b/lms/djangoapps/certificates/models.py index 9a42fc1048..736a648959 100644 --- a/lms/djangoapps/certificates/models.py +++ b/lms/djangoapps/certificates/models.py @@ -54,7 +54,6 @@ from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.db import models, transaction -from django.db.utils import IntegrityError from django.db.models import Count from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _ @@ -891,17 +890,10 @@ class CertificateGenerationCourseSetting(TimeStampedModel): is_enabled (boolean): Whether to enable or disable self-generated certificates. """ - certificate_generation_course_setting = CertificateGenerationCourseSetting(course_key=course_key, - enabled=is_enabled) - try: - with transaction.atomic(): - certificate_generation_course_setting.save() - except IntegrityError: - if is_enabled: - LOGGER.exception("Cannot enable self-generated certificates for course %s.", unicode(course_key)) - else: - LOGGER.exception("Cannot disable self-generated certificates for course %s.", unicode(course_key)) - pass + CertificateGenerationCourseSetting.objects.create( + course_key=course_key, + enabled=is_enabled + ) class CertificateGenerationConfiguration(ConfigurationModel): diff --git a/lms/djangoapps/certificates/signals.py b/lms/djangoapps/certificates/signals.py index 352df0a8ac..7ffa066a41 100644 --- a/lms/djangoapps/certificates/signals.py +++ b/lms/djangoapps/certificates/signals.py @@ -2,26 +2,24 @@ Signal handler for enabling/disabling self-generated certificates based on the course-pacing. """ from celery.task import task -from django.dispatch.dispatcher import receiver +from django.dispatch import receiver from certificates.models import CertificateGenerationCourseSetting -from openedx.core.djangoapps.content.course_overviews.models import CourseOverview, COURSE_OVERVIEW_UPDATED -from opaque_keys.edx.keys import CourseKey +from openedx.core.djangoapps.models.course_details import COURSE_PACING_CHANGE -@receiver(COURSE_OVERVIEW_UPDATED) -def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument - """ Catches the signal that a course overview table has been updated in database and - enable/disable the self-generated certificates according to course-pacing. +@receiver(COURSE_PACING_CHANGE, dispatch_uid="course_pacing_changed") +def _listen_for_course_publish(sender, course_key, course_self_paced, **kwargs): # pylint: disable=unused-argument """ - set_self_generated_certs.delay(unicode(course_key)) + Catches the signal that course pacing has changed and enable/disable + the self-generated certificates according to course-pacing. + """ + enable_self_generated_certs.delay(course_key, course_self_paced) @task() -def set_self_generated_certs(course_key): +def enable_self_generated_certs(course_key, course_self_paced): """ Enable or disable self-generated certificates for a course according to pacing. """ - course_key = CourseKey.from_string(course_key) - course = CourseOverview.get_from_id(course_key) - CertificateGenerationCourseSetting.set_enabled_for_course(course_key, course.self_paced) + CertificateGenerationCourseSetting.set_enabled_for_course(course_key, course_self_paced) diff --git a/lms/djangoapps/certificates/tests/test_signals.py b/lms/djangoapps/certificates/tests/test_signals.py index 6ddcb98e3d..b4ed25af89 100644 --- a/lms/djangoapps/certificates/tests/test_signals.py +++ b/lms/djangoapps/certificates/tests/test_signals.py @@ -29,7 +29,7 @@ class SelfGeneratedCertsSignalTest(ModuleStoreTestCase): """ self.assertFalse(certs_api.cert_generation_enabled(self.course.id)) - _listen_for_course_publish('store', self.course.id) + _listen_for_course_publish('store', self.course.id, self.course.self_paced) self.assertTrue(certs_api.cert_generation_enabled(self.course.id)) def test_cert_generation_disabled_for_instructor_paced(self): @@ -40,5 +40,5 @@ class SelfGeneratedCertsSignalTest(ModuleStoreTestCase): self.course.self_paced = False self.store.update_item(self.course, self.user.id) - _listen_for_course_publish('store', self.course.id) + _listen_for_course_publish('store', self.course.id, self.course.self_paced) self.assertFalse(certs_api.cert_generation_enabled(self.course.id)) diff --git a/openedx/core/djangoapps/content/course_overviews/models.py b/openedx/core/djangoapps/content/course_overviews/models.py index 168f190461..20330043ac 100644 --- a/openedx/core/djangoapps/content/course_overviews/models.py +++ b/openedx/core/djangoapps/content/course_overviews/models.py @@ -10,7 +10,6 @@ from django.db import models, transaction from django.db.models.fields import BooleanField, DateTimeField, DecimalField, TextField, FloatField, IntegerField from django.db.utils import IntegrityError from django.template import defaultfilters -from django.dispatch import Signal from ccx_keys.locator import CCXLocator from model_utils.models import TimeStampedModel @@ -26,7 +25,6 @@ from xmodule.error_module import ErrorDescriptor from xmodule.modulestore.django import modulestore from openedx.core.djangoapps.xmodule_django.models import CourseKeyField, UsageKeyField -COURSE_OVERVIEW_UPDATED = Signal(providing_args=["course_key"]) log = logging.getLogger(__name__) @@ -647,12 +645,6 @@ class CourseOverview(TimeStampedModel): """Represent ourselves with the course key.""" return unicode(self.id) - def send_signal(self): - """ - Sends out the signal that course_overview table has been updated. - """ - COURSE_OVERVIEW_UPDATED.send(sender=None, course_key=self.id) - class CourseOverviewTab(models.Model): """ diff --git a/openedx/core/djangoapps/content/course_overviews/signals.py b/openedx/core/djangoapps/content/course_overviews/signals.py index aab9bbafae..f32cf24848 100644 --- a/openedx/core/djangoapps/content/course_overviews/signals.py +++ b/openedx/core/djangoapps/content/course_overviews/signals.py @@ -11,11 +11,9 @@ from xmodule.modulestore.django import SignalHandler def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument """ Catches the signal that a course has been published in Studio and - updates the corresponding CourseOverview cache entry. Also sends out - the signal that course_overview table has been updated. + updates the corresponding CourseOverview cache entry. """ - course_overview = CourseOverview.load_from_module_store(course_key) - course_overview.send_signal() + CourseOverview.load_from_module_store(course_key) @receiver(SignalHandler.course_deleted) diff --git a/openedx/core/djangoapps/models/course_details.py b/openedx/core/djangoapps/models/course_details.py index 6f0a2de250..1bbc39ac3d 100644 --- a/openedx/core/djangoapps/models/course_details.py +++ b/openedx/core/djangoapps/models/course_details.py @@ -5,6 +5,7 @@ import re import logging from django.conf import settings +from django.dispatch import Signal from xmodule.fields import Date from xmodule.modulestore.exceptions import ItemNotFoundError @@ -12,6 +13,8 @@ from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.lib.courses import course_image_url from xmodule.modulestore.django import modulestore +COURSE_PACING_CHANGE = Signal(providing_args=["course_key", "course_self_paced"]) + # This list represents the attribute keys for a course's 'about' info. # Note: The 'video' attribute is intentionally excluded as it must be @@ -188,6 +191,7 @@ class CourseDetails(object): descriptor = module_store.get_course(course_key) dirty = False + is_pacing_changed = False # In the descriptor's setter, the date is converted to JSON # using Date's to_json method. Calling to_json on something that @@ -271,6 +275,7 @@ class CourseDetails(object): and jsondict['self_paced'] != descriptor.self_paced): descriptor.self_paced = jsondict['self_paced'] dirty = True + is_pacing_changed = True if dirty: module_store.update_item(descriptor, user.id) @@ -285,6 +290,10 @@ class CourseDetails(object): cls.update_about_video(descriptor, jsondict['intro_video'], user.id) + if is_pacing_changed: + # sends out the signal that course pacing has changed + COURSE_PACING_CHANGE.send(sender=None, course_key=course_key, course_self_paced=descriptor.self_paced) + # Could just return jsondict w/o doing any db reads, but I put # the reads in as a means to confirm it persisted correctly return CourseDetails.fetch(course_key)