From 2fa741318293181ebd0dec0d4736d9901d6e6de0 Mon Sep 17 00:00:00 2001
From: Helge Jung <hej@c3pb.de>
Date: Sat, 4 Nov 2023 21:29:18 +0100
Subject: [PATCH] integrate suggestions from MR !734 review

most importantly, rename "layer" to "floor"
---
 src/api/views/maps.py                         |  4 +-
 .../locale/de/LC_MESSAGES/django.po           |  8 ++--
 .../locale/en/LC_MESSAGES/django.po           |  8 ++--
 ...ap_layer_form.html => map_floor_form.html} |  6 ++-
 ...ap_layer_list.html => map_floor_list.html} | 14 +++----
 .../templates/backoffice/map_poi_form.html    |  4 +-
 src/backoffice/urls.py                        |  6 +--
 src/backoffice/views/map.py                   | 42 +++++++++----------
 src/core/admin.py                             | 13 +++---
 src/core/locale/de/LC_MESSAGES/django.po      | 26 ++++++------
 src/core/locale/en/LC_MESSAGES/django.po      | 40 +++++++++---------
 src/core/migrations/0118_map.py               | 38 ++++++++---------
 src/core/models/__init__.py                   |  4 +-
 src/core/models/assemblies.py                 | 14 +++----
 src/core/models/map.py                        | 35 +++++++++-------
 src/core/translation.py                       |  6 +--
 16 files changed, 138 insertions(+), 130 deletions(-)
 rename src/backoffice/templates/backoffice/{map_layer_form.html => map_floor_form.html} (86%)
 rename src/backoffice/templates/backoffice/{map_layer_list.html => map_floor_list.html} (85%)

diff --git a/src/api/views/maps.py b/src/api/views/maps.py
index 2129db883..3aa7ab070 100644
--- a/src/api/views/maps.py
+++ b/src/api/views/maps.py
@@ -41,7 +41,7 @@ class PoiExportView(ConferenceSlugMixin, APIView):
                 'id': str(poi.id),
                 'geometry': get_field_geojson(poi.location_point, srid=srid, ct_cache=ct_cache),
                 'properties': {
-                    'layer': poi.get_location_layer_index(),
+                    'floor': poi.get_location_floor_index(),
                     'type': 'poi',
                     'name': poi.name,
                     'official': poi.is_official,
@@ -94,7 +94,7 @@ class AssembliesExportView(ConferenceSlugMixin, APIView, metaclass=abc.ABCMeta):
                 'id': assembly.slug,
                 'geometry': get_field_geojson(geometry, srid=srid, ct_cache=ct_cache),
                 'properties': {
-                    'layer': assembly.get_location_layer_index(),
+                    'floor': assembly.get_location_floor_index(),
                     'type': 'assembly',
                     'name': assembly.name,
                     'official': assembly.is_official,
diff --git a/src/backoffice/locale/de/LC_MESSAGES/django.po b/src/backoffice/locale/de/LC_MESSAGES/django.po
index 3050e9efa..58139e8d8 100644
--- a/src/backoffice/locale/de/LC_MESSAGES/django.po
+++ b/src/backoffice/locale/de/LC_MESSAGES/django.po
@@ -823,19 +823,19 @@ msgid "registration_password_reset_link"
 msgstr "Passwort vergessen?"
 
 # use translation from core
-msgid "MapLayer"
+msgid "MapFloor"
 msgstr ""
 
 # use translation from core
-msgid "MapLayers"
+msgid "MapFloors"
 msgstr ""
 
 # use translation from core
-msgid "MapLayer__index"
+msgid "MapFloor__index"
 msgstr ""
 
 # use translation from core
-msgid "MapLayer__name"
+msgid "MapFloor__name"
 msgstr ""
 
 # use translation from core
diff --git a/src/backoffice/locale/en/LC_MESSAGES/django.po b/src/backoffice/locale/en/LC_MESSAGES/django.po
index 4da517ef1..639c44b5a 100644
--- a/src/backoffice/locale/en/LC_MESSAGES/django.po
+++ b/src/backoffice/locale/en/LC_MESSAGES/django.po
@@ -822,19 +822,19 @@ msgid "registration_password_reset_link"
 msgstr "Forgot password?"
 
 # use translation from core
-msgid "MapLayer"
+msgid "MapFloor"
 msgstr ""
 
 # use translation from core
-msgid "MapLayers"
+msgid "MapFloors"
 msgstr ""
 
 # use translation from core
-msgid "MapLayer__index"
+msgid "MapFloor__index"
 msgstr ""
 
 # use translation from core
-msgid "MapLayer__name"
+msgid "MapFloor__name"
 msgstr ""
 
 # use translation from core
diff --git a/src/backoffice/templates/backoffice/map_layer_form.html b/src/backoffice/templates/backoffice/map_floor_form.html
similarity index 86%
rename from src/backoffice/templates/backoffice/map_layer_form.html
rename to src/backoffice/templates/backoffice/map_floor_form.html
index c84d6aa07..34975ed47 100644
--- a/src/backoffice/templates/backoffice/map_layer_form.html
+++ b/src/backoffice/templates/backoffice/map_floor_form.html
@@ -14,12 +14,14 @@
       <div class="card-header bg-default">
         {% if object.id %}
             <span class="text-muted float-end text-end me-2" style="font-size: 50%;">ID: <strong>{{ object.id }}</strong></span>
-        {% trans 'MapLayer' %} "{{ object.name }}"
+        {% trans 'MapFloor' %} "{{ object.name }}"
         {% else %}
-            {% trans 'MapLayer' %} <i class="bi bi-plus-circle"></i>
+            {% trans 'MapFloor' %} <i class="bi bi-plus-circle"></i>
         {% endif %}
       </div>
       <div class="card-body">
+          {% bootstrap_form_errors form layout='inline' %}
+
           {% bootstrap_field form.index %}
           <div class="row">
               <div class="col-md-6">
diff --git a/src/backoffice/templates/backoffice/map_layer_list.html b/src/backoffice/templates/backoffice/map_floor_list.html
similarity index 85%
rename from src/backoffice/templates/backoffice/map_layer_list.html
rename to src/backoffice/templates/backoffice/map_floor_list.html
index d7e98e79c..431133bbd 100644
--- a/src/backoffice/templates/backoffice/map_layer_list.html
+++ b/src/backoffice/templates/backoffice/map_floor_list.html
@@ -46,23 +46,23 @@
 
 <div class="card">
   <div class="card-header">
-    <a href="{% url 'backoffice:map-layer-create' %}" class="float-end btn btn-sm btn-primary"><i class="bi bi-plus-circle"></i> {% trans 'add' %}</a>
-      {% trans 'MapLayers' %}
+    <a href="{% url 'backoffice:map-floor-create' %}" class="float-end btn btn-sm btn-primary"><i class="bi bi-plus-circle"></i> {% trans 'add' %}</a>
+      {% trans 'MapFloors' %}
   </div>
   <div class="card-body">
 
     <table class="table table-sm" id="pois">
       <thead>
         <tr>
-          <th>{% trans "MapLayer__index" %}</th>
-          <th>{% trans "MapLayer__name" %}</th>
+          <th>{% trans "MapFloor__index" %}</th>
+          <th>{% trans "MapFloor__name" %}</th>
         </tr>
       </thead>
       <tbody>
-  {% for layer in object_list %}
+  {% for floor in object_list %}
         <tr>
-          <td>{{ layer.index }}</td>
-          <td><a href="{% url 'backoffice:map-layer-edit' pk=layer.pk %}">{{ layer.name }}</a></td>
+          <td>{{ floor.index }}</td>
+          <td><a href="{% url 'backoffice:map-floor-edit' pk=floor.pk %}">{{ floor.name }}</a></td>
         </tr>
   {% endfor %}
       </tbody>
diff --git a/src/backoffice/templates/backoffice/map_poi_form.html b/src/backoffice/templates/backoffice/map_poi_form.html
index 4c71ac78d..36d099d11 100644
--- a/src/backoffice/templates/backoffice/map_poi_form.html
+++ b/src/backoffice/templates/backoffice/map_poi_form.html
@@ -20,6 +20,8 @@
         {% endif %}
       </div>
       <div class="card-body">
+          {% bootstrap_form_errors form layout='inline' %}
+
           {% bootstrap_field form.visible %}
           {% bootstrap_field form.is_official %}
           <div class="row">
@@ -39,7 +41,7 @@
               </div>
           </div>
 
-          {% bootstrap_field form.location_layer %}
+          {% bootstrap_field form.location_floor %}
           {% include "core/map.html" with map_config=conference.map_config.backoffice poi_id="poi" areas_id="areas" %}
           <input type="hidden" name="location_point" id="poi" value="{{ poi.get_location_point_as_json }}">
 
diff --git a/src/backoffice/urls.py b/src/backoffice/urls.py
index 6ec50ab99..92a28d242 100644
--- a/src/backoffice/urls.py
+++ b/src/backoffice/urls.py
@@ -98,9 +98,9 @@ urlpatterns = [
     path('assembly/<uuid:assembly>/r/<uuid:room>/remove_link', assemblies.RemoveRoomLinkView.as_view(), name='roomlink-remove'),
     path('assembly/<uuid:assembly>/r/<uuid:room>/remove', assemblies.RemoveRoomView.as_view(), name='assembly-remove-room'),
 
-    path('map/layers', map.LayerListView.as_view(), name='map-layer-list'),
-    path('map/layer/new', map.LayerCreateView.as_view(), name='map-layer-create'),
-    path('map/layer/<uuid:pk>', map.LayerUpdateView.as_view(), name='map-layer-edit'),
+    path('map/floors', map.FloorListView.as_view(), name='map-floor-list'),
+    path('map/floor/new', map.FloorCreateView.as_view(), name='map-floor-create'),
+    path('map/floor/<uuid:pk>', map.FloorUpdateView.as_view(), name='map-floor-edit'),
     path('map/pois', map.POIListView.as_view(), name='map-poi-list'),
     path('map/poi/new', map.POICreateView.as_view(), name='map-poi-create'),
     path('map/poi/<uuid:pk>', map.POIUpdateView.as_view(), name='map-poi-edit'),
diff --git a/src/backoffice/views/map.py b/src/backoffice/views/map.py
index 85026ee72..0c1dee708 100644
--- a/src/backoffice/views/map.py
+++ b/src/backoffice/views/map.py
@@ -8,7 +8,7 @@ from django.views.generic import ListView
 from django.views.generic.detail import SingleObjectTemplateResponseMixin
 from django.views.generic.edit import UpdateView, CreateView
 
-from core.models.map import MapPOI, MapLayer
+from core.models.map import MapFloor, MapPOI
 from .mixins import ConferenceMixin, guess_active_sidebar_item
 
 logger = logging.getLogger(__name__)
@@ -22,10 +22,10 @@ class MapAdminMixin(ConferenceMixin):
         ctx = super().get_context_data(*args, **kwargs)
         ctx['active_page'] = 'map'
 
-        layers = [{
-            'caption': f'{layer["name"]} ({layer["index"]})',
-            'link': reverse('backoffice:map-layer-edit', kwargs={'pk': layer["pk"]}),
-        } for layer in MapLayer.objects.filter(conference=self.conference).order_by('index').values('pk', 'name', 'index')]
+        floors = [{
+            'caption': f'{floor["name"]} ({floor["index"]})',
+            'link': reverse('backoffice:map-floor-edit', kwargs={'pk': floor["pk"]}),
+        } for floor in MapFloor.objects.filter(conference=self.conference).order_by('index').values('pk', 'name', 'index')]
 
         pois = []
         poi_count = 0
@@ -34,10 +34,10 @@ class MapAdminMixin(ConferenceMixin):
             # 'title_link': reverse(self.base_view_name),
             'items': [
                 {
-                    'caption': _('MapLayers'),
-                    'children': layers,
-                    'count': len(layers),
-                    'add_link': reverse('backoffice:map-layer-create'),
+                    'caption': _('MapFloors'),
+                    'children': floors,
+                    'count': len(floors),
+                    'add_link': reverse('backoffice:map-floor-create'),
                 },
                 {
                     'caption': _('MapPOIs'),
@@ -65,22 +65,22 @@ class MapAdminMixin(ConferenceMixin):
         return ctx
 
 
-class LayerListView(MapAdminMixin, ListView):
-    template_name = 'backoffice/map_layer_list.html'
+class FloorListView(MapAdminMixin, ListView):
+    template_name = 'backoffice/map_floor_list.html'
 
-    model = MapLayer
+    model = MapFloor
 
     def get_queryset(self, *args, **kwargs):
-        return MapLayer.objects.filter(conference=self.conference).order_by('index')
+        return MapFloor.objects.filter(conference=self.conference).order_by('index')
 
 
-class LayerFormMixin(MapAdminMixin, SingleObjectTemplateResponseMixin):
+class FloorFormMixin(MapAdminMixin, SingleObjectTemplateResponseMixin):
     fields = ['name_de', 'name_en', 'index']
-    template_name = 'backoffice/map_layer_form.html'
-    model = MapLayer
+    template_name = 'backoffice/map_floor_form.html'
+    model = MapFloor
 
     def get_queryset(self, *args, **kwargs):
-        return MapLayer.objects.filter(conference=self.conference)
+        return MapFloor.objects.filter(conference=self.conference)
 
     def form_valid(self, form):
         messages.success(self.request, _('updated'))
@@ -88,16 +88,16 @@ class LayerFormMixin(MapAdminMixin, SingleObjectTemplateResponseMixin):
         return super().form_valid(form)
 
     def get_success_url(self):
-        return reverse('backoffice:map-poi-edit', kwargs={'pk': self.object.id})
+        return reverse('backoffice:map-floor-edit', kwargs={'pk': self.object.id})
 
 
-class LayerCreateView(LayerFormMixin, CreateView):
+class FloorCreateView(FloorFormMixin, CreateView):
     def form_valid(self, form):
         form.instance.conference = self.conference
         return super().form_valid(form)
 
 
-class LayerUpdateView(LayerFormMixin, UpdateView):
+class FloorUpdateView(FloorFormMixin, UpdateView):
     pass
 
 
@@ -112,7 +112,7 @@ class POIListView(MapAdminMixin, ListView):
 
 class POIFormMixin(MapAdminMixin, SingleObjectTemplateResponseMixin):
     model = MapPOI
-    fields = ['visible', 'is_official', 'name_de', 'name_en', 'description_de', 'description_en', 'location_layer', 'location_point']
+    fields = ['visible', 'is_official', 'name_de', 'name_en', 'description_de', 'description_en', 'location_floor', 'location_point']
     template_name = 'backoffice/map_poi_form.html'
 
     def get_queryset(self, *args, **kwargs):
diff --git a/src/core/admin.py b/src/core/admin.py
index 013499ab2..d61b51ee3 100644
--- a/src/core/admin.py
+++ b/src/core/admin.py
@@ -16,7 +16,7 @@ from .models import \
     PlatformUser, \
     Room, RoomLink, \
     Assembly, AssemblyLink, AssemblyMember, AssemblyLogEntry, \
-    MapLayer, MapPOI, \
+    MapFloor, MapPOI, \
     Badge, BadgeToken, BadgeTokenTimeConstraint, \
     ScheduleSource, ScheduleSourceImport, ScheduleSourceMapping, \
     StaticPage, StaticPageRevision, \
@@ -355,11 +355,12 @@ class AssemblyLogEntryAdmin(admin.ModelAdmin):
     ]
 
 
-class MapLayerAdmin(admin.ModelAdmin):
-    list_display = ['conference', 'index', 'name']
+class MapFloorAdmin(admin.ModelAdmin):
+    list_display = ['index', 'name', 'conference']
     list_display_links = ['name']
     list_filter = ['conference']
     readonly_fields = ['id', 'conference']
+    ordering = ['conference', 'index']
 
     fieldsets = (
         ('Organisation', {
@@ -378,7 +379,7 @@ class MapLayerAdmin(admin.ModelAdmin):
 
 
 class MapPOIAdmin(GISModelAdmin):
-    list_display = ['conference', 'visible', 'name', 'is_official']
+    list_display = ['visible', 'name', 'is_official', 'conference']
     list_display_links = ['name']
     list_filter = ['conference', 'visible', 'is_official']
     readonly_fields = ['id', 'conference']
@@ -394,7 +395,7 @@ class MapPOIAdmin(GISModelAdmin):
                        ('description_de', 'description_en')],
         }),
         ('Location', {
-            'fields': ['location_layer', 'location_point'],
+            'fields': ['location_floor', 'location_point'],
         }),
     )
 
@@ -748,7 +749,7 @@ admin.site.register(Assembly, AssemblyAdmin)
 admin.site.register(AssemblyLogEntry, AssemblyLogEntryAdmin)
 admin.site.register(BadgeToken, BadgeTokenAdmin)
 admin.site.register(Event, EventAdmin)
-admin.site.register(MapLayer, MapLayerAdmin)
+admin.site.register(MapFloor, MapFloorAdmin)
 admin.site.register(MapPOI, MapPOIAdmin)
 admin.site.register(Room, RoomAdmin)
 admin.site.register(ScheduleSource, ScheduleSourceAdmin)
diff --git a/src/core/locale/de/LC_MESSAGES/django.po b/src/core/locale/de/LC_MESSAGES/django.po
index 884aa6a86..5208a4137 100644
--- a/src/core/locale/de/LC_MESSAGES/django.po
+++ b/src/core/locale/de/LC_MESSAGES/django.po
@@ -243,10 +243,10 @@ msgstr "öffentlich sichtbare E-Mail für Kontakt"
 msgid "Assembly__public_contact"
 msgstr "öffentlicher Kontakt"
 
-msgid "Assembly__location_layer__help"
+msgid "Assembly__location_floor__help"
 msgstr "Ebene, auf der sich die Assembly befindet"
 
-msgid "Assembly__location_layer"
+msgid "Assembly__location_floor"
 msgstr "Ebene"
 
 msgid "Assembly__location_point__help"
@@ -952,22 +952,22 @@ msgstr "persönlicher Kommentar"
 msgid "EventParticipant__must_be_conference_member"
 msgstr "Dieser Nutzer ist kein Teilnehmer der Konferenz."
 
-msgid "MapLayer"
+msgid "MapFloor"
 msgstr "Ebene"
 
-msgid "MapLayers"
+msgid "MapFloors"
 msgstr "Ebenen"
 
-msgid "MapLayer__index__help"
-msgstr "numerischer Index des Layer, wird u.a. beim Tile-Zugriff benutzt"
+msgid "MapFloor__index__help"
+msgstr "numerischer Index der Ebene/der Etage, wird u.a. beim Tile-Zugriff benutzt"
 
-msgid "MapLayer__index"
-msgstr "index"
+msgid "MapFloor__index"
+msgstr "Index"
 
-msgid "MapLayer__name__help"
+msgid "MapFloor__name__help"
 msgstr "sprechender Name"
 
-msgid "MapLayer__name"
+msgid "MapFloor__name"
 msgstr "Name"
 
 msgid "MapPOI"
@@ -1000,10 +1000,10 @@ msgstr "Dies ist ein für die Veranstaltung relevanter Point-Of-Interest (z. B.
 msgid "MapPOI__is_official"
 msgstr "offiziell"
 
-msgid "MapPOI__location_layer__help"
+msgid "MapPOI__location_floor__help"
 msgstr "auf welcher Ebene befindet sich der POI"
 
-msgid "MapPOI__location_layer"
+msgid "MapPOI__location_floor"
 msgstr "Ebene"
 
 msgid "MapPOI__location_point__help"
@@ -1012,7 +1012,7 @@ msgstr "tatsächliche Position des POI auf der Karte"
 msgid "MapPOI__location_point"
 msgstr "Position"
 
-msgid "MapPOI__need-both-layer-and-point"
+msgid "MapPOI__need-both-floor-and-point"
 msgstr "Es werden sowohl Ebene als auch Position benötigt, eines alleine ist nicht aussagekräftig."
 
 msgid "DirectMessage__sender__help"
diff --git a/src/core/locale/en/LC_MESSAGES/django.po b/src/core/locale/en/LC_MESSAGES/django.po
index b471a716b..e3c3cd736 100644
--- a/src/core/locale/en/LC_MESSAGES/django.po
+++ b/src/core/locale/en/LC_MESSAGES/django.po
@@ -243,11 +243,11 @@ msgstr "publicly visible email for contact"
 msgid "Assembly__public_contact"
 msgstr "public contact"
 
-msgid "Assembly__location_layer__help"
-msgstr "layer, on which this assembly is placed"
+msgid "Assembly__location_floor__help"
+msgstr "floor, on which this assembly is placed"
 
-msgid "Assembly__location_layer"
-msgstr "layer"
+msgid "Assembly__location_floor"
+msgstr "floor"
 
 msgid "Assembly__location_point__help"
 msgstr "point on the map where this location (assembly) can be found, consider choosing its \"main entrance\" here"
@@ -952,22 +952,22 @@ msgstr "personal comment"
 msgid "EventParticipant__must_be_conference_member"
 msgstr "The participant must be a member of the conference."
 
-msgid "MapLayer"
-msgstr "layer"
+msgid "MapFloor"
+msgstr "floor"
 
-msgid "MapLayers"
-msgstr "layers"
+msgid "MapFloors"
+msgstr "floors"
 
-msgid "MapLayer__index__help"
-msgstr "numerical ordering (or: identifier) of this map layer"
+msgid "MapFloor__index__help"
+msgstr "numerical ordering (or: identifier) of this map floor"
 
-msgid "MapLayer__index"
+msgid "MapFloor__index"
 msgstr "index"
 
-msgid "MapLayer__name__help"
-msgstr "descriptive name of this layer"
+msgid "MapFloor__name__help"
+msgstr "descriptive name of this floor"
 
-msgid "MapLayer__name"
+msgid "MapFloor__name"
 msgstr "name"
 
 msgid "MapPOI"
@@ -1000,11 +1000,11 @@ msgstr "This POI is relevant for the conference (e.g. cash desk, info desk)."
 msgid "MapPOI__is_official"
 msgstr "official"
 
-msgid "MapPOI__location_layer__help"
-msgstr "The layer this POI is on."
+msgid "MapPOI__location_floor__help"
+msgstr "Select the floor this POI is on."
 
-msgid "MapPOI__location_layer"
-msgstr "layer"
+msgid "MapPOI__location_floor"
+msgstr "floor"
 
 msgid "MapPOI__location_point__help"
 msgstr "point on the map where this POI is located"
@@ -1012,8 +1012,8 @@ msgstr "point on the map where this POI is located"
 msgid "MapPOI__location_point"
 msgstr "location"
 
-msgid "MapPOI__need-both-layer-and-point"
-msgstr "Need both layer and point, one is not enough."
+msgid "MapPOI__need-both-floor-and-point"
+msgstr "Need both floor and point, one is not enough."
 
 msgid "DirectMessage__sender__help"
 msgstr "user which sent this message (empty = system)"
diff --git a/src/core/migrations/0118_map.py b/src/core/migrations/0118_map.py
index 550b405fe..ba6e7ed1d 100644
--- a/src/core/migrations/0118_map.py
+++ b/src/core/migrations/0118_map.py
@@ -7,13 +7,13 @@ import django.db.models.deletion
 import uuid
 
 
-def create_default_layer(apps, schema_editor):
-    """ create a default layer per conference. """
+def create_default_floor(apps, schema_editor):
+    """ create a default floor per conference. """
     Conference = apps.get_model('core', 'Conference')
-    MapLayer = apps.get_model('core', 'MapLayer')
+    MapFloor = apps.get_model('core', 'MapFloor')
     for c in Conference.objects.all():
-        layer = MapLayer(conference=c, index=0, name='Default')
-        layer.save()
+        floor = MapFloor(conference=c, index=0, name='Default')
+        floor.save()
 
 
 class Migration(migrations.Migration):
@@ -24,18 +24,18 @@ class Migration(migrations.Migration):
 
     operations = [
         migrations.CreateModel(
-            name='MapLayer',
+            name='MapFloor',
             fields=[
                 ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
-                ('index', models.SmallIntegerField(help_text='MapLayer__index__help', verbose_name='MapLayer__index')),
-                ('name', models.CharField(help_text='MapLayer__name__help', max_length=200, verbose_name='MapLayer__name')),
-                ('name_de', models.CharField(help_text='MapLayer__name__help', max_length=200, null=True, verbose_name='MapLayer__name')),
-                ('name_en', models.CharField(help_text='MapLayer__name__help', max_length=200, null=True, verbose_name='MapLayer__name')),
-                ('conference', core.fields.ConferenceReference(help_text='Conference__reference_help', on_delete=django.db.models.deletion.CASCADE, related_name='map_layers', to='core.conference', verbose_name='Conference__reference')),
+                ('index', models.SmallIntegerField(help_text='MapFloor__index__help', verbose_name='MapFloor__index')),
+                ('name', models.CharField(help_text='MapFloor__name__help', max_length=200, unique=True, verbose_name='MapFloor__name')),
+                ('name_de', models.CharField(help_text='MapFloor__name__help', max_length=200, null=True, unique=True, verbose_name='MapFloor__name')),
+                ('name_en', models.CharField(help_text='MapFloor__name__help', max_length=200, null=True, unique=True, verbose_name='MapFloor__name')),
+                ('conference', core.fields.ConferenceReference(help_text='Conference__reference_help', on_delete=django.db.models.deletion.CASCADE, related_name='map_floors', to='core.conference', verbose_name='Conference__reference')),
             ],
             options={
-                'verbose_name': 'MapLayer',
-                'verbose_name_plural': 'MapLayers',
+                'verbose_name': 'MapFloor',
+                'verbose_name_plural': 'MapFloors',
             },
         ),
         migrations.AlterModelOptions(
@@ -47,9 +47,9 @@ class Migration(migrations.Migration):
             fields=[
                 ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
                 ('visible', models.BooleanField(default=True, help_text='MapPOI__visible__help', verbose_name='MapPOI__visible')),
-                ('name', models.CharField(help_text='MapPOI__name__help', max_length=200, verbose_name='MapPOI__name')),
-                ('name_de', models.CharField(help_text='MapPOI__name__help', max_length=200, null=True, verbose_name='MapPOI__name')),
-                ('name_en', models.CharField(help_text='MapPOI__name__help', max_length=200, null=True, verbose_name='MapPOI__name')),
+                ('name', models.CharField(help_text='MapPOI__name__help', max_length=200, unique=True, verbose_name='MapPOI__name')),
+                ('name_de', models.CharField(help_text='MapPOI__name__help', max_length=200, null=True, unique=True, verbose_name='MapPOI__name')),
+                ('name_en', models.CharField(help_text='MapPOI__name__help', max_length=200, null=True, unique=True, verbose_name='MapPOI__name')),
                 ('description', models.TextField(blank=True, help_text='MapPOI__description__help', null=True, verbose_name='MapPOI__description')),
                 ('description_de', models.TextField(blank=True, help_text='MapPOI__description__help', null=True, verbose_name='MapPOI__description')),
                 ('description_en', models.TextField(blank=True, help_text='MapPOI__description__help', null=True, verbose_name='MapPOI__description')),
@@ -59,7 +59,7 @@ class Migration(migrations.Migration):
                 ('is_official', models.BooleanField(default=False, help_text='MapPOI__is_official__help', verbose_name='MapPOI__is_official')),
                 ('location_point', django.contrib.gis.db.models.fields.PointField(blank=True, help_text='MapPOI__location_point__help', null=True, srid=4326, verbose_name='MapPOI__location_point')),
                 ('conference', core.fields.ConferenceReference(help_text='Conference__reference_help', on_delete=django.db.models.deletion.CASCADE, related_name='pois', to='core.conference', verbose_name='Conference__reference')),
-                ('location_layer', models.ForeignKey(blank=True, help_text='MapPOI__location_layer__help', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pois', to='core.maplayer', verbose_name='MapPOI__location_layer')),
+                ('location_floor', models.ForeignKey(blank=True, help_text='MapPOI__location_floor__help', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pois', to='core.mapfloor', verbose_name='MapPOI__location_floor')),
             ],
             options={
                 'verbose_name': 'MapPOI',
@@ -68,7 +68,7 @@ class Migration(migrations.Migration):
         ),
         migrations.AddField(
             model_name='assembly',
-            name='location_layer',
-            field=models.ForeignKey(blank=True, help_text='Assembly__location_layer__help', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='assemblies', to='core.maplayer', verbose_name='Assembly__location_layer'),
+            name='location_floor',
+            field=models.ForeignKey(blank=True, help_text='Assembly__location_floor__help', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='assemblies', to='core.mapfloor', verbose_name='Assembly__location_floor'),
         ),
     ]
diff --git a/src/core/models/__init__.py b/src/core/models/__init__.py
index 8c514fa8b..cf1321d6c 100644
--- a/src/core/models/__init__.py
+++ b/src/core/models/__init__.py
@@ -6,7 +6,7 @@ from .board import BulletinBoardEntry
 from .events import Event, EventAttachment, EventLikeCount, EventParticipant
 from .pages import StaticPage, StaticPageRevision
 from .markdown import MarkdownMeta
-from .map import MapLayer, MapPOI
+from .map import MapFloor, MapPOI
 from .messages import DirectMessage
 from .rooms import Room, RoomLink
 from .schedules import ScheduleSource, ScheduleSourceImport, ScheduleSourceMapping
@@ -28,7 +28,7 @@ __all__ = [
     'ConferenceTag', 'ConferenceTrack',
     'DereferrerStats', 'DirectMessage',
     'Event', 'EventAttachment', 'EventLikeCount', 'EventParticipant',
-    'MapLayer', 'MapPOI',
+    'MapFloor', 'MapPOI',
     'PlatformUser',
     'Room', 'RoomLink',
     'ScheduleSource', 'ScheduleSourceImport', 'ScheduleSourceMapping',
diff --git a/src/core/models/assemblies.py b/src/core/models/assemblies.py
index 6aa98f711..1bd3319e1 100644
--- a/src/core/models/assemblies.py
+++ b/src/core/models/assemblies.py
@@ -22,7 +22,7 @@ from ..fields import ConferenceReference
 from ..markdown import compile_translated_markdown_fields, render_markdown, store_relationships
 from ..utils import render_markdown_as_text
 from .conference import Conference, ConferenceMember
-from .map import MapLayer
+from .map import MapFloor
 from .tags import TaggedItemMixin
 from .users import PlatformUser
 
@@ -247,12 +247,12 @@ class Assembly(TaggedItemMixin, models.Model):
         verbose_name=_('Assembly__public_contact'),
     )
 
-    location_layer = models.ForeignKey(
-        MapLayer,
+    location_floor = models.ForeignKey(
+        MapFloor,
         blank=True, null=True,
         related_name='assemblies', on_delete=models.PROTECT,
-        help_text=_('Assembly__location_layer__help'),
-        verbose_name=_('Assembly__location_layer'),
+        help_text=_('Assembly__location_floor__help'),
+        verbose_name=_('Assembly__location_floor'),
     )
 
     location_point = gis_models.PointField(
@@ -528,8 +528,8 @@ class Assembly(TaggedItemMixin, models.Model):
         has_for_all_assemblies = Voucher.objects.available_for_conference(self.conference).exists()
         return 0 if has_for_all_assemblies else None
 
-    def get_location_layer_index(self):
-        return self.location_layer.index if self.location_layer else None
+    def get_location_floor_index(self):
+        return self.location_floor.index if self.location_floor else None
 
     def get_location_point_as_json(self):
         if not self.location_point or not self.location_point.valid:
diff --git a/src/core/models/map.py b/src/core/models/map.py
index 00f90ef0e..8200d4d96 100644
--- a/src/core/models/map.py
+++ b/src/core/models/map.py
@@ -14,19 +14,21 @@ from ..markdown import compile_translated_markdown_fields, store_relationships
 logger = logging.getLogger(__name__)
 
 
-class MapLayer(models.Model):
+class MapFloor(models.Model):
     class Meta:
-        verbose_name = _('MapLayer')
-        verbose_name_plural = _('MapLayers')
+        verbose_name = _('MapFloor')
+        verbose_name_plural = _('MapFloors')
 
     id = models.UUIDField(default=uuid4, primary_key=True, editable=False, serialize=False)
-    conference = ConferenceReference(related_name='map_layers')
+    conference = ConferenceReference(related_name='map_floors')
 
-    index = models.SmallIntegerField(help_text=_('MapLayer__index__help'), verbose_name=_('MapLayer__index'))
+    index = models.SmallIntegerField(help_text=_('MapFloor__index__help'), verbose_name=_('MapFloor__index'))
     name = models.CharField(
         max_length=200,
-        help_text=_('MapLayer__name__help'),
-        verbose_name=_('MapLayer__name'))
+        unique=True,
+        help_text=_('MapFloor__name__help'),
+        verbose_name=_('MapFloor__name'),
+    )
 
     def __str__(self):
         return f'[{self.index}] {self.name}'
@@ -47,6 +49,7 @@ class MapPOI(models.Model):
 
     name = models.CharField(
         max_length=200,
+        unique=True,
         help_text=_('MapPOI__name__help'),
         verbose_name=_('MapPOI__name'))
     description = models.TextField(
@@ -60,12 +63,12 @@ class MapPOI(models.Model):
         help_text=_('MapPOI__is_official__help'),
         verbose_name=_('MapPOI__is_official'))
 
-    location_layer = models.ForeignKey(
-        MapLayer,
+    location_floor = models.ForeignKey(
+        MapFloor,
         blank=True, null=True,
         related_name='pois', on_delete=models.PROTECT,
-        help_text=_('MapPOI__location_layer__help'),
-        verbose_name=_('MapPOI__location_layer'),
+        help_text=_('MapPOI__location_floor__help'),
+        verbose_name=_('MapPOI__location_floor'),
     )
 
     location_point = gis_models.PointField(
@@ -78,9 +81,9 @@ class MapPOI(models.Model):
         return self.name
 
     def clean(self):
-        if self.location_point or self.location_layer:
-            if not self.location_point or not self.location_layer:
-                raise ValidationError(_('MapPOI__need-both-layer-and-point'))
+        if self.location_point or self.location_floor:
+            if not self.location_point or not self.location_floor:
+                raise ValidationError(_('MapPOI__need-both-floor-and-point'))
 
     def save(self, *args, update_fields=None, **kwargs):
         if update_fields is None or 'description' in update_fields:
@@ -89,8 +92,8 @@ class MapPOI(models.Model):
 
         return super().save(*args, update_fields=update_fields, **kwargs)
 
-    def get_location_layer_index(self):
-        return self.location_layer.index if self.location_layer else None
+    def get_location_floor_index(self):
+        return self.location_floor.index if self.location_floor else None
 
     def get_location_point_as_json(self):
         if not self.location_point or not self.location_point.valid:
diff --git a/src/core/translation.py b/src/core/translation.py
index f10c55b4f..e35287c8d 100644
--- a/src/core/translation.py
+++ b/src/core/translation.py
@@ -6,7 +6,7 @@ from .models import \
     ConferenceMember, \
     ConferenceNavigationItem, \
     Event, \
-    MapLayer, MapPOI, \
+    MapFloor, MapPOI, \
     Room
 
 
@@ -40,8 +40,8 @@ class RoomTranslationOptions(TranslationOptions):
     fields = ('description', 'description_html', )
 
 
-@register(MapLayer)
-class MapLayerTranslationOptions(TranslationOptions):
+@register(MapFloor)
+class MapFloorTranslationOptions(TranslationOptions):
     fields = ('name', )
 
 
-- 
GitLab