Skip to content

Commit

Permalink
add bulk_update_export
Browse files Browse the repository at this point in the history
  • Loading branch information
saxix committed Oct 22, 2024
1 parent 8dfabfc commit 79175be
Show file tree
Hide file tree
Showing 29 changed files with 689 additions and 116 deletions.
3 changes: 2 additions & 1 deletion docker/bin/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ case "$1" in
;;
worker)
set -- tini -- "$@"
set -- gosu user:app celery -A country_workspace.config.celery worker -E --loglevel=ERROR --concurrency=4
set -- gosu user:app
celery -A country_workspace.config.celery worker -E --loglevel=ERROR --concurrency=4
;;
beat)
set -- tini -- "$@"
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies = [
"hope-flex-fields>=0.5.0",
"hope-smart-export>=0.3.0",
"hope-smart-import>=0.3.0",
"openpyxl>=3.1.5",
"psycopg2-binary>=2.9.9",
"redis",
"sentry-sdk>=2.7.1",
Expand Down
9 changes: 9 additions & 0 deletions src/country_workspace/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
from django.contrib.admin import site
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

from smart_admin.smart_auth.admin import ContentTypeAdmin, PermissionAdmin

from .batch import BatchAdmin # noqa
from .household import HouseholdAdmin # noqa
from .individual import IndividualAdmin # noqa
Expand All @@ -7,3 +13,6 @@
from .role import UserRoleAdmin # noqa
from .sync import SyncLog # noqa
from .user import UserAdmin # noqa

site.register(ContentType, admin_class=ContentTypeAdmin)
site.register(Permission, admin_class=PermissionAdmin)
9 changes: 8 additions & 1 deletion src/country_workspace/admin/sync.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from django.contrib import admin

from admin_extra_buttons.decorators import button

from ..models import SyncLog
from .base import BaseModelAdmin


@admin.register(SyncLog)
class SyncLogAdmin(admin.ModelAdmin):
class SyncLogAdmin(BaseModelAdmin):
list_display = ("content_type", "content_object", "last_update_date", "last_id")

@button()
def sync_all(self, request):
SyncLog.objects.refresh()
5 changes: 4 additions & 1 deletion src/country_workspace/config/fragments/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
TENANT_HQ = "= HQ ="

HOPE_API_TOKEN = env("HOPE_API_TOKEN")
LOOKUPS = ["ResidenceStatus", "Relationship", "Role", "MaritalStatus", "ObservedDisability"]
HH_LOOKUPS = [
"ResidenceStatus",
]
IND_LOOKUPS = ["Relationship", "Role", "MaritalStatus", "ObservedDisability"]
29 changes: 28 additions & 1 deletion src/country_workspace/models/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@
from django.utils import timezone

from country_workspace.models.base import BaseManager, BaseModel
from country_workspace.sync.client import HopeClient


class SyncManager(BaseManager):
def refresh(self):
for record in self.all():
record.refresh()

def create_lookups(self):
from hope_flex_fields.models import FieldDefinition

ct = ContentType.objects.get_for_model(FieldDefinition)
for m in settings.LOOKUPS:
for m in settings.HH_LOOKUPS:
fd = FieldDefinition.objects.get(name="HOPE HH {m}".format(m=m))
SyncLog.objects.get_or_create(
content_type=ct, object_id=fd.pk, data={"remote_url": "lookups/%s" % m.lower()}
)
for m in settings.IND_LOOKUPS:
fd = FieldDefinition.objects.get(name="HOPE IND {m}".format(m=m))
SyncLog.objects.get_or_create(
content_type=ct, object_id=fd.pk, data={"remote_url": "lookups/%s" % m.lower()}
)

def register_sync(self, model: "type[Model]") -> None:
ct = ContentType.objects.get_for_model(model)
Expand All @@ -38,3 +48,20 @@ class SyncLog(BaseModel):
data = models.JSONField(default=dict, blank=True)

objects = SyncManager()

def refresh(self):
fd = self.content_object
if not fd:
return
if "remote_url" in self.data:
client = HopeClient()
record = client.get_lookup(self.data["remote_url"])
choices = []
for k, v in record.items():
choices.append((k, v))
if not fd.attrs:
fd.attrs = {}
fd.attrs["choices"] = choices
fd.save()
self.last_update_date = timezone.now()
self.save()
27 changes: 1 addition & 26 deletions src/country_workspace/sync/office.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from typing import Optional

from django.utils import timezone

from hope_flex_fields.models import DataChecker

from country_workspace.models import Office, Program, SyncLog
Expand Down Expand Up @@ -60,31 +58,8 @@ def sync_programs(limit_to_office: "Optional[Office]" = None) -> int:
return i


def sync_lookup(sl: SyncLog):
fd = sl.content_object
if not fd:
return
client = HopeClient()
record = client.get_lookup(sl.data["remote_url"])
choices = []
for k, v in record.items():
choices.append((k, v))
if not fd.attrs:
fd.attrs = {}
fd.attrs["choices"] = choices
fd.save()
sl.last_update_date = timezone.now()
sl.save()


def sync_lookups() -> bool:
for sl in SyncLog.objects.filter(object_id__gt=0).exclude(content_type__isnull=True):
sync_lookup(sl)
return True


def sync_all() -> bool:
sync_offices()
sync_programs()
sync_lookups()
SyncLog.objects.refresh()
return True
41 changes: 17 additions & 24 deletions src/country_workspace/versioning/checkers.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,21 @@
from django import forms
from django.conf import settings
from django.utils.text import slugify

from hope_flex_fields.models import DataChecker, FieldDefinition, Fieldset

from country_workspace.constants import HOUSEHOLD_CHECKER_NAME, INDIVIDUAL_CHECKER_NAME


def create_hope_field_definitions():
for m in settings.LOOKUPS:
n = f"HOPE HH {m}"
FieldDefinition.objects.get_or_create(name=n, slug=slugify(n), field_type=forms.ChoiceField)
FieldDefinition.objects.get_or_create(
name="HOPE IND Gender",
slug=slugify("HOPE IND Gender"),
attrs={"choices": [["FEMALE", "FEMALE"], ["MALE", "MALE"], ["UNKNOWN", "UNKNOWN"]]},
field_type=forms.ChoiceField,
)
FieldDefinition.objects.get_or_create(
name="HOPE IND Disability",
slug=slugify("HOPE IND Disability"),
field_type=forms.ChoiceField,
attrs={"choices": [["not disabled", "not disabled"], ["disabled", "disabled"]]},
)


def create_hope_core_fieldset():
def create_hope_checkers():
_char = FieldDefinition.objects.get(field_type=forms.CharField)
_date = FieldDefinition.objects.get(field_type=forms.DateField)
_bool = FieldDefinition.objects.get(field_type=forms.BooleanField)
_int = FieldDefinition.objects.get(field_type=forms.IntegerField)

_h_relationship = FieldDefinition.objects.get(slug="hope-hh-relationship")
_h_residence = FieldDefinition.objects.get(slug="hope-hh-residencestatus")
_i_gender = FieldDefinition.objects.get(slug="hope-ind-gender")
_i_disability = FieldDefinition.objects.get(slug="hope-ind-disability")
_i_role = FieldDefinition.objects.get(slug="hope-ind-role")
_i_relationship = FieldDefinition.objects.get(slug="hope-ind-relationship")

hh_fs, __ = Fieldset.objects.get_or_create(name=HOUSEHOLD_CHECKER_NAME)
hh_fs.fields.get_or_create(
Expand Down Expand Up @@ -135,7 +116,7 @@ def create_hope_core_fieldset():
# hh_fs.fields.get_or_create(field=_bf, name="hh_latrine_h_f", attrs={"label": "Latrine"})
# hh_fs.fields.get_or_create(field=_bf, name="hh_electricity_h_f")

ind_fs, __ = Fieldset.objects.get_or_create(name="HOPE individual core")
ind_fs, __ = Fieldset.objects.get_or_create(name=INDIVIDUAL_CHECKER_NAME)
ind_fs.fields.get_or_create(
name="address",
attrs={"label": "Household ID", "required": True},
Expand Down Expand Up @@ -216,10 +197,22 @@ def create_hope_core_fieldset():
ind_fs.fields.get_or_create(
name="relationship",
attrs={"label": "Relationship"},
field=_h_relationship,
field=_i_relationship,
)
ind_fs.fields.get_or_create(
name="role",
attrs={"label": "Role"},
field=_i_role,
)

hh_dc, __ = DataChecker.objects.get_or_create(name=HOUSEHOLD_CHECKER_NAME)
hh_dc.fieldsets.add(hh_fs)
ind_dc, __ = DataChecker.objects.get_or_create(name=INDIVIDUAL_CHECKER_NAME)
ind_dc.fieldsets.add(ind_fs)


def removes_hope_checkers():
DataChecker.objects.filter(name=HOUSEHOLD_CHECKER_NAME).delete()
DataChecker.objects.filter(name=INDIVIDUAL_CHECKER_NAME).delete()
Fieldset.objects.filter(name=HOUSEHOLD_CHECKER_NAME).delete()
Fieldset.objects.filter(name=INDIVIDUAL_CHECKER_NAME).delete()
34 changes: 34 additions & 0 deletions src/country_workspace/versioning/hope_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django import forms
from django.conf import settings
from django.utils.text import slugify

from hope_flex_fields.models import FieldDefinition

from country_workspace.models import SyncLog


def create_hope_field_definitions():
for m in settings.HH_LOOKUPS:
n = f"HOPE HH {m}"
FieldDefinition.objects.get_or_create(name=n, slug=slugify(n), field_type=forms.ChoiceField)
for m in settings.IND_LOOKUPS:
n = f"HOPE IND {m}"
FieldDefinition.objects.get_or_create(name=n, slug=slugify(n), field_type=forms.ChoiceField)
FieldDefinition.objects.get_or_create(
name="HOPE IND Gender",
slug=slugify("HOPE IND Gender"),
attrs={"choices": [["FEMALE", "FEMALE"], ["MALE", "MALE"], ["UNKNOWN", "UNKNOWN"]]},
field_type=forms.ChoiceField,
)
FieldDefinition.objects.get_or_create(
name="HOPE IND Disability",
slug=slugify("HOPE IND Disability"),
field_type=forms.ChoiceField,
attrs={"choices": [["not disabled", "not disabled"], ["disabled", "disabled"]]},
)

SyncLog.objects.create_lookups()


def removes_hope_field_definitions():
FieldDefinition.objects.filter(name__startswith="HOPE ").delete()
20 changes: 3 additions & 17 deletions src/country_workspace/versioning/scripts/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# Generated by Django 5.1.1 on 2024-10-09 06:19
from flags.state import enable_flag
from hope_flex_fields.models import DataChecker, FieldDefinition, Fieldset
from hope_flex_fields.models import DataChecker, Fieldset

from country_workspace.constants import HOUSEHOLD_CHECKER_NAME, INDIVIDUAL_CHECKER_NAME
from country_workspace.versioning.checkers import create_hope_core_fieldset, create_hope_field_definitions


def removes_hope_field_definitions():
FieldDefinition.objects.filter(name__startswith="HOPE ").delete()


def removes_hope_core_fieldset():
Expand All @@ -18,7 +13,7 @@ def removes_hope_core_fieldset():
DataChecker.objects.filter(name=HOUSEHOLD_CHECKER_NAME).delete()


def create_base_fields_definitions():
def create_default_fields_definitions():
from hope_flex_fields.models import FieldDefinition
from hope_flex_fields.registry import field_registry
from hope_flex_fields.utils import get_default_attrs, get_kwargs_from_field_class
Expand All @@ -34,21 +29,12 @@ def create_base_fields_definitions():
)


def create_default_sys_logs():
from country_workspace.models import SyncLog

SyncLog.objects.create_lookups()


def enable_local_login():
enable_flag("LOCAL_LOGIN")


class Scripts:
operations = [
enable_local_login,
create_base_fields_definitions,
(create_hope_field_definitions, removes_hope_field_definitions),
(create_hope_core_fieldset, removes_hope_core_fieldset),
create_default_sys_logs,
create_default_fields_definitions,
]
7 changes: 7 additions & 0 deletions src/country_workspace/versioning/scripts/0002_hope_fd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from country_workspace.versioning.hope_fields import create_hope_field_definitions, removes_hope_field_definitions


class Scripts:
operations = [
(create_hope_field_definitions, removes_hope_field_definitions),
]
5 changes: 0 additions & 5 deletions src/country_workspace/versioning/scripts/0002_synclog.py

This file was deleted.

17 changes: 0 additions & 17 deletions src/country_workspace/versioning/synclog.py

This file was deleted.

20 changes: 16 additions & 4 deletions src/country_workspace/web/static/workspace/css/cw.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/country_workspace/web/static/workspace/css/cw.css.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 79175be

Please sign in to comment.