Skip to content

Commit

Permalink
Merge pull request #136 from openimis/develop
Browse files Browse the repository at this point in the history
MERGING RELEASE branches
  • Loading branch information
delcroip committed Nov 10, 2022
2 parents 4941748 + d5749ae commit 43392b9
Show file tree
Hide file tree
Showing 25 changed files with 379 additions and 88 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ If the callback returns None (or an empty array), the mutation is marked as succ

__Important Note__: by default the callback is executed __in transaction__ and, as a consequence, will (in case of exception/errors) cancel the complete mutation. If this is not the desired behaviour, the callback must explicitely detach to separate transaction (process).

#### Extending mutations with signals
Signal callbacks could use mutationExtensions JSON field to receive additional data from mutation payload. This
feature allows to extend mutations with a new module without modifying the base mutation.

#### Service signals
In addition, the core provides the possibility to register additional signals via
the `register_service_signal` decorator. Registered signals are stored in
Expand All @@ -130,6 +134,27 @@ When running the application, the modules are searched for the `bind_service_sig
function in the module_name/signals.py directory. This method should use `core.signals.bind_service_signal`
function to connect new signals. Receivers can be registered also in other places.

#### Modules Scheduled Tasks
To add a scheduled task directly from within a module, add the file `scheduled_tasks.py`
in the module package. From there, the function `schedule_tasks` accepting `BackgroundScheudler`
as argument must be accessible.

**Example content of scheduled_tasks.py:**
```python
def module_task():
...

def schedule_tasks(scheduler: BackgroundScheduler): # Has to accept BackgroundScheudler as input
scheduler.add_job(
module_task,
trigger=CronTrigger(hour=8), # Daily at 8 AM
id="custom_schedule_id", # Must be unique across application
max_instances=1
)
```
Task will be automatically registered, but it will not be triggered unless `SCHEDULER_AUTOSTART` setting is
set to `True`.

### Graphene Custom Types & Helper Classes/Methods
* schema.SmallInt: Integer, with values ranging from -32768 to +32767
* schema.TinyInt: Integer (8 bit), with values ranging from 0 to 255
Expand Down
21 changes: 14 additions & 7 deletions core/abs_calculation_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,22 @@ def run_calculation_rules(cls, sender, instance, user, context, **kwargs):
reply if they have object matching the classname in their list of object
"""
list_class = cls.get_linked_class(sender=sender, class_name=instance.__class__.__name__)
# if the class have a calculation param, (like contribution or payment plan) add class name
if hasattr(instance, 'calculation'):
list_class.append(instance.__class__.__name__)
if list_class:
if len(list_class) > 0:
rule_details = cls.get_rule_details(class_name=list_class[0], sender=sender)
for class_name in list_class:
rule_details = cls.get_rule_details(class_name=class_name, sender=sender)
if rule_details or len(cls.impacted_class_parameter) == 0:
if cls.active_for_object(instance=instance, context=context):
# add context to kwargs
kwargs["context"] = context
result = cls.calculate(instance, **kwargs)
return result
# add context to kwargs
kwargs["context"] = context
result = cls.calculate_if_active_for_object(instance, **kwargs)
return result

@classmethod
def calculate_if_active_for_object(cls, instance, **kwargs):
if cls.active_for_object(instance=instance, context=kwargs['context']):
return cls.calculate(instance, **kwargs)

@classmethod
def run_convert(cls, instance, convert_to, **kwargs):
Expand Down
10 changes: 10 additions & 0 deletions core/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,13 @@
"gql_mutation_create_claim_administrator_perms": ["121602"],
"gql_mutation_update_claim_administrator_perms": ["121603"],
"gql_mutation_delete_claim_administrator_perms": ["121604"],
"fields_controls_user": {},
"fields_controls_eo": {},
}


class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.AutoField' # Django 3.1+
name = MODULE_NAME
age_of_majority = 18
password_reset_template = "password_reset.txt"
Expand All @@ -74,6 +77,9 @@ class CoreConfig(AppConfig):
gql_mutation_update_claim_administrator_perms = []
gql_mutation_delete_claim_administrator_perms = []

fields_controls_user = {}
fields_controls_eo = {}

def _import_module(self, cfg, k):
logger.info('import %s.%s' %
(cfg["%s_module" % k], cfg["%s_package" % k]))
Expand Down Expand Up @@ -141,6 +147,10 @@ def _configure_permissions(self, cfg):
CoreConfig.gql_mutation_create_claim_administrator_perms = cfg["gql_mutation_create_claim_administrator_perms"]
CoreConfig.gql_mutation_update_claim_administrator_perms = cfg["gql_mutation_update_claim_administrator_perms"]
CoreConfig.gql_mutation_delete_claim_administrator_perms = cfg["gql_mutation_delete_claim_administrator_perms"]
CoreConfig.gql_mutation_delete_claim_administrator_perms = cfg["gql_mutation_delete_claim_administrator_perms"]

CoreConfig.fields_controls_user = cfg["fields_controls_user"]
CoreConfig.fields_controls_eo = cfg["fields_controls_eo"]

def ready(self):
from .models import ModuleConfiguration
Expand Down
4 changes: 1 addition & 3 deletions core/calendars/test_ad_calendar.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import sys
import importlib
import core
from django.test import TestCase
from ..datetimes.ad_datetime import date
from .ad_calendar import *


class CalendarTestCase(TestCase):
def setUp(self):
super(CalendarTestCase, self).setUp()
core.calendar = importlib.import_module(
'.calendars.ad_calendar', 'core')
core.datetime = importlib.import_module(
Expand Down
6 changes: 3 additions & 3 deletions core/calendars/test_ne_calendar.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import sys
import importlib
import core
from django.test import TestCase
Expand All @@ -7,6 +6,7 @@

class CalendarTestCase(TestCase):
def setUp(self):
super(CalendarTestCase, self).setUp()
core.calendar = importlib.import_module(
'.calendars.ne_calendar', 'core')
core.datetime = importlib.import_module(
Expand All @@ -16,7 +16,7 @@ def tearDown(self):
core.calendar = importlib.import_module(
'.calendars.ad_calendar', 'core')
core.datetime = importlib.import_module(
'.datetimes.ad_datetime', 'core')
'.datetimes.ad_datetime', 'core')

def test_from_ad_date(self):
dt = core.datetime.date.from_ad_date(py_date(2020, 1, 13))
Expand All @@ -36,7 +36,7 @@ def test_weekday(self):
wd = core.calendar.weekday(2076, 9, 11)
self.assertEqual(wd, 5)
wd = core.calendar.weekday(2076, 9, 28)
self.assertEqual(wd, 1)
self.assertEqual(wd, 1)

def test_monthfirstday(self):
dt = core.calendar.monthfirstday(2076, 9)
Expand Down
8 changes: 3 additions & 5 deletions core/custom_lookups.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from django.db.models import Lookup
from django.db.models import Lookup, JSONField
from django.db.models.lookups import Contains

from jsonfallback.fields import FallbackJSONField


@FallbackJSONField.register_lookup
@JSONField.register_lookup
class JsonContains(Lookup):
lookup_name = 'jsoncontains'

Expand Down Expand Up @@ -43,7 +41,7 @@ def _build_sql_params(self, entity, json_conditions, ):
return conditions


@FallbackJSONField.register_lookup
@JSONField.register_lookup
class JsonContainsKey(Contains):
lookup_name = 'jsoncontainskey'

Expand Down
2 changes: 2 additions & 0 deletions core/datetimes/test_ad_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

class SharedUtilsTest(TestCase):
def setUp(self):
super(SharedUtilsTest, self).setUp()
core.calendar = importlib.import_module(
'.calendars.ad_calendar', 'core')
core.datetime = importlib.import_module(
Expand Down Expand Up @@ -148,6 +149,7 @@ def test_diff(self):

class AdDatetimeTestCase(TestCase):
def setUp(self):
super(AdDatetimeTestCase, self).setUp()
core.calendar = importlib.import_module(
'.calendars.ad_calendar', 'core')
core.datetime = importlib.import_module(
Expand Down
2 changes: 2 additions & 0 deletions core/datetimes/test_ne_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

class NeDateTestCase(TestCase):
def setUp(self):
super(NeDateTestCase, self).setUp()
core.calendar = importlib.import_module(
'.calendars.ne_calendar', 'core')
core.datetime = importlib.import_module(
Expand Down Expand Up @@ -163,6 +164,7 @@ def test_diff(self):

class NeDatetimeTestCase(TestCase):
def setUp(self):
super(NeDatetimeTestCase, self).setUp()
core.calendar = importlib.import_module(
'.calendars.ne_calendar', 'core')
core.datetime = importlib.import_module(
Expand Down
6 changes: 5 additions & 1 deletion core/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

User = get_user_model()


class TechnicalUserForm(forms.ModelForm):
password = forms.CharField(
strip=False,
Expand All @@ -25,9 +26,11 @@ def save(self, commit=True):
user.save()
return user


class TechnicalUserAdmin(admin.ModelAdmin):
form = TechnicalUserForm


class GroupAdminForm(forms.ModelForm):
class Meta:
model = Group
Expand All @@ -52,6 +55,7 @@ def save(self, *args, **kwargs):
self.save_m2m()
return instance


class GroupAdmin(admin.ModelAdmin):
form = GroupAdminForm
filter_horizontal = ['permissions']
filter_horizontal = ['permissions']
8 changes: 8 additions & 0 deletions core/gql_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ def get_queryset(cls, queryset, info):


class RoleGQLType(DjangoObjectType):
system_role_id = graphene.Int()

class Meta:
model = Role
interfaces = (graphene.relay.Node,)
Expand Down Expand Up @@ -123,6 +125,12 @@ def resolve_roles(self, info, **kwargs):
else:
return None

def resolve_userdistrict_set(self, info, **kwargs):
if self.userdistrict_set:
return self.userdistrict_set.filter(*filter_validity())
else:
return None

@classmethod
def get_queryset(cls, queryset, info):
return InteractiveUser.get_queryset(queryset, info)
Expand Down
1 change: 0 additions & 1 deletion core/jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 0 additions & 28 deletions core/migrations/0012_users_officers_admins.py
Original file line number Diff line number Diff line change
Expand Up @@ -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="")
]
41 changes: 40 additions & 1 deletion core/migrations/0013_users_api.py
Original file line number Diff line number Diff line change
@@ -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 settings.MSSQL else "gen_random_uuid()"


class Migration(migrations.Migration):

dependencies = [
Expand All @@ -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="")
]
2 changes: 1 addition & 1 deletion core/migrations/0015_missing_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
logger = logging.getLogger(__name__)

ROLE_RIGHTS_ID = [101201, 101101, 101001, 101105]
MANAGER_ROLE_IS_SYSTEM = 256 # By default missing rights are assigned to ClaimAdmin role
MANAGER_ROLE_IS_SYSTEM = 64 # By default missing rights are assigned to ClaimAdmin role


@lru_cache(maxsize=1)
Expand Down
8 changes: 5 additions & 3 deletions core/migrations/0016_add_last_login_on_interactive_user.py
Original file line number Diff line number Diff line change
@@ -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


Expand All @@ -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 settings.MSSQL else
'ALTER TABLE "tblUsers" ADD "LastLogin" timestamp NULL',
reverse_sql='ALTER TABLE "tblUsers" DROP COLUMN "LastLogin"',
),
]
Loading

0 comments on commit 43392b9

Please sign in to comment.