add Location.details_display()

This commit is contained in:
Laura Klünder 2017-11-02 13:35:58 +01:00
parent ba3e1e485e
commit 949b88389e
8 changed files with 114 additions and 78 deletions

View file

@ -1,17 +1,15 @@
import mimetypes import mimetypes
from collections import namedtuple from collections import namedtuple
from functools import wraps from functools import wraps
from operator import attrgetter
from django.core.cache import cache from django.core.cache import cache
from django.db.models import FieldDoesNotExist, Model, Prefetch from django.db.models import Prefetch
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse
from django.utils.cache import get_conditional_response from django.utils.cache import get_conditional_response
from django.utils.http import quote_etag from django.utils.http import quote_etag
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language, get_language_info from django.utils.translation import get_language
from rest_framework.decorators import detail_route, list_route from rest_framework.decorators import detail_route, list_route
from rest_framework.exceptions import NotFound, ValidationError from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.mixins import RetrieveModelMixin from rest_framework.mixins import RetrieveModelMixin
@ -19,7 +17,7 @@ from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet, ViewSet from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet, ViewSet
from c3nav.mapdata.models import AccessRestriction, Building, Door, Hole, LocationGroup, MapUpdate, Source, Space from c3nav.mapdata.models import AccessRestriction, Building, Door, Hole, LocationGroup, MapUpdate, Source, Space
from c3nav.mapdata.models.access import AccessPermission, AccessRestrictionMixin from c3nav.mapdata.models.access import AccessPermission
from c3nav.mapdata.models.geometry.level import LevelGeometryMixin from c3nav.mapdata.models.geometry.level import LevelGeometryMixin
from c3nav.mapdata.models.geometry.space import POI, Area, Column, LineObstacle, Obstacle, SpaceGeometryMixin, Stair from c3nav.mapdata.models.geometry.space import POI, Area, Column, LineObstacle, Obstacle, SpaceGeometryMixin, Stair
from c3nav.mapdata.models.level import Level from c3nav.mapdata.models.level import Level
@ -301,78 +299,7 @@ class LocationViewSet(RetrieveModelMixin, GenericViewSet):
if isinstance(location, LocationRedirect): if isinstance(location, LocationRedirect):
return redirect('../' + location.target.slug + '/display/') return redirect('../' + location.target.slug + '/display/')
result = location.serialize(geometry=True) return Response(location.details_display())
display = [
(str(_('Type')), str(location.__class__._meta.verbose_name)),
(str(_('ID')), str(location.pk)),
]
for lang, title in sorted(location.titles.items(), key=lambda item: item[0] != get_language()):
language = _('Title ({lang})').format(lang=get_language_info(lang)['name_translated'])
display.append((language, title))
display.append((str(_('Slug')), str(location.get_slug())))
if isinstance(location, Level):
display.append((str(_('short label')), location.short_label))
if isinstance(location, LevelGeometryMixin):
display.append((str(_('Level')), {'slug': location.level.get_slug(), 'title': location.level.title}))
if isinstance(location, SpaceGeometryMixin):
display.append((str(_('Space')), {'slug': location.space.get_slug(), 'title': location.space.title}))
if isinstance(location, LocationGroup):
display.append((str(_('Category')), location.category.title))
if isinstance(location, AccessRestrictionMixin):
display.append((str(_('Access Restriction')),
location.access_restriction_id and location.access_restriction.title))
groupcategories = {}
if isinstance(location, SpecificLocation):
for group in location.groups.all():
groupcategories.setdefault(group.category, []).append(group)
for category, groups in sorted(groupcategories.items(), key=lambda item: item[0].priority, reverse=True):
display.append((category.title, tuple(
{'slug': group.get_slug(), 'title': group.title}
for group in sorted(groups, key=attrgetter('priority'), reverse=True)
)))
model: Model = location.__class__
for name in ('can_search', 'can_describe', 'color', 'outside', 'base_altitude', 'height', 'default_height',
'priority'):
try:
field = model._meta.get_field(name)
except FieldDoesNotExist:
continue
value = getattr(location, name)
if isinstance(value, bool):
value = _('Ja') if value else _('Nein')
display.append((str(field.verbose_name), value and str(value)))
editor_url = None
if isinstance(location, Level):
editor_url = reverse('editor.levels.detail', kwargs={'pk': location.pk})
elif isinstance(location, Space):
editor_url = reverse('editor.spaces.detail', kwargs={'level': location.level_id, 'pk': location.pk})
elif isinstance(location, Area):
editor_url = reverse('editor.areas.edit', kwargs={'space': location.space_id, 'pk': location.pk})
elif isinstance(location, POI):
editor_url = reverse('editor.pois.edit', kwargs={'space': location.space_id, 'pk': location.pk})
elif isinstance(location, LocationGroup):
editor_url = reverse('editor.locationgroups.edit', kwargs={'pk': location.pk})
result = {
'editor_url': editor_url,
'display': display,
'geometry': result['geometry'],
}
return Response(result)
@list_route(methods=['get']) @list_route(methods=['get'])
@api_etag(permissions=False) @api_etag(permissions=False)

View file

@ -89,6 +89,13 @@ class AccessRestrictionMixin(SerializableMixin, models.Model):
result['access_restriction'] = self.access_restriction_id result['access_restriction'] = self.access_restriction_id
return result return result
def details_display(self):
result = super().details_display()
result['display'].extend([
(str(_('Access Restriction')), self.access_restriction_id and self.access_restriction.title),
])
return result
@classmethod @classmethod
def qs_for_request(cls, request, allow_none=False): def qs_for_request(cls, request, allow_none=False):
return cls.objects.filter(cls.q_for_request(request, allow_none=allow_none)) return cls.objects.filter(cls.q_for_request(request, allow_none=allow_none))

View file

@ -3,7 +3,7 @@ from collections import OrderedDict
from django.core.cache import cache from django.core.cache import cache
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language from django.utils.translation import get_language, get_language_info
from c3nav.mapdata.fields import JSONField from c3nav.mapdata.fields import JSONField
from c3nav.mapdata.models import MapUpdate from c3nav.mapdata.models import MapUpdate
@ -32,6 +32,14 @@ class SerializableMixin(models.Model):
result['id'] = self.pk result['id'] = self.pk
return result return result
def details_display(self):
return {
'display': [
(str(_('Type')), str(self.__class__._meta.verbose_name)),
(str(_('ID')), str(self.pk)),
]
}
@property @property
def title(self): def title(self):
return self._meta.verbose_name + ' ' + str(self.id) return self._meta.verbose_name + ' ' + str(self.id)
@ -57,6 +65,13 @@ class TitledMixin(SerializableMixin, models.Model):
result['title'] = self.title result['title'] = self.title
return result return result
def details_display(self):
result = super().details_display()
for lang, title in sorted(self.titles.items(), key=lambda item: item[0] != get_language()):
language = _('Title ({lang})').format(lang=get_language_info(lang)['name_translated'])
result['display'].append((language, title))
return result
@property @property
def title(self): def title(self):
lang = get_language() lang = get_language()

View file

@ -88,6 +88,11 @@ class GeometryMixin(SerializableMixin):
(int(math.ceil(self.maxx)), int(math.ceil(self.maxy)))) (int(math.ceil(self.maxx)), int(math.ceil(self.maxy))))
return result return result
def details_display(self):
result = super().details_display()
result['geometry'] = format_geojson(mapping(self.geometry), round=False)
return result
def get_shadow_geojson(self): def get_shadow_geojson(self):
pass pass

View file

@ -4,6 +4,7 @@ from operator import attrgetter, itemgetter
import numpy as np import numpy as np
from django.db import models from django.db import models
from django.db.models import F from django.db.models import F
from django.urls import reverse
from django.utils.text import format_lazy from django.utils.text import format_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from scipy.sparse.csgraph._shortest_path import dijkstra from scipy.sparse.csgraph._shortest_path import dijkstra
@ -43,6 +44,11 @@ class LevelGeometryMixin(GeometryMixin):
result['level'] = self.level_id result['level'] = self.level_id
return result return result
def details_display(self):
result = super().details_display()
result['display'].insert(3, (str(_('Level')), {'slug': self.level.get_slug(), 'title': self.level.title}))
return result
@property @property
def subtitle(self): def subtitle(self):
base_subtitle = super().subtitle base_subtitle = super().subtitle
@ -96,6 +102,15 @@ class Space(LevelGeometryMixin, SpecificLocation, models.Model):
result['height'] = None if self.height is None else float(str(self.height)) result['height'] = None if self.height is None else float(str(self.height))
return result return result
def details_display(self):
result = super().details_display()
result['display'].extend([
(str(_('height')), self.height),
(str(_('outside only')), str(_('yes') if self.outside else _('no'))),
])
result['editor_url'] = reverse('editor.spaces.detail', kwargs={'level': self.level_id, 'pk': self.pk})
return result
class Door(LevelGeometryMixin, AccessRestrictionMixin, models.Model): class Door(LevelGeometryMixin, AccessRestrictionMixin, models.Model):
""" """

View file

@ -1,4 +1,5 @@
from django.db import models from django.db import models
from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.text import format_lazy from django.utils.text import format_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -52,6 +53,11 @@ class SpaceGeometryMixin(GeometryMixin):
self.geometry if force else self.get_changed_geometry() self.geometry if force else self.get_changed_geometry()
)) ))
def details_display(self):
result = super().details_display()
result['display'].insert(3, (str(_('Space')), {'slug': self.space.get_slug(), 'title': self.space.title}))
return result
def register_delete(self): def register_delete(self):
space = self.space space = self.space
changed_geometries.register(space.level_id, space.geometry.intersection(self.geometry)) changed_geometries.register(space.level_id, space.geometry.intersection(self.geometry))
@ -88,6 +94,11 @@ class Area(SpaceGeometryMixin, SpecificLocation, models.Model):
result = super()._serialize(**kwargs) result = super()._serialize(**kwargs)
return result return result
def details_display(self):
result = super().details_display()
result['editor_url'] = reverse('editor.areas.edit', kwargs={'space': self.space_id, 'pk': self.pk})
return result
class Stair(SpaceGeometryMixin, models.Model): class Stair(SpaceGeometryMixin, models.Model):
""" """
@ -168,6 +179,11 @@ class POI(SpaceGeometryMixin, SpecificLocation, models.Model):
verbose_name_plural = _('Points of Interest') verbose_name_plural = _('Points of Interest')
default_related_name = 'pois' default_related_name = 'pois'
def details_display(self):
result = super().details_display()
result['editor_url'] = reverse('editor.pois.edit', kwargs={'space': self.space_id, 'pk': self.pk})
return result
class Hole(SpaceGeometryMixin, models.Model): class Hole(SpaceGeometryMixin, models.Model):
""" """

View file

@ -6,6 +6,7 @@ from operator import attrgetter, itemgetter
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.db.models import Prefetch from django.db.models import Prefetch
from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from shapely.geometry import JOIN_STYLE, box from shapely.geometry import JOIN_STYLE, box
@ -88,6 +89,16 @@ class Level(SpecificLocation, models.Model):
result['default_height'] = float(str(self.default_height)) result['default_height'] = float(str(self.default_height))
return result return result
def details_display(self):
result = super().details_display()
result['display'].insert(3, (str(_('short label')), self.short_label))
result['display'].extend([
(str(_('outside only')), self.base_altitude),
(str(_('default height')), self.default_height),
])
result['editor_url'] = reverse('editor.levels.detail', kwargs={'pk': self.pk})
return result
def _render_space_ground(self, svg, space): def _render_space_ground(self, svg, space):
areas_by_color = {} areas_by_color = {}
for area in space.areas.all(): for area in space.areas.all():

View file

@ -1,8 +1,10 @@
from collections import OrderedDict from collections import OrderedDict
from contextlib import suppress from contextlib import suppress
from operator import attrgetter
from django.db import models from django.db import models
from django.db.models import Prefetch from django.db.models import Prefetch
from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.text import format_lazy from django.utils.text import format_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -57,6 +59,11 @@ class LocationSlug(SerializableMixin, models.Model):
result['slug'] = self.get_slug() result['slug'] = self.get_slug()
return result return result
def details_display(self):
result = super().details_display()
result['display'].insert(2, (str(_('Slug')), str(self.get_slug())))
return result
@cached_property @cached_property
def order(self): def order(self):
return (-1, 0) return (-1, 0)
@ -94,6 +101,14 @@ class Location(LocationSlug, AccessRestrictionMixin, TitledMixin, models.Model):
result['can_describe'] = self.can_search result['can_describe'] = self.can_search
return result return result
def details_display(self):
result = super().details_display()
result['display'].extend([
(str(_('can be searched')), str(_('yes') if self.can_search else _('no'))),
(str(_('can describe')), str(_('yes') if self.can_describe else _('no')))
])
return result
def get_slug(self): def get_slug(self):
if self.slug is None: if self.slug is None:
code = self.LOCATION_TYPE_CODES.get(self.__class__.__name__) code = self.LOCATION_TYPE_CODES.get(self.__class__.__name__)
@ -139,6 +154,21 @@ class SpecificLocation(Location, models.Model):
result['groups'] = groups result['groups'] = groups
return result return result
def details_display(self):
result = super().details_display()
groupcategories = {}
for group in self.groups.all():
groupcategories.setdefault(group.category, []).append(group)
for category, groups in sorted(groupcategories.items(), key=lambda item: item[0].priority):
result['display'].insert(3, (category.title, tuple(
{'slug': group.get_slug(), 'title': group.title}
for group in sorted(groups, key=attrgetter('priority'), reverse=True)
)))
return result
@property @property
def subtitle(self): def subtitle(self):
groups = tuple(self.groups.all()) groups = tuple(self.groups.all())
@ -230,6 +260,16 @@ class LocationGroup(Location, models.Model):
result['locations'] = tuple(obj.pk for obj in getattr(self, 'locations', ())) result['locations'] = tuple(obj.pk for obj in getattr(self, 'locations', ()))
return result return result
def details_display(self):
result = super().details_display()
result['display'].insert(3, (str(_('Category')), self.category.title))
result['display'].extend([
(str(_('color')), self.color),
(str(_('priority')), self.priority),
])
result['editor_url'] = reverse('editor.locationgroups.edit', kwargs={'pk': self.pk})
return result
@property @property
def title_for_forms(self): def title_for_forms(self):
attributes = [] attributes = []