Skip to content

Commit db292b0

Browse files
authored
Merge pull request #70 from mapswipe/feature/sync-org-to-firebase
chore(organization): sync organization data into firebase.
2 parents 8284819 + ce454ab commit db292b0

File tree

8 files changed

+162
-6
lines changed

8 files changed

+162
-6
lines changed

apps/project/firebase.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import logging
2+
import typing
3+
4+
from celery import shared_task
5+
from django.utils import timezone
6+
from firebase_admin.db import Reference as FbReference
7+
from pyfirebase_mapswipe import models as firebase_models
8+
from pyfirebase_mapswipe import utils as firebase_utils
9+
10+
from apps.project.models import FirebasePushStatusEnum, Organization
11+
from main.config import Config
12+
from main.logging import log_extra
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
class InvalidOrganizationPushException(Exception): ...
18+
19+
20+
def handle_new_organization_on_firebase(organization: Organization, organization_ref: FbReference):
21+
organization_data = firebase_models.FbOrganisation(
22+
name=organization.name,
23+
nameKey="",
24+
description=organization.description if organization.description else firebase_models.UNDEFINED,
25+
abbreviation=organization.abbreviation if organization.abbreviation else firebase_models.UNDEFINED,
26+
isArchived=organization.is_archived,
27+
)
28+
29+
organization_ref.set(
30+
value={
31+
**firebase_utils.serialize(organization_data),
32+
},
33+
)
34+
35+
36+
def handle_organization_update_on_firebase(organization: Organization, organization_ref: FbReference):
37+
organization_ref.update(
38+
value=firebase_utils.serialize(
39+
firebase_models.FbOrganisation(
40+
name=organization.name,
41+
nameKey="",
42+
description=organization.description if organization.description else firebase_models.UNDEFINED,
43+
abbreviation=organization.abbreviation if organization.abbreviation else firebase_models.UNDEFINED,
44+
isArchived=organization.is_archived,
45+
),
46+
),
47+
)
48+
49+
50+
@shared_task
51+
def push_organization_to_firebase(organization_id: int):
52+
organization = Organization.objects.filter(id=organization_id).first()
53+
if not organization:
54+
return
55+
organization.update_firebase_push_status(FirebasePushStatusEnum.PROCESSING)
56+
57+
try:
58+
organization_ref = Config.FIREBASE_HELPER.ref(
59+
Config.FirebaseKeys.organization(organization.id),
60+
)
61+
fb_organization: typing.Any = organization_ref.get()
62+
63+
if not organization.firebase_last_pushed:
64+
if fb_organization is not None:
65+
logger.error(
66+
"push_to_firebase found a organization already in firebase when creating a organization",
67+
extra=log_extra({"organization": organization.pk}),
68+
)
69+
raise InvalidOrganizationPushException
70+
handle_new_organization_on_firebase(organization, organization_ref)
71+
else:
72+
if fb_organization is None:
73+
logger.error(
74+
"push_to_firebase did not find organization in firebase when updating a organization",
75+
extra=log_extra({"organization": organization.pk}),
76+
)
77+
raise InvalidOrganizationPushException
78+
handle_organization_update_on_firebase(organization, organization_ref)
79+
except InvalidOrganizationPushException:
80+
organization.update_firebase_push_status(FirebasePushStatusEnum.FAILED)
81+
except Exception:
82+
logger.error(
83+
"push_to_firebase failed",
84+
extra=log_extra({"organization": organization.pk}),
85+
exc_info=True,
86+
)
87+
organization.update_firebase_push_status(FirebasePushStatusEnum.FAILED)
88+
else:
89+
organization.firebase_last_pushed = timezone.now()
90+
organization.update_firebase_push_status(FirebasePushStatusEnum.SUCCESS, commit=False)
91+
organization.save(
92+
update_fields=[
93+
"firebase_last_pushed",
94+
"firebase_push_status",
95+
],
96+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 5.2.4 on 2025-07-25 09:42
2+
3+
import apps.project.models
4+
import django_choices_field.fields
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('project', '0008_merge_20250722_0437'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='organization',
17+
name='firebase_last_pushed',
18+
field=models.DateTimeField(blank=True, help_text='The latest time when organization was pushed to firebase', null=True),
19+
),
20+
migrations.AddField(
21+
model_name='organization',
22+
name='firebase_push_status',
23+
field=django_choices_field.fields.IntegerChoicesField(blank=True, choices=[(1, 'Pending'), (2, 'Processing'), (3, 'Success'), (4, 'Failed')], choices_enum=apps.project.models.FirebasePushStatusEnum, null=True),
24+
),
25+
]

apps/project/models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,28 @@ class Organization(UserResource, ArchivableResource): # type: ignore[reportInco
161161
unique=True,
162162
)
163163

164+
# FIREBASE FIELDS
165+
166+
firebase_push_status: int | None = IntegerChoicesField( # type: ignore[reportAssignmentType]
167+
choices_enum=FirebasePushStatusEnum,
168+
null=True,
169+
blank=True,
170+
)
171+
firebase_last_pushed = models.DateTimeField(
172+
null=True,
173+
blank=True,
174+
help_text=gettext_lazy("The latest time when organization was pushed to firebase"),
175+
)
176+
164177
@typing.override
165178
def __str__(self) -> str:
166179
return self.name
167180

181+
def update_firebase_push_status(self, firebase_push_status: FirebasePushStatusEnum, *, commit: bool = True):
182+
self.firebase_push_status = firebase_push_status
183+
if commit:
184+
self.save(update_fields=("firebase_push_status",))
185+
168186

169187
class Project(UserResource):
170188
Type = ProjectTypeEnum

apps/project/serializers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from rest_framework import serializers
77

88
from apps.common.serializers import ArchivableResourceSerializer, UserResourceSerializer
9+
from apps.project.firebase import push_organization_to_firebase
910
from apps.tutorial.models import Tutorial
1011
from project_types.store import get_project_property
1112
from utils.common import clean_up_none_keys
@@ -348,3 +349,15 @@ class OrganizationSerializer(UserResourceSerializer[Organization], ArchivableRes
348349
class Meta: # type: ignore[reportIncompatibleVariableOverride]
349350
model = Organization
350351
fields = ("name", "description", "abbreviation")
352+
353+
@typing.override
354+
def create(self, validated_data: dict[str, typing.Any]) -> Organization:
355+
organization = super().create(validated_data)
356+
transaction.on_commit(lambda: push_organization_to_firebase.delay(organization.pk))
357+
return organization
358+
359+
@typing.override
360+
def update(self, instance: Organization, validated_data: dict[typing.Any, typing.Any]):
361+
organization = super().update(instance, validated_data)
362+
transaction.on_commit(lambda: push_organization_to_firebase.delay(organization.pk))
363+
return organization

main/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ def project_groups(project_id: str | int):
4242
def project_tasks(project_id: str | int):
4343
return f"/v2/groups/{project_id}/"
4444

45+
@staticmethod
46+
def organization(organization_id: str | int):
47+
return f"/v2/organisation/{organization_id}/"
48+
4549

4650
# FIXME: Import utils/geo/raster_tile_server/config.py here
4751
# FIXME: Import utils/geo/vector_tile_server/config.py here

project_types/base/project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ def push_to_firebase(self):
384384
else:
385385
if fb_project is None:
386386
logger.error(
387-
"push_to_firebase found did not find project in firebase when updating a project",
387+
"push_to_firebase did not find project in firebase when updating a project",
388388
extra=log_extra({"project": self.project.pk}),
389389
)
390390
raise InvalidProjectPushException

schema.graphql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ enum Ordering {
708708
}
709709

710710
"""
711-
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name)
711+
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name, firebase_push_status, firebase_last_pushed)
712712
"""
713713
input OrganizationCreateInput {
714714
clientId: String!
@@ -718,7 +718,7 @@ input OrganizationCreateInput {
718718
}
719719

720720
"""
721-
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name)
721+
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name, firebase_push_status, firebase_last_pushed)
722722
"""
723723
input OrganizationFilter {
724724
id: IDBaseFilterLookup
@@ -741,7 +741,7 @@ type OrganizationSwipeStatsType {
741741
}
742742

743743
"""
744-
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name)
744+
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name, firebase_push_status, firebase_last_pushed)
745745
"""
746746
type OrganizationType implements UserResourceTypeMixin {
747747
clientId: String!
@@ -775,7 +775,7 @@ type OrganizationTypeOffsetPaginated {
775775
}
776776

777777
"""
778-
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name)
778+
Organization(id, client_id, created_at, modified_at, created_by, modified_by, is_archived, archived_at, archived_by, name, description, abbreviation, unique_name, firebase_push_status, firebase_last_pushed)
779779
"""
780780
input OrganizationUpdateInput {
781781
clientId: String!

0 commit comments

Comments
 (0)