Skip to content

Commit 9b1f315

Browse files
Merge pull request #2522 from IFRCGo/project/local-unit-edit-functionality
Project: Local unit edit functionality workflow
2 parents 9570843 + 2df1fd0 commit 9b1f315

26 files changed

+2294
-227
lines changed

api/serializers.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
from collections import defaultdict
23
from typing import List, Union
34

45
from django.conf import settings
@@ -11,6 +12,7 @@
1112

1213
# from api.utils import pdf_exporter
1314
from api.tasks import generate_url
15+
from api.utils import CountryValidator, RegionValidator
1416
from deployments.models import EmergencyProject, Personnel, PersonnelDeployment
1517
from dref.models import Dref, DrefFinalReport, DrefOperationalUpdate
1618
from lang.models import String
@@ -1771,6 +1773,10 @@ class UserMeSerializer(UserSerializer):
17711773
user_countries_regions = serializers.SerializerMethodField()
17721774
limit_access_to_guest = serializers.BooleanField(read_only=True, source="profile.limit_access_to_guest")
17731775

1776+
local_unit_country_validators = serializers.SerializerMethodField()
1777+
local_unit_region_validators = serializers.SerializerMethodField()
1778+
local_unit_global_validators = serializers.SerializerMethodField()
1779+
17741780
class Meta:
17751781
model = User
17761782
fields = UserSerializer.Meta.fields + (
@@ -1782,6 +1788,9 @@ class Meta:
17821788
"is_per_admin_for_countries",
17831789
"user_countries_regions",
17841790
"limit_access_to_guest",
1791+
"local_unit_country_validators",
1792+
"local_unit_region_validators",
1793+
"local_unit_global_validators",
17851794
)
17861795

17871796
@staticmethod
@@ -1845,6 +1854,49 @@ def get_user_countries_regions(user):
18451854
qs = UserCountry.objects.filter(user=user).distinct("country")
18461855
return UserCountrySerializer(qs, many=True).data
18471856

1857+
@staticmethod
1858+
def get_local_unit_global_validators(user) -> List[int]:
1859+
permission_codenames = Permission.objects.filter(
1860+
codename__startswith="local_unit_global_validator", group__user=user
1861+
).values_list("codename", flat=True)
1862+
global_validators = {int(code.split("_")[-1]) for code in permission_codenames}
1863+
return list(global_validators)
1864+
1865+
@staticmethod
1866+
def get_local_unit_region_validators(user) -> list[RegionValidator]:
1867+
permission_codenames = Permission.objects.filter(
1868+
codename__startswith="local_unit_region_validator",
1869+
group__user=user,
1870+
).values_list("codename", flat=True)
1871+
region_validators = defaultdict(set)
1872+
for code in permission_codenames:
1873+
parts = code.split("_")[-2:]
1874+
if len(parts) == 2 and all(p.isdigit() for p in parts):
1875+
local_unit_type_id = int(parts[0])
1876+
region_id = int(parts[1])
1877+
region_validators[region_id].add(local_unit_type_id)
1878+
return [
1879+
{"region": region, "local_unit_types": list(local_unit_types)}
1880+
for region, local_unit_types in region_validators.items()
1881+
]
1882+
1883+
@staticmethod
1884+
def get_local_unit_country_validators(user) -> list[CountryValidator]:
1885+
permission_codenames = Permission.objects.filter(
1886+
codename__startswith="local_unit_country_validator", group__user=user
1887+
).values_list("codename", flat=True)
1888+
country_validator = defaultdict(set)
1889+
for code in permission_codenames:
1890+
parts = code.split("_")[-2:]
1891+
if len(parts) == 2 and all(p.isdigit() for p in parts):
1892+
local_unit_type_id = int(parts[0])
1893+
country_id = int(parts[1])
1894+
country_validator[country_id].add(local_unit_type_id)
1895+
return [
1896+
{"country": country, "local_unit_types": list(local_unit_types)}
1897+
for country, local_unit_types in country_validator.items()
1898+
]
1899+
18481900

18491901
class ActionSerializer(ModelSerializer):
18501902
class Meta:

api/utils.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import base64
22
import typing
3-
from typing import Optional
3+
from typing import Optional, TypedDict
44

55
from django.core.exceptions import ValidationError
66
from django.db import models
@@ -146,3 +146,13 @@ def generate_field_report_title(
146146
else:
147147
summary = f"{country.iso3}: {dtype.name} - {start_date} - {title} {suffix}"
148148
return summary
149+
150+
151+
class RegionValidator(TypedDict):
152+
region: int
153+
local_unit_types: list[int]
154+
155+
156+
class CountryValidator(TypedDict):
157+
country: int
158+
local_unit_types: list[int]

deploy/helm/ifrcgo-helm/values.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,9 @@ cronjobs:
271271
schedule: '0 0 * * 0'
272272
- command: 'ingest_icrc'
273273
schedule: '0 3 * * 0'
274-
- command: 'notify_validators'
275-
schedule: '0 0 * * *'
274+
# NOTE: Disabling local unit email notification for now
275+
# - command: 'notify_validators'
276+
# schedule: '0 0 * * *'
276277
# https://github.com/jazzband/django-oauth-toolkit/blob/master/docs/management_commands.rst#cleartokens
277278
- command: 'oauth_cleartokens'
278279
schedule: '0 1 * * *'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
local_branch_name,english_branch_name,subtype,level,postcode,address_loc,address_en,city_loc,city_en,focal_person_loc,focal_person_en,phone,email,link,source_en,source_loc,date_of_data,visibility,longitude,latitude
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
focal_point_email,focal_point_phone_number,focal_point_position,health_facility_type,other_facility_type,affiliation,functionality,primary_health_care_centre,speciality,hospital_type,is_teaching_hospital,is_in_patient_capacity,maximum_capacity,is_isolation_rooms_wards,number_of_isolation_rooms,is_warehousing,is_cold_chain,general_medical_services,specialized_medical_beyond_primary_level,other_services,blood_services,total_number_of_human_resource,general_practitioner,specialist,residents_doctor,nurse,dentist,nursing_aid,midwife,other_medical_heal,other_profiles,feedback,professional_training_facilities,ambulance_type_a,ambulance_type_b,ambulance_type_c,residential_long_term_care_facilities,primary_health_care_center,other_affiliation,local_branch_name,english_branch_name,subtype,level,postcode,address_loc,address_en,city_loc,city_en,focal_person_loc,focal_person_en,phone,email,link,source_en,source_loc,date_of_data,visibility,longitude,latitude

local_units/admin.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
BloodService,
1111
DelegationOffice,
1212
DelegationOfficeType,
13+
ExternallyManagedLocalUnit,
1314
FacilityType,
1415
Functionality,
1516
GeneralMedicalService,
1617
HealthData,
1718
HospitalType,
1819
LocalUnit,
20+
LocalUnitBulkUpload,
1921
LocalUnitChangeRequest,
2022
LocalUnitLevel,
2123
LocalUnitType,
@@ -51,10 +53,13 @@ class LocalUnitAdmin(CompareVersionAdmin, admin.OSMGeoAdmin):
5153
"type",
5254
"level",
5355
"health",
56+
"bulk_upload",
5457
)
5558
readonly_fields = (
5659
"validated",
60+
"status",
5761
"is_locked",
62+
"is_new_local_unit",
5863
)
5964
list_filter = (
6065
AutocompleteFilterFactory("Country", "country"),
@@ -71,6 +76,42 @@ def save_model(self, request, obj, form, change):
7176
super().save_model(request, obj, form, change)
7277

7378

79+
@admin.register(ExternallyManagedLocalUnit)
80+
class ExternallyManagedLocalUnitAdmin(admin.ModelAdmin):
81+
list_display = ("local_unit_type", "created_at", "updated_at")
82+
search_fields = ("country__name",)
83+
list_select_related = True
84+
autocomplete_fields = (
85+
"country",
86+
"local_unit_type",
87+
)
88+
list_filter = (
89+
AutocompleteFilterFactory("Country", "country"),
90+
AutocompleteFilterFactory("Type", "local_unit_type"),
91+
)
92+
93+
94+
@admin.register(LocalUnitBulkUpload)
95+
class LocalUnitBulkUploadAdmin(ReadOnlyMixin, admin.ModelAdmin):
96+
search_fields = ("country__name", "local_unit_type__id")
97+
list_select_related = True
98+
autocomplete_fields = (
99+
"country",
100+
"local_unit_type",
101+
"triggered_by",
102+
)
103+
list_filter = ("status",)
104+
105+
def get_queryset(self, request):
106+
return (
107+
super()
108+
.get_queryset(request)
109+
.select_related(
110+
"triggered_by",
111+
)
112+
)
113+
114+
74115
@admin.register(LocalUnitChangeRequest)
75116
class LocalUnitChangeRequestAdmin(ReadOnlyMixin, admin.ModelAdmin):
76117
autocomplete_fields = (

0 commit comments

Comments
 (0)