From 95280a14337112dac3a2127ca0c46501d53e1769 Mon Sep 17 00:00:00 2001 From: Eric Darchis Date: Wed, 10 Aug 2022 00:37:07 +0200 Subject: [PATCH 1/2] PostgreSQL support * Introduce insert_role_right_for_system that was used verbosely from various modules with TSQL blocks * Adapt migrations * Transfer some migrations RunSQL to the next migration step to avoid renumbering them but also avoid an error that the SQL referred a DDL change --- core/jwt.py | 1 - core/migrations/0012_users_officers_admins.py | 28 ------------- core/migrations/0013_users_api.py | 41 ++++++++++++++++++- ...0016_add_last_login_on_interactive_user.py | 8 ++-- core/utils.py | 18 ++++++++ 5 files changed, 63 insertions(+), 33 deletions(-) diff --git a/core/jwt.py b/core/jwt.py index 772ccef9..72097f3f 100644 --- a/core/jwt.py +++ b/core/jwt.py @@ -2,7 +2,6 @@ # from django.utils.deprecation import MiddlewareMixin import jwt from graphql_jwt.settings import jwt_settings -from django.apps import apps from graphql_jwt.signals import token_issued from django.apps import apps from django.utils import timezone diff --git a/core/migrations/0012_users_officers_admins.py b/core/migrations/0012_users_officers_admins.py index fc9e5ebe..b74993fc 100644 --- a/core/migrations/0012_users_officers_admins.py +++ b/core/migrations/0012_users_officers_admins.py @@ -38,32 +38,4 @@ class Migration(migrations.Migration): }, bases=(models.Model, core.models.ObjectMutation), ), - migrations.RunSQL(sql=""" - insert into core_User (id, username, i_user_id, t_user_id, officer_id, claim_admin_id) - select replace(lower(newid()), '-', ''), o.code, u.UserID, null, max(o.OfficerID), null - from tblOfficer o - left join tblUsers u on o.code = u.LoginName - where not exists (select 1 from core_User where username=o.code) - and o.ValidityTo is null and u.ValidityTo is null - group by o.code, u.UserID; - update core_User - set officer_id=maxofficer.maxid - from core_User cu inner join - (select code, max(OfficerID) as maxid from tblOfficer where validityTo is null group by code) maxofficer - on code=cu.username - where cu.officer_id is null; - insert into core_User (id, username, i_user_id, t_user_id, officer_id, claim_admin_id) - select replace(lower(newid()), '-', '') as uuid, ca.ClaimAdminCode, u.UserID, null as t, null as o, max(ca.ClaimAdminId) as max_id - from tblClaimAdmin ca - left join tblUsers u on ca.ClaimAdminCode = u.LoginName - where not exists (select 1 from core_User where username=ca.ClaimAdminCode) - and ca.ValidityTo is null and u.ValidityTo is null - group by ca.ClaimAdminCode, u.UserID; - update core_User - set claim_admin_id=maxca.maxid - from core_User cu inner join - (select ClaimAdminCode, max(ClaimAdminId) as maxid from tblClaimAdmin where validityTo is null group by ClaimAdminCode) maxca - on ClaimAdminCode=cu.username - where cu.claim_admin_id is null; - """, reverse_sql="") ] diff --git a/core/migrations/0013_users_api.py b/core/migrations/0013_users_api.py index 0dd71755..48477723 100644 --- a/core/migrations/0013_users_api.py +++ b/core/migrations/0013_users_api.py @@ -1,8 +1,11 @@ # Generated by Django 3.0.14 on 2021-06-01 12:51 - +from django.conf import settings from django.db import migrations +NEWID_FUNC = "replace(lower(newid()), '-', '')" if "sql_server" in settings.DB_ENGINE else "gen_random_uuid()" + + class Migration(migrations.Migration): dependencies = [ @@ -15,4 +18,40 @@ class Migration(migrations.Migration): old_name='user', new_name='core_user', ), + # The following migrations are not related to users api but a continuation of the previous one + # It is necessary to support PostgreSQL without breaking existing setups + migrations.RunSQL(sql=f""" + insert into "core_User" (id, username, i_user_id, t_user_id, officer_id, claim_admin_id) + select {NEWID_FUNC}, o."Code", u."UserID", null, max(o."OfficerID"), null + from "tblOfficer" o + left join "tblUsers" u on o."Code" = u."LoginName" + where not exists (select 1 from "core_User" where username=o."Code") + and o."ValidityTo" is null and u."ValidityTo" is null + group by o."Code", u."UserID"; + """, reverse_sql=""), + migrations.RunSQL(sql=f""" + update "core_User" + set officer_id=maxofficer.maxid + from "core_User" cu inner join + (select "Code", max("OfficerID") as maxid from "tblOfficer" where "ValidityTo" is null group by "Code") maxofficer + on "Code"=cu.username + where cu.officer_id is null; + """, reverse_sql=""), + migrations.RunSQL(sql=f""" + insert into "core_User" (id, username, i_user_id, t_user_id, officer_id, claim_admin_id) + select {NEWID_FUNC} as uuid, ca."ClaimAdminCode", u."UserID", null as t, null as o, max(ca."ClaimAdminId") as max_id + from "tblClaimAdmin" ca + left join "tblUsers" u on ca."ClaimAdminCode" = u."LoginName" + where not exists (select 1 from "core_User" where username=ca."ClaimAdminCode") + and ca."ValidityTo" is null and u."ValidityTo" is null + group by ca."ClaimAdminCode", u."UserID"; + """, reverse_sql=""), + migrations.RunSQL(sql=f""" + update "core_User" + set claim_admin_id=maxca.maxid + from "core_User" cu inner join + (select "ClaimAdminCode", max("ClaimAdminId") as maxid from "tblClaimAdmin" where "ValidityTo" is null group by "ClaimAdminCode") maxca + on "ClaimAdminCode"=cu.username + where cu.claim_admin_id is null; + """, reverse_sql="") ] diff --git a/core/migrations/0016_add_last_login_on_interactive_user.py b/core/migrations/0016_add_last_login_on_interactive_user.py index 08132ee8..458cf931 100644 --- a/core/migrations/0016_add_last_login_on_interactive_user.py +++ b/core/migrations/0016_add_last_login_on_interactive_user.py @@ -1,5 +1,5 @@ # Generated by Django 3.0.14 on 2022-01-04 11:04 - +from django.conf import settings from django.db import migrations, models @@ -11,7 +11,9 @@ class Migration(migrations.Migration): operations = [ migrations.RunSQL( - "ALTER TABLE tblUsers ADD LastLogin [datetime] NULL", - reverse_sql="ALTER TABLE tblUsers DROP COLUMN LastLogin", + "ALTER TABLE tblUsers ADD LastLogin [datetime] NULL" + if "sql_server" in settings.DB_ENGINE else + 'ALTER TABLE "tblUsers" ADD "LastLogin" timestamp NULL', + reverse_sql='ALTER TABLE "tblUsers" DROP COLUMN "LastLogin"', ), ] diff --git a/core/utils.py b/core/utils.py index 10191491..d6a61e18 100644 --- a/core/utils.py +++ b/core/utils.py @@ -2,6 +2,11 @@ import graphene from django.db.models import Q from django.utils.translation import gettext as _ +import logging +from django.apps import apps + + +logger = logging.getLogger(__file__) __all__ = [ "TimeUtils", @@ -232,3 +237,16 @@ def get_first_or_default_language(): return sorted_languages.order_by('sort_order').first() else: return Language.objects.first() + + +def insert_role_right_for_system(system_role, right_id): + RoleRight = apps.get_model("core", "RoleRight") + Role = apps.get_model("core", "Role") + existing_role = Role.objects.filter(is_system=system_role).first() + if not existing_role: + logger.warning("Migration requested a role_right for system role %s but couldn't find that role", system_role) + role_right = RoleRight.objects.filter(role=existing_role, right_id=right_id).first() + if not role_right: + role_right = RoleRight.objects.create(role=existing_role, right_id=right_id) + + return role_right From 4f5570bfd345e437bd1b66c9216a2e2e7d035dfb Mon Sep 17 00:00:00 2001 From: Eric Darchis Date: Thu, 11 Aug 2022 16:19:16 +0200 Subject: [PATCH 2/2] Sort by random support on PostgreSQL --- core/schema.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/schema.py b/core/schema.py index 09e98251..f7b5c832 100644 --- a/core/schema.py +++ b/core/schema.py @@ -287,16 +287,18 @@ def _filter_order_by(cls, order_by: str) -> str: def orderBy(cls, qs, args): order = args.get('orderBy', None) if order: + random_expression = RawSQL("NEWID()", params=[]) \ + if "sql_server" in settings.DB_ENGINE else \ + RawSQL("RANDOM()", params=[]) if type(order) is str: if order == "?": - snake_order = RawSQL("NEWID()", params=[]) + snake_order = random_expression else: # due to https://github.com/advisories/GHSA-xpfp-f569-q3p2 we are aggressively filtering the orderBy snake_order = to_snake_case(cls._filter_order_by(order)) else: snake_order = [ - to_snake_case(cls._filter_order_by(o)) if o != "?" else RawSQL( - "NEWID()", params=[]) + to_snake_case(cls._filter_order_by(o)) if o != "?" else random_expression for o in order ] qs = qs.order_by(*snake_order)