ui base for reporting issues and missing locations

This commit is contained in:
Laura Klünder 2019-12-24 03:56:35 +01:00
parent 9664b22a0c
commit a8d0be6653
10 changed files with 157 additions and 69 deletions

View file

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-23 17:06+0100\n"
"POT-Creation-Date: 2019-12-24 03:50+0100\n"
"PO-Revision-Date: 2019-12-22 00:44+0100\n"
"Last-Translator: Jenny Danzmayr <mail@evilscientress.at>\n"
"Language-Team: \n"
@ -556,9 +556,10 @@ msgstr "Zugangs­beschränkung"
#: c3nav/control/templates/control/user.html:145
#: c3nav/editor/templates/editor/fragment_changesets.html:10
#: c3nav/editor/templates/editor/list.html:26
#: c3nav/site/templates/site/map.html:90 c3nav/site/templates/site/map.html:124
#: c3nav/site/templates/site/map.html:136
#: c3nav/site/templates/site/map.html:142
#: c3nav/site/templates/site/map.html:100
#: c3nav/site/templates/site/map.html:134
#: c3nav/site/templates/site/map.html:143
#: c3nav/site/templates/site/map.html:164
msgid "Details"
msgstr "Details"
@ -1490,12 +1491,12 @@ msgstr "Du hast direktes Bearbeiten aktiviert."
msgid "You deactivated direct editing."
msgstr "Du hast direktes Bearbeiten deaktiviert."
#: c3nav/mapdata/api.py:201
#: c3nav/mapdata/api.py:202
#, python-format
msgid "%(field)s is not an integer."
msgstr "%(field)s ist keine ganze Zahl."
#: c3nav/mapdata/api.py:209
#: c3nav/mapdata/api.py:210
#, python-format
msgid "%(model)s not found."
msgstr "%(model)s nicht gefunden."
@ -1844,12 +1845,12 @@ msgstr ""
"Höhenmarker #%(marker_id)d in Raum #%(space_id)d auf Etage %(level_label)s "
"ist nicht in einem begehbaren Bereich platziert"
#: c3nav/mapdata/models/geometry/level.py:639
#: c3nav/mapdata/models/geometry/level.py:624
#, python-format
msgid "%d altitude areas built."
msgstr "%d Höhenbereiche gebaut."
#: c3nav/mapdata/models/geometry/level.py:640
#: c3nav/mapdata/models/geometry/level.py:625
#, python-format
msgid ""
"%(num_modified)d modified, %(num_deleted)d deleted, %(num_created)d created."
@ -1916,7 +1917,6 @@ msgstr "Rampen"
#: c3nav/mapdata/models/geometry/space.py:173
#: c3nav/mapdata/models/geometry/space.py:205
#, fuzzy
msgid "altitude above ground"
msgstr "Höhe über Grund"
@ -2396,19 +2396,19 @@ msgstr[1] "%d freigeschaltete Bereiche"
msgid "Login"
msgstr "Anmelden"
#: c3nav/routing/api.py:49
#: c3nav/routing/api.py:50
msgid "Not yet routable, try again shortly."
msgstr "Noch nicht routebar, bitte einige Minuten warten."
#: c3nav/routing/api.py:53
#: c3nav/routing/api.py:54
msgid "Unreachable location."
msgstr "Unerreichbarer Ort."
#: c3nav/routing/api.py:57
#: c3nav/routing/api.py:58
msgid "No route found."
msgstr "Keine Route gefunden."
#: c3nav/routing/api.py:103
#: c3nav/routing/api.py:110
msgid "Invalid scan data."
msgstr "Invalide Scandaten."
@ -2456,65 +2456,65 @@ msgstr "Invalider Scan. Unerlaubte Frequenz."
msgid "Invalid Scan. Invalid last timestamp."
msgstr "Invalider Scan. Letzter Zeitstempel ungültig."
#: c3nav/routing/models.py:20 c3nav/routing/models.py:21
#: c3nav/site/templates/site/map.html:149
#: c3nav/routing/models.py:21 c3nav/routing/models.py:22
#: c3nav/site/templates/site/map.html:177
msgid "Route options"
msgstr "Routenoptionen"
#: c3nav/routing/models.py:32
#: c3nav/routing/models.py:33
msgid "Routing mode"
msgstr "Routemodus"
#: c3nav/routing/models.py:33
#: c3nav/routing/models.py:34
msgid "fastest"
msgstr "schnellste"
#: c3nav/routing/models.py:33
#: c3nav/routing/models.py:34
msgid "shortest"
msgstr "kürzeste"
#: c3nav/routing/models.py:37
#: c3nav/routing/models.py:38
msgid "Walk speed"
msgstr "Gehgeschwindigkeit"
#: c3nav/routing/models.py:38
#: c3nav/routing/models.py:39
msgid "slow"
msgstr "langsam"
#: c3nav/routing/models.py:38
#: c3nav/routing/models.py:39
msgid "default"
msgstr "standard"
#: c3nav/routing/models.py:38
#: c3nav/routing/models.py:39
msgid "fast"
msgstr "schnell"
#: c3nav/routing/models.py:44
#: c3nav/routing/models.py:45
msgid "allow"
msgstr "erlaubt"
#: c3nav/routing/models.py:46
#: c3nav/routing/models.py:47
msgid "avoid upwards"
msgstr "aufwärts vermeiden"
#: c3nav/routing/models.py:47
#: c3nav/routing/models.py:48
msgid "avoid downwards"
msgstr "abwärts vermeiden"
#: c3nav/routing/models.py:48
#: c3nav/routing/models.py:49
msgid "avoid completely"
msgstr "komplett vermeiden"
#: c3nav/routing/models.py:50
#: c3nav/routing/models.py:51
msgid "avoid"
msgstr "vermeiden"
#: c3nav/routing/models.py:143
#: c3nav/routing/models.py:144
#, python-format
msgid "Unknown route option: %s"
msgstr "Unbekannte Routenoption: %s"
#: c3nav/routing/models.py:147
#: c3nav/routing/models.py:148
#, python-format
msgid "Invalid value for route option %s."
msgstr "Invalider Wert für Routenoption %s."
@ -2549,11 +2549,11 @@ msgstr "einige Wegtypen vermieden"
msgid "default options"
msgstr "Standardoptionen"
#: c3nav/settings.py:305
#: c3nav/settings.py:304
msgid "English"
msgstr "Englisch"
#: c3nav/settings.py:306
#: c3nav/settings.py:305
msgid "German"
msgstr "Deutsch"
@ -2682,8 +2682,8 @@ msgstr "über c3nav"
msgid "Select"
msgstr "Auswählen"
#: c3nav/site/templates/site/map.html:40 c3nav/site/templates/site/map.html:51
#: c3nav/site/templates/site/map.html:94
#: c3nav/site/templates/site/map.html:40 c3nav/site/templates/site/map.html:61
#: c3nav/site/templates/site/map.html:104
msgid "Share"
msgstr "Teilen"
@ -2695,57 +2695,67 @@ msgstr "Route hierhin"
msgid "Route from here"
msgstr "Route von hier aus"
#: c3nav/site/templates/site/map.html:55
#: c3nav/site/templates/site/map.html:52 c3nav/site/templates/site/map.html:149
#: c3nav/site/templates/site/map.html:170
msgid "Report issue"
msgstr "Fehler melden"
#: c3nav/site/templates/site/map.html:56 c3nav/site/templates/site/map.html:153
#| msgid "Select this location"
msgid "Report missing location"
msgstr "Fehlenden Ort melden"
#: c3nav/site/templates/site/map.html:65
msgid "share"
msgstr "Teilen"
#: c3nav/site/templates/site/map.html:56
#: c3nav/site/templates/site/map.html:66
msgid "create shortcut"
msgstr "Verknüpfung anlegen"
#: c3nav/site/templates/site/map.html:60
#: c3nav/site/templates/site/map.html:70
msgid "Wifi-based location"
msgstr "WLAN-basierte Ortung"
#: c3nav/site/templates/site/map.html:61
#: c3nav/site/templates/site/map.html:71
msgid "Get the c3nav app for Android to see your location on the map."
msgstr ""
"Hole dir die c3nav-App für Android um deine Position auf der Karte zu sehen."
#: c3nav/site/templates/site/map.html:64
#: c3nav/site/templates/site/map.html:74
msgid "Download APK"
msgstr "APK herunterladen"
#: c3nav/site/templates/site/map.html:74 c3nav/site/templates/site/map.html:81
#: c3nav/site/templates/site/map.html:84 c3nav/site/templates/site/map.html:91
msgid "Search any location…"
msgstr "Suche einen beliebigen Ort…"
#: c3nav/site/templates/site/map.html:98
#: c3nav/site/templates/site/map.html:108
msgid "Route"
msgstr "Route"
#: c3nav/site/templates/site/map.html:110
#: c3nav/site/templates/site/map.html:120
#: c3nav/site/templates/site/map.html:130
msgid "Swap"
msgstr "Vertauschen"
#: c3nav/site/templates/site/map.html:114
#: c3nav/site/templates/site/map.html:124
msgid "Close"
msgstr "Schließen"
#: c3nav/site/templates/site/map.html:134
#: c3nav/site/templates/site/map.html:157
msgid "Open in Editor"
msgstr "Im Editor öffnen"
#: c3nav/site/templates/site/map.html:154
#: c3nav/site/templates/site/map.html:182
msgid "Save and reroute"
msgstr "Speichern und neu routen"
#: c3nav/site/templates/site/map.html:155
#: c3nav/site/templates/site/map.html:183
msgid "Just reroute"
msgstr "Nur neu routen"
#: c3nav/site/templates/site/map.html:164
#: c3nav/site/templates/site/map.html:192
#, python-format
msgid ""
"Get the c3nav Android app on <a href=\"%(play_url)s\" target=\"_blank"
@ -2756,10 +2766,14 @@ msgstr ""
"\">Google Play</a> oder <a href=\"%(apk_url)s\" target=\"_blank\">downloade "
"die APK!</a>"
#: c3nav/site/templates/site/map.html:169
#: c3nav/site/templates/site/map.html:197
msgid "open in c3nav"
msgstr "in c3nav öffnen"
#: c3nav/site/templates/site/report.html:6
msgid "Coming soon"
msgstr "Coming soon"
#: c3nav/site/views.py:71 c3nav/site/views.py:318
msgid "You need to log in to unlock areas."
msgstr "Du musst dich anmelden um Bereiche freizuschalten."
@ -2792,9 +2806,6 @@ msgstr[1] "Du wurdest eingeladen, die folgenden Bereiche freizuschalten:"
#~ msgid "You can not edit this object."
#~ msgstr "Du kannst dieses Objekt nicht bearbeiten."
#~ msgid "Select this location"
#~ msgstr "Diesen Ort auswählen"
#~ msgid "Get the c3nav Android app!"
#~ msgstr "Hol' dir die c3nav Android-App!"

View file

@ -1,4 +1,5 @@
from django.core.exceptions import ValidationError
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from rest_framework.decorators import action
from rest_framework.response import Response
@ -74,6 +75,11 @@ class RoutingViewSet(ViewSet):
'destination': form.cleaned_data['destination'].pk,
},
'options': options.serialize(),
'report_issue_url': reverse('site.report', kwargs={
'origin': request.POST['origin'],
'destination': request.POST['destination'],
'options': options.serialize_string()
}),
'result': route.serialize(locations=visible_locations_for_request(request)),
})

View file

@ -178,6 +178,9 @@ class RouteOptions(models.Model):
for name, field in self.get_fields().items()
]
def serialize_string(self):
return ','.join('%s=%s' % (key, val) for key, val in self.data.items())
def save(self, *args, **kwargs):
if self.request is None or self.request.user.is_authenticated:
self.user = self.request.user

View file

@ -1,4 +1,3 @@
import json
import logging
import operator
import os
@ -375,7 +374,7 @@ class Router:
areas=areas, near_area=near_area, near_poi=near_poi)
def shortest_path(self, restrictions, options):
options_key = json.dumps(options.data, separators=(',', '='), sort_keys=True)[1:-1]
options_key = options.serialize_string()
cache_key = 'router:shortest_path:%s:%s:%s' % (MapUpdate.current_processed_cache_key(),
restrictions.cache_key,
options_key)

View file

@ -379,10 +379,12 @@ section.details {
opacity: 0;
line-height: 2;
}
#sidebar section.details.loading > .details-body {
#sidebar section.details.loading > .details-body,
#sidebar section.details.loading > .details-buttons {
max-height: 0;
opacity: 0;
}
#sidebar section.details:not(.loading) > .details-head {
-webkit-transition: background-color 50ms;
-o-transition: background-color 50ms;
@ -396,7 +398,8 @@ section.details {
pointer-events: auto;
opacity: 1;
}
#sidebar section.details:not(.loading) > div.details-body {
#sidebar section.details:not(.loading) > div.details-body,
#sidebar section.details:not(.loading) > div.details-buttons {
max-height: 100vh;
-webkit-transition: max-height 150ms, opacity 50ms;
-o-transition: max-height 150ms, opacity 50ms;
@ -745,18 +748,19 @@ main:not([data-view=route-result]) #route-dots {
.buttons {
border: 0 #dddddd solid;
border-top-width: 1px;
.button-clear {
display:block;
width: 100%;
padding: 0 7px;
margin: 0;
line-height: 3.3rem;
}
}
.location {
margin-right: 24px;
padding-right: 0;
overflow: hidden;
}
.button-clear {
display:block;
width: 100%;
padding: 0 7px;
margin: 0;
}
.as-location .material-icons {
transform: rotate(-45deg);
}

View file

@ -193,7 +193,7 @@ c3nav = {
.on('submit', 'form', c3nav._modal_submit)
.on('click', '.mobileclient-share', c3nav._mobileclient_share_click)
.on('click', '.mobileclient-shortcut', c3nav._mobileclient_shortcut_click);
$('header #user, #about-link').on('click', c3nav._modal_link_click);
$('header #user, #about-link, .buttons a').on('click', c3nav._modal_link_click);
$('header h1 a').removeAttr('href');
@ -351,13 +351,13 @@ c3nav = {
var $location_details = $('#location-details');
if ($location_details.attr('data-id') !== String(location.id)) {
$location_details.addClass('loading').attr('data-id', location.id);
$location_details.find('.details-buttons').hide();
c3nav._clear_route_layers();
$.getJSON('/api/locations/'+location.id+'/details', c3nav._location_details_loaded).fail(function (data) {
var $location_details = $('#location-details');
$location_details.find('.details-body').text('Error '+String(data.status));
$location_details.find('.details-body').html('').append(elem);
$location_details.find('.editor').hide();
$location_details.find('.report').hide();
$location_details.removeClass('loading');
});
}
@ -394,7 +394,6 @@ c3nav = {
elem.append(loclist);
}
}
$location_details.find('.details-buttons').show();
$location_details.find('.details-body').html('').append(elem);
var $editor = $location_details.find('.editor');
@ -404,6 +403,12 @@ c3nav = {
$editor.hide();
}
var custom_location = typeof data.id !== 'number',
report_url = '/report/l/'+String(data.id)+'/';
$location_details.find('.report').attr('href', report_url);
$location_details.find('.report-issue').toggle(!custom_location);
$location_details.find('.report-missing').toggle(custom_location);
if (data.geometry && data.level) {
L.geoJSON(data.geometry, {
style: {
@ -449,6 +454,7 @@ c3nav = {
// loaded too late, information no longer needed
return;
}
$('#route-details .report').attr('href', data.report_issue_url);
c3nav._push_state({route_result: data.result, route_options: data.options}, true);
c3nav._display_route_result(data.result, nofly);
c3nav._display_route_options(data.options);
@ -465,6 +471,8 @@ c3nav = {
item, coords, description;
c3nav._clear_route_layers();
$details_wrapper.find('.report')
$details.html('');
$details.append(c3nav._build_location_html(result.origin));
@ -778,6 +786,8 @@ c3nav = {
c3nav.update_state(false);
} else if ($(this).is('.share')) {
c3nav._buttons_share_click(location);
} else if ($(this).is('a')) {
c3nav._modal_link_click.call(this, e);
} else {
var $locationinput = $(this).is('.as-origin') ? $origin : $destination,
$other_locationinput = $(this).is('.as-origin') ? $destination : $origin,
@ -1246,7 +1256,10 @@ c3nav = {
if (c3nav._click_anywhere_popup !== popup || !popup.isOpen()) return;
popup.remove();
popup = L.popup(c3nav._add_map_padding({className: 'location-popup', maxWidth: 500}, 'autoPanPaddingTopLeft', 'autoPanPaddingBottomRight'));
popup.setLatLng(e.latlng).setContent(c3nav._build_location_html(data)+$('#popup-buttons').html());
var buttons = $('#popup-buttons').clone();
buttons.find('.report-issue').remove();
buttons.find('.report').attr('href', '/report/l/'+String(data.id)+'/');
popup.setLatLng(e.latlng).setContent(c3nav._build_location_html(data)+buttons.html());
c3nav._click_anywhere_popup = popup;
popup.on('remove', function() { c3nav._click_anywhere_popup = null }).openOn(c3nav.map);
}).fail(function() {
@ -1368,10 +1381,18 @@ c3nav = {
}
var point = c3nav._location_point_overrides[location.id] || location.point.slice(1),
latlng = L.GeoJSON.coordsToLatLng(point);
latlng = L.GeoJSON.coordsToLatLng(point),
buttons = $('#popup-buttons').clone();
if (typeof location.id == 'number') {
buttons.find('.report-missing').remove();
} else {
buttons.find('.report-issue').remove();
}
buttons.find('.report').attr('href', '/report/l/'+String(location.id)+'/');
L.marker(latlng, {
icon: icon
}).bindPopup(location.elem+$('#popup-buttons').html(), c3nav._add_map_padding({
}).bindPopup(location.elem+buttons.html(), c3nav._add_map_padding({
className: 'location-popup',
maxWidth: 500
}, 'autoPanPaddingTopLeft', 'autoPanPaddingBottomRight')).addTo(c3nav._locationLayers[location.point[0]]);

View file

@ -46,6 +46,16 @@
<div class="buttons">
<button class="button-clear as-origin"><i class="material-icons">directions</i> {% trans 'Route from here' %}</button>
</div>
<div class="buttons">
<a class="button button-clear report report-issue">
<i class="material-icons">feedback</i>
{% trans 'Report issue' %}
</a>
<a class="button button-clear report report-missing">
<i class="material-icons">feedback</i>
{% trans 'Report missing location' %}
</a>
</div>
</section>
<section class="share-ui">
<h3>{% trans 'Share' %}</h3>
@ -132,13 +142,21 @@
<button class="button close button-clear material-icons float-right">close</button>
<h2>{% trans 'Details' %}</h2>
</div>
<div class="details-buttons buttons">
<div class="details-body"></div>
<div class="details-buttons buttons">
<a class="button button-clear report report-issue">
<i class="material-icons">feedback</i>
{% trans 'Report issue' %}
</a>
<a class="button button-clear report report-missing">
<i class="material-icons">feedback</i>
{% trans 'Report missing location' %}
</a>
<a class="button button-clear editor" target="_blank">
<i class="material-icons">edit</i>
{% trans 'Open in Editor' %}
</a>
</div>
<div class="details-body"></div>
</section>
<section id="route-details" class="details">
<div class="details-head">
@ -146,6 +164,12 @@
<h2>{% trans 'Details' %}</h2>
</div>
<div class="details-body"></div>
<div class="details-buttons buttons">
<a class="button button-clear report report-issue">
<i class="material-icons">feedback</i>
{% trans 'Report issue' %}
</a>
</div>
</section>
<section id="route-options" class="details">
<div class="details-head">

View file

@ -0,0 +1,10 @@
{% extends 'site/base.html' %}
{% load i18n %}
{% block content %}
<main class="account">
<h2>{% trans 'Coming soon' %}</h2>
{% include 'site/fragment_messages.html' %}
</main>
{% endblock %}

View file

@ -1,9 +1,10 @@
from django.conf.urls import url
from c3nav.site.views import (about_view, access_redeem_view, account_view, change_password_view, choose_language,
login_view, logout_view, map_index, qr_code, register_view)
login_view, logout_view, map_index, qr_code, register_view, report_view)
slug = r'(?P<slug>[a-z0-9-_.:]+)'
coordinates = r'(?P<coordinates>[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?)'
slug2 = r'(?P<slug2>[a-z0-9-_.:]+)'
details = r'(?P<details>details/)?'
options = r'(?P<options>options/)?'
@ -25,4 +26,8 @@ urlpatterns = [
url(r'^access/(?P<token>[^/]+)$', access_redeem_view, name='site.access.redeem'),
url(r'^lang/$', choose_language, name='site.language'),
url(r'^about/$', about_view, name='site.about'),
url(r'^report/$', about_view, name='site.about'),
url(r'^report/l/%s/$' % coordinates, report_view, name='site.report'),
url(r'^report/l/(?P<location>\d+)/$', report_view, name='site.report'),
url(r'^report/r/(?P<origin>[^/]+)/(?P<destination>[^/]+)/(?P<options>[^/]+)/$', report_view, name='site.report'),
]

View file

@ -348,3 +348,8 @@ def about_view(request):
'team': settings.IMPRINT_TEAM,
'hosting': settings.IMPRINT_HOSTING,
})
@never_cache
def report_view(request, coordinates=None, location=None, origin=None, destination=None, options=None):
return render(request, 'site/report.html', {})