From 4d723f57c3b3913c6a8b344005b395ee08bcaa10 Mon Sep 17 00:00:00 2001
From: Helge Jung <hej@c3pb.de>
Date: Thu, 26 Dec 2024 16:43:02 +0100
Subject: [PATCH] Room: new location_state and location_data fields (like
 Assembly)

---
 src/core/admin.py                         |  8 +++-
 src/core/locale/de/LC_MESSAGES/django.po  | 12 ++++++
 src/core/locale/en/LC_MESSAGES/django.po  | 12 ++++++
 src/core/migrations/0174_room_location.py | 29 +++++++++++++++
 src/core/models/rooms.py                  | 45 +++++++++++++++++++++++
 5 files changed, 104 insertions(+), 2 deletions(-)
 create mode 100644 src/core/migrations/0174_room_location.py

diff --git a/src/core/admin.py b/src/core/admin.py
index c00e2f344..6f45d562b 100644
--- a/src/core/admin.py
+++ b/src/core/admin.py
@@ -770,9 +770,9 @@ class RoomShareAdmin(admin.ModelAdmin):
 
 
 class RoomAdmin(admin.ModelAdmin):
-    list_display = ['conference', 'assembly', 'name', 'room_type', 'blocked', 'official_room_order', 'id']
+    list_display = ['conference', 'assembly', 'name', 'room_type', 'location_state', 'blocked', 'official_room_order', 'id']
     list_display_links = ['name']
-    list_filter = ['conference', 'room_type', 'backend_status', 'blocked', 'is_official', 'is_public_fahrplan']
+    list_filter = ['conference', 'room_type', 'backend_status', 'location_state', 'blocked', 'is_official', 'is_public_fahrplan']
     save_as = True
     search_fields = ['assembly__name', 'name', 'slug', 'id']
     inlines = [RoomLinkInline, RoomShareInline, TagsInline]
@@ -792,6 +792,10 @@ class RoomAdmin(admin.ModelAdmin):
             'Data',
             {'fields': ['name', 'room_type', 'capacity', 'occupants', 'description']},
         ),
+        (
+            'Location',
+            {'fields': ['location_state', 'location_data']},
+        ),
         (
             'Backend',
             {'fields': ['backend_link', 'backend_link_branch', 'backend_status', 'backend_data', 'director_data']},
diff --git a/src/core/locale/de/LC_MESSAGES/django.po b/src/core/locale/de/LC_MESSAGES/django.po
index 54605f17f..5f859b6db 100644
--- a/src/core/locale/de/LC_MESSAGES/django.po
+++ b/src/core/locale/de/LC_MESSAGES/django.po
@@ -1763,6 +1763,18 @@ msgstr "Art des Raums"
 msgid "Room__type"
 msgstr "Typ"
 
+msgid "Room__location_state__help"
+msgstr "Qualität der ausgewählten Position auf der Karte"
+
+msgid "Room__location_state"
+msgstr "Position (Karte) Status"
+
+msgid "Room__location_floor__help"
+msgstr "Ebene, auf der sich der Raum befindet"
+
+msgid "Room__location_floor"
+msgstr "Ebene"
+
 msgid "Room__backend_link__help"
 msgstr "Referenz zu interner Quelle"
 
diff --git a/src/core/locale/en/LC_MESSAGES/django.po b/src/core/locale/en/LC_MESSAGES/django.po
index d5c6b5e3d..a2be9e62b 100644
--- a/src/core/locale/en/LC_MESSAGES/django.po
+++ b/src/core/locale/en/LC_MESSAGES/django.po
@@ -1763,6 +1763,18 @@ msgstr "type of room"
 msgid "Room__type"
 msgstr "type"
 
+msgid "Room__location_state__help"
+msgstr "quality of the selected position, how to handle it?"
+
+msgid "Room__location_state"
+msgstr "location state"
+
+msgid "Room__location_floor__help"
+msgstr "floor, on which this room is placed"
+
+msgid "Room__location_floor"
+msgstr "floor"
+
 msgid "Room__backend_link__help"
 msgstr "reference to internal (backend) source"
 
diff --git a/src/core/migrations/0174_room_location.py b/src/core/migrations/0174_room_location.py
new file mode 100644
index 000000000..6b96922c1
--- /dev/null
+++ b/src/core/migrations/0174_room_location.py
@@ -0,0 +1,29 @@
+# Generated by Django 5.1.3 on 2024-12-26 13:10
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0173_lock_created_at'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='room',
+            name='location_data',
+            field=models.JSONField(blank=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='room',
+            name='location_floor',
+            field=models.ForeignKey(blank=True, help_text='Room__location_floor__help', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='rooms', to='core.mapfloor', verbose_name='Room__location_floor'),
+        ),
+        migrations.AddField(
+            model_name='room',
+            name='location_state',
+            field=models.CharField(choices=[('none', 'Assembly__location_state-none'), ('draft', 'Assembly__location_state-draft'), ('rough', 'Assembly__location_state-rough'), ('preview', 'Assembly__location_state-preview'), ('final', 'Assembly__location_state-final')], default='none', help_text='Room__location_state__help', max_length=20, verbose_name='Room__location_state'),
+        ),
+    ]
diff --git a/src/core/models/rooms.py b/src/core/models/rooms.py
index cef75f46a..a0fdf8146 100644
--- a/src/core/models/rooms.py
+++ b/src/core/models/rooms.py
@@ -1,3 +1,4 @@
+import json
 import uuid
 from datetime import datetime
 from pathlib import Path
@@ -153,6 +154,27 @@ class Room(BackendMixin, models.Model):
     room_type = models.CharField(max_length=20, choices=RoomType.choices, help_text=_('Room__type__help'), verbose_name=_('Room__type'))
     """Style of the room."""
 
+    location_state = models.CharField(
+        max_length=20,
+        choices=Assembly.LocationState.choices,
+        default=Assembly.LocationState.NONE,
+        help_text=_('Room__location_state__help'),
+        verbose_name=_('Room__location_state'),
+    )
+    location_floor = models.ForeignKey(
+        'MapFloor',
+        blank=True,
+        null=True,
+        related_name='rooms',
+        on_delete=models.PROTECT,
+        help_text=_('Room__location_floor__help'),
+        verbose_name=_('Room__location_floor'),
+    )
+    location_data = models.JSONField(
+        blank=True,
+        null=True,
+    )
+
     backend_link = models.URLField(blank=True, null=True, help_text=_('Room__backend_link__help'), verbose_name=_('Room__backend_link'))
     """Reference to integration/source system. For e.g. WorkAdventure this is the collection JSON URL."""
 
@@ -301,6 +323,29 @@ class Room(BackendMixin, models.Model):
     def generate_slug(self):
         self.slug = self.__create_slug()
 
+    def get_location_floor_index(self) -> int | None:
+        return self.location_floor.index if self.location_floor else None
+
+    def get_location_point_xy(self) -> tuple[int, int] | None:
+        if self.location_data is None:
+            return None
+        if p := self.location_data.get('point'):
+            return p[0], p[1]
+        return None
+
+    def get_location_point_as_json(self) -> str:
+        return json.dumps(self.get_location_point_xy() or '')
+
+    def get_location_boundaries_xy(self) -> list[list[tuple[int, int]]] | None:
+        if self.location_data is None:
+            return None
+        if b := self.location_data.get('boundaries'):
+            return b
+        return None
+
+    def get_location_boundaries_as_json(self) -> str:
+        return json.dumps(self.get_location_boundaries_xy() or '')
+
     def clean(self):
         if self.room_type == self.RoomType.PROJECT:
             raise ValidationError(_('Room__type_project_not_allowed'))
-- 
GitLab