From 90c670c0aca80e327fac7f8d88cde10ef226d17e Mon Sep 17 00:00:00 2001 From: muzaffaryousaf Date: Fri, 25 Mar 2016 16:14:14 +0500 Subject: [PATCH 1/4] Unit test to check the migrations are in sync. --- common/djangoapps/util/tests/test_db.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/common/djangoapps/util/tests/test_db.py b/common/djangoapps/util/tests/test_db.py index 603eecd9bb..40650372c7 100644 --- a/common/djangoapps/util/tests/test_db.py +++ b/common/djangoapps/util/tests/test_db.py @@ -6,6 +6,7 @@ import time import unittest from django.contrib.auth.models import User +from django.core.management import call_command from django.db import connection, IntegrityError from django.db.transaction import atomic, TransactionManagementError from django.test import TestCase, TransactionTestCase @@ -161,3 +162,17 @@ class GenerateIntIdTestCase(TestCase): for i in range(times): int_id = generate_int_id(minimum, maximum, used_ids) self.assertIn(int_id, list(set(range(minimum, maximum + 1)) - used_ids)) + + +class MigrationTests(TestCase): + """ + Tests for migrations. + """ + + def test_migrations_are_in_sync(self): + """ + Tests that the migration files are in sync with the models. + If this fails, you needs to run the Django command makemigrations. + """ + with self.assertRaises(SystemExit): + call_command('makemigrations', '-e') From e2d9ecc0100b801f4529ee1568e545d42096a826 Mon Sep 17 00:00:00 2001 From: muzaffaryousaf Date: Tue, 29 Mar 2016 15:08:42 +0500 Subject: [PATCH 2/4] Make migrations in-sync with models --- .../migrations/0002_auto_20160325_0407.py | 24 +++++++++++++++++++ common/djangoapps/util/tests/test_db.py | 6 +++-- .../migrations/0003_auto_20160329_0709.py | 18 ++++++++++++++ .../migrations/0002_auto_20160325_0407.py | 20 ++++++++++++++++ .../migrations/0002_auto_20160325_0407.py | 18 ++++++++++++++ .../migrations/0002_auto_20160325_0631.py | 19 +++++++++++++++ .../migrations/0002_auto_20160325_0631.py | 18 ++++++++++++++ 7 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py create mode 100644 lms/djangoapps/commerce/migrations/0003_auto_20160329_0709.py create mode 100644 lms/djangoapps/lti_provider/migrations/0002_auto_20160325_0407.py create mode 100644 openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py create mode 100644 openedx/core/djangoapps/coursetalk/migrations/0002_auto_20160325_0631.py create mode 100644 openedx/core/djangoapps/credentials/migrations/0002_auto_20160325_0631.py diff --git a/common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py b/common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py new file mode 100644 index 0000000000..d697b75126 --- /dev/null +++ b/common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('third_party_auth', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='oauth2providerconfig', + name='backend_name', + field=models.CharField(help_text=b'Which python-social-auth OAuth2 provider backend to use. The list of backend choices is determined by the THIRD_PARTY_AUTH_BACKENDS setting.', max_length=50, db_index=True, choices=[(b'google-oauth2', b'google-oauth2'), (b'linkedin-oauth2', b'linkedin-oauth2'), (b'facebook', b'facebook'), (b'twitter', b'twitter'), (b'dummy', b'dummy')]), + ), + migrations.AlterField( + model_name='samlproviderconfig', + name='backend_name', + field=models.CharField(default=b'tpa-saml', help_text=b"Which python-social-auth provider backend to use. 'tpa-saml' is the standard edX SAML backend.", max_length=50, choices=[(b'tpa-saml', b'tpa-saml')]), + ), + ] diff --git a/common/djangoapps/util/tests/test_db.py b/common/djangoapps/util/tests/test_db.py index 40650372c7..75895e5e48 100644 --- a/common/djangoapps/util/tests/test_db.py +++ b/common/djangoapps/util/tests/test_db.py @@ -4,14 +4,16 @@ import ddt import threading import time import unittest +from unittest import skipIf from django.contrib.auth.models import User from django.core.management import call_command +from django.conf import settings from django.db import connection, IntegrityError from django.db.transaction import atomic, TransactionManagementError from django.test import TestCase, TransactionTestCase -from util.db import commit_on_success, generate_int_id, outer_atomic +from util.db import commit_on_success, generate_int_id, outer_atomic, NoOpMigrationModules @ddt.ddt @@ -168,7 +170,7 @@ class MigrationTests(TestCase): """ Tests for migrations. """ - + @skipIf(isinstance(settings.MIGRATION_MODULES, NoOpMigrationModules), 'Skip in case of NoOpMigrationModules') def test_migrations_are_in_sync(self): """ Tests that the migration files are in sync with the models. diff --git a/lms/djangoapps/commerce/migrations/0003_auto_20160329_0709.py b/lms/djangoapps/commerce/migrations/0003_auto_20160329_0709.py new file mode 100644 index 0000000000..814d57450f --- /dev/null +++ b/lms/djangoapps/commerce/migrations/0003_auto_20160329_0709.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('commerce', '0002_commerceconfiguration'), + ] + + operations = [ + migrations.AlterModelOptions( + name='commerceconfiguration', + options={}, + ), + ] diff --git a/lms/djangoapps/lti_provider/migrations/0002_auto_20160325_0407.py b/lms/djangoapps/lti_provider/migrations/0002_auto_20160325_0407.py new file mode 100644 index 0000000000..232a1e6c00 --- /dev/null +++ b/lms/djangoapps/lti_provider/migrations/0002_auto_20160325_0407.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import provider.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('lti_provider', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='lticonsumer', + name='consumer_secret', + field=models.CharField(default=provider.utils.short_token, unique=True, max_length=32), + ), + ] diff --git a/openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py b/openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py new file mode 100644 index 0000000000..ffb6ee7d68 --- /dev/null +++ b/openedx/core/djangoapps/ccxcon/migrations/0002_auto_20160325_0407.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ccxcon', '0001_initial_ccxcon_model'), + ] + + operations = [ + migrations.AlterModelOptions( + name='ccxcon', + options={'verbose_name': 'CCX Connector', 'verbose_name_plural': 'CCX Connectors'}, + ), + ] diff --git a/openedx/core/djangoapps/coursetalk/migrations/0002_auto_20160325_0631.py b/openedx/core/djangoapps/coursetalk/migrations/0002_auto_20160325_0631.py new file mode 100644 index 0000000000..73f04f9065 --- /dev/null +++ b/openedx/core/djangoapps/coursetalk/migrations/0002_auto_20160325_0631.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('coursetalk', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='coursetalkwidgetconfiguration', + name='platform_key', + field=models.CharField(help_text='The platform key associates CourseTalk widgets with your platform. Generally, it is the domain name for your platform. For example, if your platform is http://edx.org, the platform key is "edx".', max_length=50), + ), + ] diff --git a/openedx/core/djangoapps/credentials/migrations/0002_auto_20160325_0631.py b/openedx/core/djangoapps/credentials/migrations/0002_auto_20160325_0631.py new file mode 100644 index 0000000000..5cafeda4e1 --- /dev/null +++ b/openedx/core/djangoapps/credentials/migrations/0002_auto_20160325_0631.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('credentials', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='credentialsapiconfig', + options={}, + ), + ] From c3cd2db384d3e19f2b4702121d1a8544064e3396 Mon Sep 17 00:00:00 2001 From: muzaffaryousaf Date: Thu, 31 Mar 2016 16:02:24 +0500 Subject: [PATCH 3/4] Moving choices to admin form instead of models. TNL-4296 --- common/djangoapps/third_party_auth/admin.py | 18 +++++++++++++- .../migrations/0002_auto_20160325_0407.py | 24 ------------------- common/djangoapps/third_party_auth/models.py | 4 ++-- 3 files changed, 19 insertions(+), 27 deletions(-) delete mode 100644 common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py diff --git a/common/djangoapps/third_party_auth/admin.py b/common/djangoapps/third_party_auth/admin.py index 3491be6eee..5d29c08246 100644 --- a/common/djangoapps/third_party_auth/admin.py +++ b/common/djangoapps/third_party_auth/admin.py @@ -13,14 +13,23 @@ from .models import ( SAMLConfiguration, SAMLProviderData, LTIProviderConfig, - ProviderApiPermissions + ProviderApiPermissions, + _PSA_OAUTH2_BACKENDS, + _PSA_SAML_BACKENDS ) from .tasks import fetch_saml_metadata from third_party_auth.provider import Registry +class OAuth2ProviderConfigForm(forms.ModelForm): + """ Django Admin form class for OAuth2ProviderConfig """ + backend_name = forms.ChoiceField(choices=((name, name) for name in _PSA_OAUTH2_BACKENDS)) + + class OAuth2ProviderConfigAdmin(KeyedConfigurationModelAdmin): """ Django Admin class for OAuth2ProviderConfig """ + form = OAuth2ProviderConfigForm + def get_list_display(self, request): """ Don't show every single field in the admin change list """ return ( @@ -31,8 +40,15 @@ class OAuth2ProviderConfigAdmin(KeyedConfigurationModelAdmin): admin.site.register(OAuth2ProviderConfig, OAuth2ProviderConfigAdmin) +class SAMLProviderConfigForm(forms.ModelForm): + """ Django Admin form class for SAMLProviderConfig """ + backend_name = forms.ChoiceField(choices=((name, name) for name in _PSA_SAML_BACKENDS)) + + class SAMLProviderConfigAdmin(KeyedConfigurationModelAdmin): """ Django Admin class for SAMLProviderConfig """ + form = SAMLProviderConfigForm + def get_list_display(self, request): """ Don't show every single field in the admin change list """ return ( diff --git a/common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py b/common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py deleted file mode 100644 index d697b75126..0000000000 --- a/common/djangoapps/third_party_auth/migrations/0002_auto_20160325_0407.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('third_party_auth', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='oauth2providerconfig', - name='backend_name', - field=models.CharField(help_text=b'Which python-social-auth OAuth2 provider backend to use. The list of backend choices is determined by the THIRD_PARTY_AUTH_BACKENDS setting.', max_length=50, db_index=True, choices=[(b'google-oauth2', b'google-oauth2'), (b'linkedin-oauth2', b'linkedin-oauth2'), (b'facebook', b'facebook'), (b'twitter', b'twitter'), (b'dummy', b'dummy')]), - ), - migrations.AlterField( - model_name='samlproviderconfig', - name='backend_name', - field=models.CharField(default=b'tpa-saml', help_text=b"Which python-social-auth provider backend to use. 'tpa-saml' is the standard edX SAML backend.", max_length=50, choices=[(b'tpa-saml', b'tpa-saml')]), - ), - ] diff --git a/common/djangoapps/third_party_auth/models.py b/common/djangoapps/third_party_auth/models.py index 5200a92b71..ce76ef20c5 100644 --- a/common/djangoapps/third_party_auth/models.py +++ b/common/djangoapps/third_party_auth/models.py @@ -212,7 +212,7 @@ class OAuth2ProviderConfig(ProviderConfig): prefix = 'oa2' KEY_FIELDS = ('backend_name', ) # Backend name is unique backend_name = models.CharField( - max_length=50, choices=[(name, name) for name in _PSA_OAUTH2_BACKENDS], blank=False, db_index=True, + max_length=50, blank=False, db_index=True, help_text=( "Which python-social-auth OAuth2 provider backend to use. " "The list of backend choices is determined by the THIRD_PARTY_AUTH_BACKENDS setting." @@ -265,7 +265,7 @@ class SAMLProviderConfig(ProviderConfig): prefix = 'saml' KEY_FIELDS = ('idp_slug', ) backend_name = models.CharField( - max_length=50, default='tpa-saml', choices=[(name, name) for name in _PSA_SAML_BACKENDS], blank=False, + max_length=50, default='tpa-saml', blank=False, help_text="Which python-social-auth provider backend to use. 'tpa-saml' is the standard edX SAML backend.") idp_slug = models.SlugField( max_length=30, db_index=True, From 2e0a9b265894ad9821c6cd11acc6cc6b442589d5 Mon Sep 17 00:00:00 2001 From: muzaffaryousaf Date: Thu, 7 Apr 2016 12:21:56 +0500 Subject: [PATCH 4/4] Bump version for edx/django-oauth2-provider that includes in-sync migrations. TNL-4296 --- requirements/edx/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index ca346fed43..bfa8fe06bc 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -39,7 +39,7 @@ djangorestframework-oauth==1.1.0 edx-ccx-keys==0.1.2 edx-lint==0.4.3 edx-management-commands==0.0.1 -edx-django-oauth2-provider==1.0.1 +edx-django-oauth2-provider==1.0.2 edx-oauth2-provider==1.0.0 edx-opaque-keys==0.2.1 edx-organizations==0.4.0