diff --git a/openedx/core/djangoapps/schedules/admin.py b/openedx/core/djangoapps/schedules/admin.py index d1485e519e..e6cb1bfc12 100644 --- a/openedx/core/djangoapps/schedules/admin.py +++ b/openedx/core/djangoapps/schedules/admin.py @@ -4,12 +4,17 @@ from django.utils.translation import ugettext_lazy as _ from . import models +class ScheduleExperienceAdminInline(admin.StackedInline): + model = models.ScheduleExperience + + @admin.register(models.Schedule) class ScheduleAdmin(admin.ModelAdmin): list_display = ('username', 'course_id', 'active', 'start', 'upgrade_deadline') raw_id_fields = ('enrollment',) readonly_fields = ('modified',) search_fields = ('enrollment__user__username', 'enrollment__course_id',) + inlines = (ScheduleExperienceAdminInline,) def username(self, obj): return obj.enrollment.user.username diff --git a/openedx/core/djangoapps/schedules/migrations/0006_scheduleexperience.py b/openedx/core/djangoapps/schedules/migrations/0006_scheduleexperience.py new file mode 100644 index 0000000000..4ffca66d46 --- /dev/null +++ b/openedx/core/djangoapps/schedules/migrations/0006_scheduleexperience.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('schedules', '0005_auto_20171010_1722'), + ] + + operations = [ + migrations.CreateModel( + name='ScheduleExperience', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('experience_type', models.IntegerField(default=0, choices=[(0, b'Recurring Nudge and Upgrade Reminder'), (1, b'Course Updates')])), + ('schedule', models.OneToOneField(related_name='experience', to='schedules.Schedule')), + ], + ), + ] diff --git a/openedx/core/djangoapps/schedules/models.py b/openedx/core/djangoapps/schedules/models.py index 7248e98754..eff9fabd2d 100644 --- a/openedx/core/djangoapps/schedules/models.py +++ b/openedx/core/djangoapps/schedules/models.py @@ -6,6 +6,13 @@ from model_utils.models import TimeStampedModel from config_models.models import ConfigurationModel +EXPERIENCE_TYPES = ( + (0, 'Recurring Nudge and Upgrade Reminder'), + (1, 'Course Updates'), +) +DEFAULT_EXPERIENCE_TYPE = EXPERIENCE_TYPES[0][0] + + class Schedule(TimeStampedModel): enrollment = models.OneToOneField('student.CourseEnrollment', null=False) active = models.BooleanField( @@ -23,6 +30,12 @@ class Schedule(TimeStampedModel): help_text=_('Deadline by which the learner must upgrade to a verified seat') ) + def get_experience_type(self): + if (hasattr(self, 'experience')): + return self.experience.experience_type + else: + return DEFAULT_EXPERIENCE_TYPE + class Meta(object): verbose_name = _('Schedule') verbose_name_plural = _('Schedules') @@ -39,3 +52,8 @@ class ScheduleConfig(ConfigurationModel): deliver_upgrade_reminder = models.BooleanField(default=False) enqueue_course_update = models.BooleanField(default=False) deliver_course_update = models.BooleanField(default=False) + + +class ScheduleExperience(models.Model): + schedule = models.OneToOneField(Schedule, related_name='experience') + experience_type = models.IntegerField(choices=EXPERIENCE_TYPES, default=DEFAULT_EXPERIENCE_TYPE) diff --git a/openedx/core/djangoapps/schedules/resolvers.py b/openedx/core/djangoapps/schedules/resolvers.py index d2da8f31da..4770ef32ec 100644 --- a/openedx/core/djangoapps/schedules/resolvers.py +++ b/openedx/core/djangoapps/schedules/resolvers.py @@ -18,7 +18,7 @@ from courseware.date_summary import verified_upgrade_deadline_link, verified_upg from openedx.core.djangoapps.monitoring_utils import function_trace, set_custom_metric from openedx.core.djangoapps.schedules.config import COURSE_UPDATE_WAFFLE_FLAG from openedx.core.djangoapps.schedules.exceptions import CourseUpdateDoesNotExist -from openedx.core.djangoapps.schedules.models import Schedule +from openedx.core.djangoapps.schedules.models import DEFAULT_EXPERIENCE_TYPE, EXPERIENCE_TYPES, Schedule from openedx.core.djangoapps.schedules.utils import PrefixedDebugLoggerMixin from openedx.core.djangoapps.schedules.template_context import ( absolute_url, @@ -64,6 +64,7 @@ class BinnedSchedulesBaseResolver(PrefixedDebugLoggerMixin, RecipientResolver): relative to. For example, if this resolver finds schedules that started 7 days ago this variable should be set to "start". num_bins -- the int number of bins to split the users into + experience_type -- the string name for the experience type that users will be filtered to """ async_send_task = attr.ib() site = attr.ib() @@ -74,6 +75,7 @@ class BinnedSchedulesBaseResolver(PrefixedDebugLoggerMixin, RecipientResolver): schedule_date_field = None num_bins = DEFAULT_NUM_BINS + experience_type = DEFAULT_EXPERIENCE_TYPE def __attrs_post_init__(self): # TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here @@ -123,10 +125,14 @@ class BinnedSchedulesBaseResolver(PrefixedDebugLoggerMixin, RecipientResolver): 'enrollment__user__profile', 'enrollment__course', ).prefetch_related( - 'enrollment__course__modes' + 'enrollment__course__modes', + 'experience', ).filter( Q(enrollment__course__end__isnull=True) | Q( enrollment__course__end__gte=self.current_datetime), + Q(experience__isnull=True) | Q(experience__experience_type=self.experience_type) + if self.experience_type == DEFAULT_EXPERIENCE_TYPE else + Q(experience__isnull=False) & Q(experience__experience_type=self.experience_type), enrollment__user__in=users, enrollment__is_active=True, **schedule_day_equals_target_day_filter @@ -333,6 +339,7 @@ class CourseUpdateResolver(BinnedSchedulesBaseResolver): log_prefix = 'Course Update' schedule_date_field = 'start' num_bins = COURSE_UPDATE_NUM_BINS + experience_type = EXPERIENCE_TYPES[1][0] def schedules_for_bin(self): week_num = abs(self.day_offset) / 7