0001-Revert-add-compatibility-layer-for-support-of-Django.patch
src/authentic2/apps.py | ||
---|---|---|
18 | 18 |
from django.apps import AppConfig |
19 | 19 |
from django.views import debug |
20 | 20 | |
21 |
from django.db import connection, router |
|
22 |
from django.db.models.signals import post_migrate |
|
23 | ||
24 |
from . import plugins, compat |
|
25 | ||
21 |
from . import plugins |
|
26 | 22 | |
27 | 23 |
class Authentic2Config(AppConfig): |
28 | 24 |
name = 'authentic2' |
29 | 25 |
verbose_name = 'Authentic2' |
30 | 26 | |
31 |
def post_migrate_update_json_column(self, sender, using, **kwargs): |
|
32 |
# adapted from https://github.com/kbussell/django-jsonfield-compat/blob/4f6ac4bfaea2224559b174b6d16d846b93d125c6/jsonfield_compat/convert.py |
|
33 |
# MIT License, kbussel |
|
34 |
if connection.vendor != 'postgresql': |
|
35 |
return |
|
36 | ||
37 |
if compat.has_postgresql_support(): |
|
38 |
expected_type = 'JSONB' |
|
39 |
else: |
|
40 |
expected_type = 'TEXT' |
|
41 | ||
42 |
def convert_column_to_json(model, column_name): |
|
43 |
table_name = model._meta.db_table |
|
44 | ||
45 |
with connection.cursor() as cursor: |
|
46 |
cursor.execute( |
|
47 |
"select data_type from information_schema.columns " |
|
48 |
"where table_name = %s and column_name = %s;", |
|
49 |
[table_name, column_name]) |
|
50 | ||
51 |
current_type = cursor.fetchone()[0].upper() |
|
52 | ||
53 |
if current_type != expected_type: |
|
54 |
print("{app}: Converting {col} to use native {type} field".format( |
|
55 |
app=model._meta.app_label, col=column_name, type=expected_type)) |
|
56 | ||
57 |
cursor.execute( |
|
58 |
"ALTER TABLE {table} ALTER COLUMN {col} " |
|
59 |
"TYPE {type} USING {col}::{type};".format( |
|
60 |
table=table_name, col=column_name, type=expected_type |
|
61 |
) |
|
62 |
) |
|
63 | ||
64 |
def convert_model_json_fields(model): |
|
65 |
json_fields = [f for f in model._meta.fields if f.__class__ == compat.JSONField] |
|
66 |
for field in json_fields: |
|
67 |
_, column_name = field.get_attname_column() |
|
68 |
convert_column_to_json(model, column_name) |
|
69 | ||
70 |
for model in list(sender.get_models()): |
|
71 |
if not router.allow_migrate(using, model): |
|
72 |
continue |
|
73 |
convert_model_json_fields(model) |
|
74 | ||
75 | 27 |
def ready(self): |
76 | 28 |
plugins.init() |
77 | 29 |
debug.HIDDEN_SETTINGS = re.compile( |
78 | 30 |
'API|TOKEN|KEY|SECRET|PASS|PROFANITIES_LIST|SIGNATURE|LDAP') |
79 |
post_migrate.connect(self.post_migrate_update_json_column) |
src/authentic2/compat.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
import inspect |
|
18 | ||
19 |
import django |
|
20 |
from django.db import connection |
|
21 |
from django.db.utils import OperationalError |
|
22 |
from django.core.exceptions import ImproperlyConfigured |
|
17 |
from datetime import datetime |
|
23 | 18 | |
19 |
from django.conf import settings |
|
24 | 20 |
from django.contrib.auth.tokens import PasswordResetTokenGenerator |
25 | 21 | |
26 | ||
27 |
default_token_generator = PasswordResetTokenGenerator() |
|
28 | ||
29 | ||
30 |
def has_postgresql_support(): |
|
31 |
try: |
|
32 |
return connection.vendor == 'postgresql' and connection.pg_version > 90400 |
|
33 |
except (ImproperlyConfigured, OperationalError): |
|
34 |
# database is not initialized, be conservative |
|
35 |
return False |
|
36 | ||
37 | ||
38 |
def use_django_native_field(): |
|
39 |
return has_postgresql_support() and django.VERSION >= (1, 11) |
|
40 | ||
41 | ||
42 |
class JSONField(object): |
|
43 |
__dj11_field = None |
|
44 |
__jsonfield_field = None |
|
45 |
__name = None |
|
46 | ||
47 |
def __init__(self, *args, **kwargs): |
|
48 |
self.__args = args |
|
49 |
self.__kwargs = kwargs |
|
50 |
if django.VERSION >= (1, 11): |
|
51 |
try: |
|
52 |
from django.contrib.postgres.fields import JSONField |
|
53 |
self.__dj11_field = JSONField(*args, **kwargs) |
|
54 |
except ImportError: |
|
55 |
pass |
|
56 |
try: |
|
57 |
from jsonfield.fields import JSONField |
|
58 |
self.__jsonfield_field = JSONField(*args, **kwargs) |
|
59 |
except ImportError: |
|
60 |
pass |
|
61 | ||
62 |
def __real_field__(self): |
|
63 |
if use_django_native_field(): |
|
64 |
assert self.__dj11_field |
|
65 |
return self.__dj11_field |
|
66 |
assert self.__jsonfield_field |
|
67 |
return self.__jsonfield_field |
|
68 | ||
69 |
def __getattr__(self, key): |
|
70 |
return getattr(self.__real_field__(), key) |
|
71 | ||
72 |
def __setattr__(self, key, value): |
|
73 |
if key.startswith('_JSONField__'): |
|
74 |
super(JSONField, self).__setattr__(key, value) |
|
75 |
else: |
|
76 |
setattr(self.__real__field(), key, value) |
|
77 | ||
78 |
# we need to implement contribute_to_class so that the direct |
|
79 |
# implementation from the two sub-fields is not used directly |
|
80 |
def contribute_to_class(self, cls, name, private_only=False, virtual_only=False, **kwargs): |
|
81 |
assert not virtual_only and not private_only, 'virtual_only / private_only are not supported' |
|
82 |
assert not kwargs, 'new arguments to contribute_to_class not supported' |
|
83 |
self.__name = name |
|
84 |
if self.__dj11_field: |
|
85 |
self.__dj11_field.set_attributes_from_name(name) |
|
86 |
self.__dj11_field.model = cls |
|
87 |
if self.__jsonfield_field: |
|
88 |
self.__jsonfield_field.set_attributes_from_name(name) |
|
89 |
self.__jsonfield_field.model = cls |
|
90 |
cls._meta.add_field(self) |
|
91 | ||
92 |
# the next two methods are useful for compatibilit with the migration engine |
|
93 |
# inspect is used because migration autodetector cannot recognize this class |
|
94 |
# as a subclass of models.Field. |
|
95 |
def deconstruct(self): |
|
96 |
d = (self.__name, 'authentic2.compat.JSONField', self.__args, self.__kwargs) |
|
97 |
previous_frame = inspect.currentframe().f_back |
|
98 |
if inspect.getframeinfo(previous_frame)[2] in ('serialize', 'deep_deconstruct'): |
|
99 |
d = d[1:] |
|
100 |
return d |
|
101 | ||
102 |
def clone(self): |
|
103 |
from copy import copy |
|
104 |
new = copy(self) |
|
105 |
if self.__dj11_field: |
|
106 |
new.__dj11_field = new.__dj11_field.clone() |
|
107 |
if self.__jsonfield_field: |
|
108 |
new.__jsonfield_field = new.__jsonfield_field.clone() |
|
109 |
return new |
|
110 | ||
22 |
try: |
|
23 |
from django.contrib.auth import get_user_model |
|
24 |
except ImportError: |
|
25 |
from django.contrib.auth.models import User |
|
26 |
get_user_model = lambda: User |
|
111 | 27 | |
112 | 28 |
try: |
113 |
import jsonfield.fields |
|
29 |
from django.db.transaction import atomic |
|
30 |
commit_on_success = atomic |
|
114 | 31 |
except ImportError: |
115 |
pass |
|
116 |
else: |
|
117 |
# prevent django-jsonfield from modifying postgresql connection when we are |
|
118 |
# not using it |
|
119 |
if hasattr(jsonfield.fields, 'connection_created'): |
|
120 |
def configure_database_connection(connection, **kwargs): |
|
121 |
if django.VERSION < (1, 11): |
|
122 |
jsonfield.fields.configure_database_connection(connection, **kwargs) |
|
123 |
jsonfield.fields.connection_created.disconnect(jsonfield.fields.configure_database_connection) |
|
124 |
jsonfield.fields.connection_created.connect(configure_database_connection) |
|
32 |
from django.db.transaction import commit_on_success |
|
33 | ||
34 |
user_model_label = getattr(settings, 'AUTH_USER_MODEL', 'auth.User') |
|
35 | ||
36 |
default_token_generator = PasswordResetTokenGenerator() |
src/authentic2_auth_oidc/migrations/0007_auto_20181219_0005.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Generated by Django 1.11.17 on 2018-12-18 23:05 |
|
3 |
from __future__ import unicode_literals |
|
4 | ||
5 |
import authentic2.compat |
|
6 |
import authentic2_auth_oidc.models |
|
7 |
from django.db import migrations |
|
8 | ||
9 | ||
10 |
class Migration(migrations.Migration): |
|
11 | ||
12 |
dependencies = [ |
|
13 |
('authentic2_auth_oidc', '0006_oidcprovider_claims_parameter_supported'), |
|
14 |
] |
|
15 | ||
16 |
operations = [ |
|
17 |
migrations.AlterField( |
|
18 |
model_name='oidcprovider', |
|
19 |
name='jwkset_json', |
|
20 |
field=authentic2.compat.JSONField(blank=True, null=True, validators=[authentic2_auth_oidc.models.validate_jwkset], verbose_name='JSON WebKey set'), |
|
21 |
), |
|
22 |
] |
src/authentic2_auth_oidc/models.py | ||
---|---|---|
23 | 23 |
from django.conf import settings |
24 | 24 |
from django.core.exceptions import ValidationError |
25 | 25 | |
26 |
from jsonfield import JSONField |
|
26 | 27 | |
27 | 28 |
from jwcrypto.jwk import JWKSet, InvalidJWKValue, JWK |
28 | 29 | |
29 | 30 |
from django_rbac.utils import get_ou_model_name |
30 | 31 | |
31 |
from authentic2 import compat |
|
32 | ||
33 | 32 |
from . import managers |
34 | 33 | |
35 | 34 | |
... | ... | |
108 | 107 |
max_length=128, |
109 | 108 |
blank=True, |
110 | 109 |
verbose_name=_('scopes')) |
111 |
jwkset_json = compat.JSONField(
|
|
110 |
jwkset_json = JSONField( |
|
112 | 111 |
verbose_name=_('JSON WebKey set'), |
113 | 112 |
null=True, |
114 | 113 |
blank=True, |
tox.ini | ||
---|---|---|
42 | 42 |
dj111: django<2.0 |
43 | 43 |
dj111: django-tables<2.0 |
44 | 44 |
pg: psycopg2-binary |
45 |
dj111: psycopg2-binary |
|
46 | 45 |
coverage |
47 | 46 |
pytest-cov |
48 | 47 |
pytest-django<3.4.6 |
49 |
- |