From cef04caf83376793c29cb58d4bc0fc690b251762 Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Tue, 29 Oct 2019 11:18:16 +0100
Subject: [PATCH 1/3] Revert "add compatibility layer for support of Django
 native JSONField (fixes #29193)"

This reverts commit d730dba525215d615fa2b974d44183d16909f4d2.
---
 src/authentic2/apps.py                        |  51 +-------
 src/authentic2/compat.py                      | 116 +++---------------
 .../migrations/0007_auto_20181219_0005.py     |  22 ----
 src/authentic2_auth_oidc/models.py            |   5 +-
 tox.ini                                       |   1 -
 5 files changed, 17 insertions(+), 178 deletions(-)
 delete mode 100644 src/authentic2_auth_oidc/migrations/0007_auto_20181219_0005.py

diff --git a/src/authentic2/apps.py b/src/authentic2/apps.py
index 0699a73eb..a02c23b8a 100644
--- a/src/authentic2/apps.py
+++ b/src/authentic2/apps.py
@@ -18,62 +18,13 @@ import re
 from django.apps import AppConfig
 from django.views import debug
 
-from django.db import connection, router
-from django.db.models.signals import post_migrate
-
-from . import plugins, compat
-
+from . import plugins
 
 class Authentic2Config(AppConfig):
     name = 'authentic2'
     verbose_name = 'Authentic2'
 
-    def post_migrate_update_json_column(self, sender, using, **kwargs):
-        # adapted from https://github.com/kbussell/django-jsonfield-compat/blob/4f6ac4bfaea2224559b174b6d16d846b93d125c6/jsonfield_compat/convert.py
-        # MIT License, kbussel
-        if connection.vendor != 'postgresql':
-            return
-
-        if compat.has_postgresql_support():
-            expected_type = 'JSONB'
-        else:
-            expected_type = 'TEXT'
-
-        def convert_column_to_json(model, column_name):
-            table_name = model._meta.db_table
-
-            with connection.cursor() as cursor:
-                cursor.execute(
-                    "select data_type from information_schema.columns "
-                    "where table_name = %s and column_name = %s;",
-                    [table_name, column_name])
-
-                current_type = cursor.fetchone()[0].upper()
-
-                if current_type != expected_type:
-                    print("{app}: Converting {col} to use native {type} field".format(
-                        app=model._meta.app_label, col=column_name, type=expected_type))
-
-                    cursor.execute(
-                        "ALTER TABLE {table} ALTER COLUMN {col} "
-                        "TYPE {type} USING {col}::{type};".format(
-                            table=table_name, col=column_name, type=expected_type
-                        )
-                    )
-
-        def convert_model_json_fields(model):
-            json_fields = [f for f in model._meta.fields if f.__class__ == compat.JSONField]
-            for field in json_fields:
-                _, column_name = field.get_attname_column()
-                convert_column_to_json(model, column_name)
-
-        for model in list(sender.get_models()):
-            if not router.allow_migrate(using, model):
-                continue
-            convert_model_json_fields(model)
-
     def ready(self):
         plugins.init()
         debug.HIDDEN_SETTINGS = re.compile(
             'API|TOKEN|KEY|SECRET|PASS|PROFANITIES_LIST|SIGNATURE|LDAP')
-        post_migrate.connect(self.post_migrate_update_json_column)
diff --git a/src/authentic2/compat.py b/src/authentic2/compat.py
index 0f7b71f7c..01e98464d 100644
--- a/src/authentic2/compat.py
+++ b/src/authentic2/compat.py
@@ -14,111 +14,23 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-import inspect
-
-import django
-from django.db import connection
-from django.db.utils import OperationalError
-from django.core.exceptions import ImproperlyConfigured
+from datetime import datetime
 
+from django.conf import settings
 from django.contrib.auth.tokens import PasswordResetTokenGenerator
 
-
-default_token_generator = PasswordResetTokenGenerator()
-
-
-def has_postgresql_support():
-    try:
-        return connection.vendor == 'postgresql' and connection.pg_version > 90400
-    except (ImproperlyConfigured, OperationalError):
-        # database is not initialized, be conservative
-        return False
-
-
-def use_django_native_field():
-    return has_postgresql_support() and django.VERSION >= (1, 11)
-
-
-class JSONField(object):
-    __dj11_field = None
-    __jsonfield_field = None
-    __name = None
-
-    def __init__(self, *args, **kwargs):
-        self.__args = args
-        self.__kwargs = kwargs
-        if django.VERSION >= (1, 11):
-            try:
-                from django.contrib.postgres.fields import JSONField
-                self.__dj11_field = JSONField(*args, **kwargs)
-            except ImportError:
-                pass
-        try:
-            from jsonfield.fields import JSONField
-            self.__jsonfield_field = JSONField(*args, **kwargs)
-        except ImportError:
-            pass
-
-    def __real_field__(self):
-        if use_django_native_field():
-            assert self.__dj11_field
-            return self.__dj11_field
-        assert self.__jsonfield_field
-        return self.__jsonfield_field
-
-    def __getattr__(self, key):
-        return getattr(self.__real_field__(), key)
-
-    def __setattr__(self, key, value):
-        if key.startswith('_JSONField__'):
-            super(JSONField, self).__setattr__(key, value)
-        else:
-            setattr(self.__real__field(), key, value)
-
-    # we need to implement contribute_to_class so that the direct
-    # implementation from the two sub-fields is not used directly
-    def contribute_to_class(self, cls, name, private_only=False, virtual_only=False, **kwargs):
-        assert not virtual_only and not private_only, 'virtual_only / private_only are not supported'
-        assert not kwargs, 'new arguments to contribute_to_class not supported'
-        self.__name = name
-        if self.__dj11_field:
-            self.__dj11_field.set_attributes_from_name(name)
-            self.__dj11_field.model = cls
-        if self.__jsonfield_field:
-            self.__jsonfield_field.set_attributes_from_name(name)
-            self.__jsonfield_field.model = cls
-        cls._meta.add_field(self)
-
-    # the next two methods are useful for compatibilit with the migration engine
-    # inspect is used because migration autodetector cannot recognize this class
-    # as a subclass of models.Field.
-    def deconstruct(self):
-        d = (self.__name, 'authentic2.compat.JSONField', self.__args, self.__kwargs)
-        previous_frame = inspect.currentframe().f_back
-        if inspect.getframeinfo(previous_frame)[2] in ('serialize', 'deep_deconstruct'):
-            d = d[1:]
-        return d
-
-    def clone(self):
-        from copy import copy
-        new = copy(self)
-        if self.__dj11_field:
-            new.__dj11_field = new.__dj11_field.clone()
-        if self.__jsonfield_field:
-            new.__jsonfield_field = new.__jsonfield_field.clone()
-        return new
-
+try:
+    from django.contrib.auth import get_user_model
+except ImportError:
+    from django.contrib.auth.models import User
+    get_user_model = lambda: User
 
 try:
-    import jsonfield.fields
+    from django.db.transaction import atomic
+    commit_on_success = atomic
 except ImportError:
-    pass
-else:
-    # prevent django-jsonfield from modifying postgresql connection when we are
-    # not using it
-    if hasattr(jsonfield.fields, 'connection_created'):
-        def configure_database_connection(connection, **kwargs):
-            if django.VERSION < (1, 11):
-                jsonfield.fields.configure_database_connection(connection, **kwargs)
-        jsonfield.fields.connection_created.disconnect(jsonfield.fields.configure_database_connection)
-        jsonfield.fields.connection_created.connect(configure_database_connection)
+    from django.db.transaction import commit_on_success
+
+user_model_label = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
+
+default_token_generator = PasswordResetTokenGenerator()
diff --git a/src/authentic2_auth_oidc/migrations/0007_auto_20181219_0005.py b/src/authentic2_auth_oidc/migrations/0007_auto_20181219_0005.py
deleted file mode 100644
index 367744996..000000000
--- a/src/authentic2_auth_oidc/migrations/0007_auto_20181219_0005.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.11.17 on 2018-12-18 23:05
-from __future__ import unicode_literals
-
-import authentic2.compat
-import authentic2_auth_oidc.models
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('authentic2_auth_oidc', '0006_oidcprovider_claims_parameter_supported'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='oidcprovider',
-            name='jwkset_json',
-            field=authentic2.compat.JSONField(blank=True, null=True, validators=[authentic2_auth_oidc.models.validate_jwkset], verbose_name='JSON WebKey set'),
-        ),
-    ]
diff --git a/src/authentic2_auth_oidc/models.py b/src/authentic2_auth_oidc/models.py
index 64bf1c441..5fcdcf3ee 100644
--- a/src/authentic2_auth_oidc/models.py
+++ b/src/authentic2_auth_oidc/models.py
@@ -23,13 +23,12 @@ from django.utils.translation import ugettext_lazy as _
 from django.conf import settings
 from django.core.exceptions import ValidationError
 
+from jsonfield import JSONField
 
 from jwcrypto.jwk import JWKSet, InvalidJWKValue, JWK
 
 from django_rbac.utils import get_ou_model_name
 
-from authentic2 import compat
-
 from . import managers
 
 
@@ -108,7 +107,7 @@ class OIDCProvider(models.Model):
         max_length=128,
         blank=True,
         verbose_name=_('scopes'))
-    jwkset_json = compat.JSONField(
+    jwkset_json = JSONField(
         verbose_name=_('JSON WebKey set'),
         null=True,
         blank=True,
diff --git a/tox.ini b/tox.ini
index 29f0921ed..4cb9878f4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -42,7 +42,6 @@ deps =
   dj111: django<2.0
   dj111: django-tables<2.0
   pg: psycopg2-binary
-  dj111: psycopg2-binary
   coverage
   pytest-cov
   pytest-django<3.4.6
-- 
2.24.0

