diff --git a/lms/envs/common.py b/lms/envs/common.py index 75b24a142c..020fe37e45 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -2490,6 +2490,7 @@ INSTALLED_APPS = [ 'lms.djangoapps.course_goals.apps.CourseGoalsConfig', # Features + 'openedx.features.calendar_sync', 'openedx.features.course_bookmarks', 'openedx.features.course_experience', 'openedx.features.course_search', diff --git a/openedx/features/calendar_sync/migrations/0001_initial.py b/openedx/features/calendar_sync/migrations/0001_initial.py new file mode 100644 index 0000000000..317179a620 --- /dev/null +++ b/openedx/features/calendar_sync/migrations/0001_initial.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.28 on 2020-02-20 20:20 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import opaque_keys.edx.django.models +import simple_history.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='HistoricalUserCalendarSyncConfig', + fields=[ + ('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')), + ('course_key', opaque_keys.edx.django.models.CourseKeyField(db_index=True, max_length=255)), + ('enabled', models.BooleanField(default=False)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField()), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'historical user calendar sync config', + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': 'history_date', + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + migrations.CreateModel( + name='UserCalendarSyncConfig', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('course_key', opaque_keys.edx.django.models.CourseKeyField(db_index=True, max_length=255)), + ('enabled', models.BooleanField(default=False)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AlterUniqueTogether( + name='usercalendarsyncconfig', + unique_together=set([('user', 'course_key')]), + ), + ] diff --git a/openedx/features/calendar_sync/migrations/__init__.py b/openedx/features/calendar_sync/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openedx/features/calendar_sync/models.py b/openedx/features/calendar_sync/models.py new file mode 100644 index 0000000000..49608c6a42 --- /dev/null +++ b/openedx/features/calendar_sync/models.py @@ -0,0 +1,43 @@ +""" +Models for Calendar Sync +""" + + +from django.contrib.auth.models import User +from django.db import models +from simple_history.models import HistoricalRecords + +from opaque_keys.edx.django.models import CourseKeyField + + +class UserCalendarSyncConfig(models.Model): + """ + Model to track if a user has the calendar integration enabled for a specific Course + + .. no_pii: + """ + user = models.ForeignKey(User, db_index=True, on_delete=models.CASCADE) + course_key = CourseKeyField(max_length=255, db_index=True) + enabled = models.BooleanField(default=False) + + history = HistoricalRecords() + + class Meta: + unique_together = ('user', 'course_key',) + + @classmethod + def is_enabled_for_course(cls, user, course_key): + """ + Check if the User calendar sync is enabled for a particular course. + Returns False if the object does not exist. + + Parameters: + user (User): The user to check against + course_key (CourseKey): The course key to check against + Returns: + (bool) True if the config exists and is enabled. Otherwise, False + """ + try: + return cls.objects.get(user=user, course_key=course_key).enabled + except cls.DoesNotExist: + return False diff --git a/openedx/features/calendar_sync/tests/test_models.py b/openedx/features/calendar_sync/tests/test_models.py new file mode 100644 index 0000000000..fe1f51a6fb --- /dev/null +++ b/openedx/features/calendar_sync/tests/test_models.py @@ -0,0 +1,34 @@ +""" Tests for the Calendar Sync models """ + + +from openedx.features.calendar_sync.models import UserCalendarSyncConfig +from student.tests.factories import UserFactory +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory + +TEST_PASSWORD = 'test' + + +class TestUserCalendarSyncConfig(SharedModuleStoreTestCase): + """ Tests for the UserCalendarSyncConfig model """ + @classmethod + def setUpClass(cls): + """ Set up any course data """ + super(TestUserCalendarSyncConfig, cls).setUpClass() + cls.course = CourseFactory.create() + cls.course_key = cls.course.id + + def setUp(self): + super(TestUserCalendarSyncConfig, self).setUp() + self.user = UserFactory(password=TEST_PASSWORD) + + def test_is_enabled_for_course(self): + # Calendar Sync Config does not exist and returns False + self.assertFalse(UserCalendarSyncConfig.is_enabled_for_course(self.user, self.course_key)) + + # Default value for enabled is False + UserCalendarSyncConfig.objects.create(user=self.user, course_key=self.course_key) + self.assertFalse(UserCalendarSyncConfig.is_enabled_for_course(self.user, self.course_key)) + + UserCalendarSyncConfig.objects.filter(user=self.user, course_key=self.course_key).update(enabled=True) + self.assertTrue(UserCalendarSyncConfig.is_enabled_for_course(self.user, self.course_key)) diff --git a/scripts/thresholds.sh b/scripts/thresholds.sh index 31d9d2fb00..381f107f7a 100755 --- a/scripts/thresholds.sh +++ b/scripts/thresholds.sh @@ -2,6 +2,6 @@ set -e export LOWER_PYLINT_THRESHOLD=1000 -export UPPER_PYLINT_THRESHOLD=1985 +export UPPER_PYLINT_THRESHOLD=1962 export ESLINT_THRESHOLD=5530 export STYLELINT_THRESHOLD=880