From e8108ad82931c016ef95e25873b8780edcc68339 Mon Sep 17 00:00:00 2001 From: ngovinh2k2 Date: Mon, 17 Aug 2026 17:17:04 +0700 Subject: [PATCH] feat:implement the default settings for water level --- apps/organization_monitoring/__init__.py | 0 apps/organization_monitoring/apps.py | 6 ++ apps/organization_monitoring/constants.py | 5 ++ .../migrations/0001_initial.py | 55 +++++++++++++++++++ .../migrations/__init__.py | 0 apps/organization_monitoring/models.py | 31 +++++++++++ apps/organization_monitoring/serializers.py | 23 ++++++++ apps/organization_monitoring/services.py | 23 ++++++++ apps/organization_monitoring/urls.py | 21 +++++++ apps/organization_monitoring/views.py | 20 +++++++ .../management/commands/init_organization.py | 2 + bootstrap_service/settings.py | 1 + bootstrap_service/urls.py | 1 + 13 files changed, 188 insertions(+) create mode 100644 apps/organization_monitoring/__init__.py create mode 100644 apps/organization_monitoring/apps.py create mode 100644 apps/organization_monitoring/constants.py create mode 100644 apps/organization_monitoring/migrations/0001_initial.py create mode 100644 apps/organization_monitoring/migrations/__init__.py create mode 100644 apps/organization_monitoring/models.py create mode 100644 apps/organization_monitoring/serializers.py create mode 100644 apps/organization_monitoring/services.py create mode 100644 apps/organization_monitoring/urls.py create mode 100644 apps/organization_monitoring/views.py diff --git a/apps/organization_monitoring/__init__.py b/apps/organization_monitoring/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/organization_monitoring/apps.py b/apps/organization_monitoring/apps.py new file mode 100644 index 0000000..fd72581 --- /dev/null +++ b/apps/organization_monitoring/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MonitoringConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "apps.organization_monitoring" diff --git a/apps/organization_monitoring/constants.py b/apps/organization_monitoring/constants.py new file mode 100644 index 0000000..6f64980 --- /dev/null +++ b/apps/organization_monitoring/constants.py @@ -0,0 +1,5 @@ +from django.db import models + + +class MonitoringType(models.TextChoices): + WATER_LEVEL = "water_level" diff --git a/apps/organization_monitoring/migrations/0001_initial.py b/apps/organization_monitoring/migrations/0001_initial.py new file mode 100644 index 0000000..09f169d --- /dev/null +++ b/apps/organization_monitoring/migrations/0001_initial.py @@ -0,0 +1,55 @@ +import uuid + +from django.db import migrations, models + +from apps.organization_monitoring.constants import MonitoringType + + +class Migration(migrations.Migration): + initial = True + dependencies = [ + ("organization", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="OrganizationMonitoring", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ("cell_size", models.FloatField(default=50.0)), + ( + "type", + models.CharField(default=MonitoringType.WATER_LEVEL, max_length=50), + ), + ("thresholds", models.JSONField(blank=True, default=dict)), + ("colors", models.JSONField(blank=True, default=dict)), + ("display_settings", models.JSONField(blank=True, default=dict)), + ( + "organization", + models.ForeignKey( + on_delete=models.deletion.CASCADE, + related_name="monitoring_settings", + to="organization.Organization", + ), + ), + ], + options={"db_table": "organization_monitoring"}, + ), + migrations.AddConstraint( + model_name="organizationmonitoring", + constraint=models.UniqueConstraint( + fields=["organization", "type"], name="unique_monitoring_type_per_org" + ), + ), + ] diff --git a/apps/organization_monitoring/migrations/__init__.py b/apps/organization_monitoring/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/organization_monitoring/models.py b/apps/organization_monitoring/models.py new file mode 100644 index 0000000..d2978b0 --- /dev/null +++ b/apps/organization_monitoring/models.py @@ -0,0 +1,31 @@ +from common.models.base_model import BaseModel +from django.db import models + +from apps.organization.models import Organization +from apps.organization_monitoring.constants import MonitoringType + + +class OrganizationMonitoring(BaseModel): + organization = models.ForeignKey( + Organization, + on_delete=models.CASCADE, + related_name="monitoring_settings", + ) + cell_size = models.FloatField(default=50.0) + type = models.CharField( + max_length=50, + default=MonitoringType.WATER_LEVEL, + choices=MonitoringType.choices, + ) + thresholds = models.JSONField(default=dict, blank=True) + colors = models.JSONField(default=dict, blank=True) + display_settings = models.JSONField(default=dict, blank=True) + + class Meta: + db_table = "organization_monitoring" + constraints = [ + models.UniqueConstraint( + fields=["organization", "type"], + name="unique_monitoring_type_per_org", + ) + ] diff --git a/apps/organization_monitoring/serializers.py b/apps/organization_monitoring/serializers.py new file mode 100644 index 0000000..d08948a --- /dev/null +++ b/apps/organization_monitoring/serializers.py @@ -0,0 +1,23 @@ +from rest_framework import serializers + +from apps.organization_monitoring.models import OrganizationMonitoring + + +class OrganizationMonitoringSerializer(serializers.ModelSerializer): + class Meta: + model = OrganizationMonitoring + fields = [ + "id", + "cell_size", + "type", + "thresholds", + "colors", + "display_settings", + "created_at", + "updated_at", + ] + extra_kwargs = { + "id": {"read_only": True}, + "created_at": {"read_only": True}, + "updated_at": {"read_only": True}, + } diff --git a/apps/organization_monitoring/services.py b/apps/organization_monitoring/services.py new file mode 100644 index 0000000..3ce5c00 --- /dev/null +++ b/apps/organization_monitoring/services.py @@ -0,0 +1,23 @@ +from apps.organization.models import Organization +from apps.organization_monitoring.constants import MonitoringType +from apps.organization_monitoring.models import OrganizationMonitoring + +DEFAULT_MONITORING_VALUES = { + "cell_size": 50.0, + "thresholds": {"safe": 0.1, "caution": 0.3, "warning": 0.6}, + "colors": { + "safe": "#08B94E", + "caution": "#EBA622", + "warning": "#FD6665", + "danger": "#E5372B", + }, + "display_settings": {"device_icons": True, "water_column": True, "coverage": True}, +} + + +def create_default_organization_monitoring(organization: Organization): + return OrganizationMonitoring.objects.get_or_create( + organization=organization, + type=MonitoringType.WATER_LEVEL, + defaults=DEFAULT_MONITORING_VALUES, + ) diff --git a/apps/organization_monitoring/urls.py b/apps/organization_monitoring/urls.py new file mode 100644 index 0000000..54f41fb --- /dev/null +++ b/apps/organization_monitoring/urls.py @@ -0,0 +1,21 @@ +from django.urls import path + +from apps.organization_monitoring.views import ( + OrganizationMonitoringDetailView, + OrganizationMonitoringListCreateView, +) + +app_name = "organization_monitoring" + +urlpatterns = [ + path( + "organizations/monitoring", + OrganizationMonitoringListCreateView.as_view(), + name="organization-monitoring-list", + ), + path( + "organizations/monitoring/", + OrganizationMonitoringDetailView.as_view(), + name="organization-monitoring-detail", + ), +] diff --git a/apps/organization_monitoring/views.py b/apps/organization_monitoring/views.py new file mode 100644 index 0000000..ce7be01 --- /dev/null +++ b/apps/organization_monitoring/views.py @@ -0,0 +1,20 @@ +from apps.organization_monitoring.models import OrganizationMonitoring +from apps.organization_monitoring.serializers import OrganizationMonitoringSerializer +from utils.views import ( + OrganizationListCreateAPIView, + OrganizationRetrieveUpdateDestroyAPIView, +) + + +class OrganizationMonitoringListCreateView(OrganizationListCreateAPIView): + model = OrganizationMonitoring + serializer_class = OrganizationMonitoringSerializer + queryset = OrganizationMonitoring.objects.select_related("organization") + organization_field = "organization" + + +class OrganizationMonitoringDetailView(OrganizationRetrieveUpdateDestroyAPIView): + model = OrganizationMonitoring + serializer_class = OrganizationMonitoringSerializer + queryset = OrganizationMonitoring.objects.select_related("organization") + organization_field = "organization" diff --git a/bootstrap_service/management/commands/init_organization.py b/bootstrap_service/management/commands/init_organization.py index f77945b..31a079f 100644 --- a/bootstrap_service/management/commands/init_organization.py +++ b/bootstrap_service/management/commands/init_organization.py @@ -28,6 +28,7 @@ from apps.custom_email.service import create_default_organization_email from apps.custom_page.service import create_default_pages from apps.organization.models import Organization +from apps.organization_monitoring.services import create_default_organization_monitoring from apps.organization_roles.constants import OrganizationRoleType from apps.organization_roles.models import OrganizationRoleUser from apps.organization_roles.services import ( @@ -125,6 +126,7 @@ def _create_organization_with_roles(self, org_id, org_name, org_slug, result): create_default_pages(organization) create_default_organization_email(organization) create_default_organization_setting(organization) + create_default_organization_monitoring(organization) create_default_subscription(organization) self.stdout.write(self.style.SUCCESS("Created default policies")) diff --git a/bootstrap_service/settings.py b/bootstrap_service/settings.py index a3c36b9..f279c5e 100644 --- a/bootstrap_service/settings.py +++ b/bootstrap_service/settings.py @@ -64,6 +64,7 @@ "apps.custom_page", "apps.custom_email", "apps.organization_setting", + "apps.organization_monitoring", "apps.billing", "apps.contact_sales", "apps.organization_roles", diff --git a/bootstrap_service/urls.py b/bootstrap_service/urls.py index 2609e21..df759e0 100644 --- a/bootstrap_service/urls.py +++ b/bootstrap_service/urls.py @@ -63,6 +63,7 @@ def health_check(_): path("api/", include("apps.custom_page.urls")), path("api/", include("apps.custom_email.urls")), path("api/", include("apps.organization_setting.urls")), + path("api/", include("apps.organization_monitoring.urls")), path("api/", include("apps.billing.urls")), path("api/", include("apps.contact_sales.urls")), path("api/", include("apps.organization.urls")),