diff --git a/CHANGES.md b/CHANGES.md index 6606b8b..5e35b8a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,8 @@ - Bugfix: Add correction reason to GMW-InsertRequests +- Add Events Endpoint +- Add Events Import ## 0.72 (2024-12-17) diff --git a/api/bro_import/object_import.py b/api/bro_import/object_import.py index 4e5073c..8ce1b89 100644 --- a/api/bro_import/object_import.py +++ b/api/bro_import/object_import.py @@ -11,7 +11,7 @@ from gar.models import GAR from gld.models import GLD from gmn.models import GMN, Measuringpoint -from gmw.models import GMW, MonitoringTube +from gmw.models import GMW, Event, MonitoringTube logger = logging.getLogger(__name__) @@ -186,6 +186,7 @@ def _save_data_to_database(self, json_data: dict[str, Any]) -> None: self._save_gmw_data(gmw_data) self._save_monitoringtubes_data(monitoringtubes_data, event_data) + self._save_events_data(event_data) def _split_json_data( self, dispatch_document_data: dict[str, Any] @@ -385,6 +386,83 @@ def _save_monitoringtubes_data( }, ) + def _get_well_data(self, intermediate_event: list[dict[str, any]]) -> dict: + event_data = intermediate_event.get("eventData", {}).get("wellData", {}) + if not event_data: + return {} + + well_data = {} + for key in event_data.keys(): + if isinstance(event_data[key], str): + well_data[key] = event_data[key] + else: + well_data[key] = event_data[key].get("#text", None) + + return well_data + + def _get_tube_data(self, intermediate_event: list[dict[str, any]]) -> list[dict]: + event_data = intermediate_event.get("eventData", {}).get("tubeData", {}) + if not event_data: + return {} + + tubes_data = [] + if isinstance(event_data, list): + for tube in event_data: + tube_data = {} + for key in tube.keys(): + data = tube[key] + logger.info(tube) + logger.info(data) + if isinstance(tube[key], (str | int)): + tube_data[key] = tube[key] + else: + tube_data[key] = tube[key].get("#text", None) + tubes_data.append(tube_data) + + return tube_data + + tube_data = {} + for key in event_data.keys(): + data = event_data[key] + if isinstance(event_data[key], (str | int)): + tube_data[key] = event_data[key] + else: + tube_data[key] = event_data[key].get("#text", None) + tubes_data.append(tube_data) + return tubes_data + + def _save_events_data(self, event_data: list[dict[str, any]]): + intermediate_events = event_data.get("intermediateEvent", []) + if isinstance(intermediate_events, dict): + intermediate_events = [intermediate_events] + + for intermediate_event in intermediate_events: + name = intermediate_event.get("eventName", {}).get("#text") + event_date = intermediate_event.get("eventDate", {}).get( + "brocom:date" + ) or intermediate_event.get("eventDate", {}).get("brocom:year") + + # If event_date is a year, convert it to a date + if event_date: + event_date = ( + event_date + "-01-01" if len(event_date) == 4 else event_date + ) + else: + continue + + sourcedocument_data = self._get_well_data(intermediate_event) + sourcedocument_data["monitoringTubes"] = self._get_tube_data( + intermediate_event + ) + + Event.objects.update_or_create( + gmw=self.gmw_obj, + data_owner=self.data_owner, + event_name=name, + event_date=event_date, + defaults={"sourcedocument_data": sourcedocument_data}, + ) + def _lookup_most_recent_top_position( self, monitoringtube: list[dict[str, any]], event_data: list[dict[str, any]] ): diff --git a/api/views.py b/api/views.py index 7ec9666..cb64fb8 100644 --- a/api/views.py +++ b/api/views.py @@ -69,6 +69,7 @@ def get(self, request: HttpRequest, format: Any = None) -> HttpResponse: "monitoringtubes": reverse( "api:gmw:monitoringtube-list", request=request, format=format ), + "events": reverse("api:gmw:event-list", request=request, format=format), "gars": reverse("api:gar:gar-list", request=request, format=format), "glds": reverse("api:gld:gld-list", request=request, format=format), "observations": reverse( diff --git a/brostar_api/settings.py b/brostar_api/settings.py index 8b0c309..597b692 100644 --- a/brostar_api/settings.py +++ b/brostar_api/settings.py @@ -12,9 +12,13 @@ "SECRET_KEY", default="django-insecure-r4_51z=)9re0wxnj(fwanhzi($42k#usdr37z!o2c-a04*4p06", ) -NENS_AUTH_ISSUER = os.getenv("NENS_AUTH_ISSUER") -NENS_AUTH_CLIENT_ID = os.getenv("NENS_AUTH_CLIENT_ID") -NENS_AUTH_CLIENT_SECRET = os.getenv("NENS_AUTH_CLIENT_SECRET") +# NENS_AUTH_ISSUER = os.getenv("NENS_AUTH_ISSUER") +# NENS_AUTH_CLIENT_ID = os.getenv("NENS_AUTH_CLIENT_ID") +# NENS_AUTH_CLIENT_SECRET = os.getenv("NENS_AUTH_CLIENT_SECRET") +NENS_AUTH_ISSUER = "https://cognito-idp.eu-west-1.amazonaws.com/eu-west-1_vPwXOnNbi" +NENS_AUTH_CLIENT_ID = "71uv1605es7ksjc83sabon95u3" +NENS_AUTH_CLIENT_SECRET = "uuahp4p1o8sgh89r9mgdp5314skcngeru5jljjf3qh3ipf7poe8" + _debug_env = os.getenv("DEBUG", default="true") DATABASE_HOST = os.getenv("DATABASE_HOST", "db") DATABASE_USER = os.getenv("DATABASE_USER", "brostar") diff --git a/gmw/admin.py b/gmw/admin.py index 3b39f61..b069830 100644 --- a/gmw/admin.py +++ b/gmw/admin.py @@ -4,3 +4,4 @@ admin.site.register(gmw_models.GMW) admin.site.register(gmw_models.MonitoringTube) +admin.site.register(gmw_models.Event) diff --git a/gmw/filters.py b/gmw/filters.py index b974b93..5e9e94a 100644 --- a/gmw/filters.py +++ b/gmw/filters.py @@ -2,7 +2,7 @@ from gmn.models import Measuringpoint -from .models import MonitoringTube +from .models import Event, MonitoringTube class MonitoringTubeFilter(filters.FilterSet): @@ -20,3 +20,14 @@ def filter_by_gmn_bro_id(self, queryset, name, value) -> any: def filter_by_gmw_bro_id(self, queryset, name, value) -> any: return queryset.filter(gmw__bro_id=value) + + +class EventFilter(filters.FilterSet): + gmw_bro_id = filters.CharFilter(method="filter_by_gmw_bro_id") + + class Meta: + model = Event + exclude = ["metadata", "sourcedocument_data"] + + def filter_by_gmw_bro_id(self, queryset, name, value) -> any: + return queryset.filter(gmw__bro_id=value) diff --git a/gmw/migrations/0016_event.py b/gmw/migrations/0016_event.py new file mode 100644 index 0000000..c228505 --- /dev/null +++ b/gmw/migrations/0016_event.py @@ -0,0 +1,52 @@ +# Generated by Django 5.0.4 on 2024-12-05 18:51 + +import uuid + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0050_alter_uploadtask_registration_type"), + ("gmw", "0015_gmw_horizontal_positioning_method_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="Event", + fields=[ + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ("created", models.DateTimeField(auto_now_add=True)), + ("updated", models.DateTimeField(auto_now=True)), + ("event_name", models.CharField(max_length=40)), + ("event_date", models.DateField()), + ("metadata", models.JSONField(default=dict, verbose_name="Metadata")), + ( + "sourcedocument_data", + models.JSONField(default=dict, verbose_name="Sourcedocument data"), + ), + ( + "data_owner", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="api.organisation", + ), + ), + ( + "gmw", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="gmw.gmw" + ), + ), + ], + ), + ] diff --git a/gmw/models.py b/gmw/models.py index 3133d69..a081f35 100644 --- a/gmw/models.py +++ b/gmw/models.py @@ -86,3 +86,22 @@ class MonitoringTube(models.Model): def __str__(self) -> str: return f"{self.gmw}-{self.tube_number}" + + +class Event(models.Model): + """A event is a change after a period of time to a GMW or its monitoring tube(s).""" + + uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + data_owner = models.ForeignKey( + "api.Organisation", + on_delete=models.CASCADE, + ) + gmw = models.ForeignKey(GMW, on_delete=models.CASCADE) + event_name = models.CharField( + max_length=40, + ) + event_date = models.DateField() + metadata = JSONField("Metadata", default=dict, blank=False) + sourcedocument_data = JSONField("Sourcedocument data", default=dict, blank=False) diff --git a/gmw/serializers.py b/gmw/serializers.py index 47bf47c..e42efab 100644 --- a/gmw/serializers.py +++ b/gmw/serializers.py @@ -68,3 +68,27 @@ def get_linked_gmns( except ObjectDoesNotExist: return None + + +class EventSerializer(UrlFieldMixin, serializers.ModelSerializer): + gmw_well_code = serializers.SerializerMethodField() + gmw_bro_id = serializers.SerializerMethodField() + + class Meta: + model = gmw_models.Event + fields = "__all__" + + def __init__(self: Any, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + def get_gmw_well_code(self, obj: gmw_models.MonitoringTube) -> str | None: + try: + return gmw_models.GMW.objects.get(uuid=obj.gmw.uuid).well_code + except ObjectDoesNotExist: + return None + + def get_gmw_bro_id(self, obj: gmw_models.MonitoringTube) -> str | None: + try: + return gmw_models.GMW.objects.get(uuid=obj.gmw.uuid).bro_id + except ObjectDoesNotExist: + return None diff --git a/gmw/urls.py b/gmw/urls.py index a04d325..c01272d 100644 --- a/gmw/urls.py +++ b/gmw/urls.py @@ -17,4 +17,14 @@ views.MonitoringTubeDetailView.as_view(), name="monitoringtube-detail", ), + path( + "events/", + views.EventListView.as_view(), + name="event-list", + ), + path( + "events//", + views.EventDetailView.as_view(), + name="event-detail", + ), ] diff --git a/gmw/views.py b/gmw/views.py index 2e67623..a4d1ce0 100644 --- a/gmw/views.py +++ b/gmw/views.py @@ -33,3 +33,17 @@ class MonitoringTubeDetailView(mixins.UserOrganizationMixin, generics.RetrieveAP queryset = gmw_models.MonitoringTube.objects.all() serializer_class = serializers.MonitoringTubeSerializer lookup_field = "uuid" + + +class EventListView(mixins.UserOrganizationMixin, generics.ListAPIView): + serializer_class = serializers.EventSerializer + queryset = gmw_models.Event.objects.all().order_by("-created") + + filter_backends = [DjangoFilterBackend] + filterset_class = filters.EventFilter + + +class EventDetailView(mixins.UserOrganizationMixin, generics.RetrieveAPIView): + queryset = gmw_models.Event.objects.all() + serializer_class = serializers.EventSerializer + lookup_field = "uuid"