From 407e3ba06bc3680f5a36feda6a5378da006b6297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Fri, 27 Dec 2019 14:13:40 +0100 Subject: [PATCH] first stuff for custom positions --- src/c3nav/locale/de/LC_MESSAGES/django.po | 586 +++++++++++------- .../0082_dynamiclocation_position.py | 56 ++ src/c3nav/mapdata/models/locations.py | 53 ++ src/c3nav/mapdata/models/report.py | 36 +- src/c3nav/mapdata/utils/fields.py | 35 ++ src/c3nav/site/forms.py | 7 + src/c3nav/site/templates/site/account.html | 9 + .../site/templates/site/position_create.html | 16 + .../site/templates/site/position_detail.html | 30 + .../site/templates/site/position_list.html | 18 + src/c3nav/site/urls.py | 7 +- src/c3nav/site/views.py | 69 ++- 12 files changed, 655 insertions(+), 267 deletions(-) create mode 100644 src/c3nav/mapdata/migrations/0082_dynamiclocation_position.py create mode 100644 src/c3nav/mapdata/utils/fields.py create mode 100644 src/c3nav/site/templates/site/position_create.html create mode 100644 src/c3nav/site/templates/site/position_detail.html create mode 100644 src/c3nav/site/templates/site/position_list.html diff --git a/src/c3nav/locale/de/LC_MESSAGES/django.po b/src/c3nav/locale/de/LC_MESSAGES/django.po index f32f2163..3049f9fe 100644 --- a/src/c3nav/locale/de/LC_MESSAGES/django.po +++ b/src/c3nav/locale/de/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-12-25 00:40+0100\n" -"PO-Revision-Date: 2019-12-25 00:41+0100\n" +"POT-Creation-Date: 2019-12-27 14:08+0100\n" +"PO-Revision-Date: 2019-12-27 14:11+0100\n" "Last-Translator: Jenny Danzmayr \n" "Language-Team: \n" "Language: de\n" @@ -42,7 +42,8 @@ msgstr "Nich angemeldet." msgid "Logout successful." msgstr "Login erfolgreich." -#: c3nav/api/models.py:14 c3nav/mapdata/models/report.py:85 +#: c3nav/api/models.py:14 c3nav/mapdata/models/locations.py:497 +#: c3nav/mapdata/models/report.py:55 msgid "secret" msgstr "secret" @@ -206,6 +207,7 @@ msgid "can review reports belonging to" msgstr "can Meldungen überprüfen die zu diesen Gruppen gehören" #: c3nav/control/models.py:38 c3nav/control/templates/control/user.html:34 +#: c3nav/site/templates/site/position_detail.html:15 msgid "API secret" msgstr "API secret" @@ -266,7 +268,7 @@ msgstr "Benutzer" #: c3nav/control/templates/control/announcements.html:9 #: c3nav/control/templates/control/map_updates.html:59 #: c3nav/control/templates/control/users.html:15 -#: c3nav/mapdata/models/base.py:43 c3nav/mapdata/utils/locations.py:309 +#: c3nav/mapdata/models/base.py:43 c3nav/mapdata/utils/locations.py:315 #: c3nav/site/templates/site/report_list.html:18 msgid "ID" msgstr "ID" @@ -450,7 +452,7 @@ msgstr "" #: c3nav/control/templates/control/user.html:144 #: c3nav/control/templates/control/user.html:177 #: c3nav/mapdata/models/geometry/level.py:142 -#: c3nav/mapdata/models/locations.py:122 c3nav/mapdata/models/locations.py:123 +#: c3nav/mapdata/models/locations.py:131 c3nav/mapdata/models/locations.py:132 msgid "Yes" msgstr "Ja" @@ -460,7 +462,7 @@ msgstr "Ja" #: c3nav/control/templates/control/user.html:146 #: c3nav/control/templates/control/user.html:179 #: c3nav/mapdata/models/geometry/level.py:142 -#: c3nav/mapdata/models/locations.py:122 c3nav/mapdata/models/locations.py:123 +#: c3nav/mapdata/models/locations.py:131 c3nav/mapdata/models/locations.py:132 msgid "No" msgstr "Nein" @@ -528,7 +530,7 @@ msgstr "zurück" #: c3nav/control/templates/control/user.html:77 #: c3nav/mapdata/models/access.py:77 c3nav/mapdata/models/geometry/space.py:385 -#: c3nav/mapdata/models/report.py:64 c3nav/mapdata/models/report.py:163 +#: c3nav/mapdata/models/report.py:34 c3nav/mapdata/models/report.py:170 #: c3nav/site/models.py:17 msgid "author" msgstr "Autor" @@ -571,10 +573,10 @@ msgstr "Zugangs­beschränkung" #: c3nav/control/templates/control/user.html:149 #: c3nav/editor/templates/editor/fragment_changesets.html:10 #: c3nav/editor/templates/editor/list.html:26 -#: c3nav/site/templates/site/map.html:112 -#: c3nav/site/templates/site/map.html:146 -#: c3nav/site/templates/site/map.html:155 -#: c3nav/site/templates/site/map.html:176 +#: c3nav/site/templates/site/map.html:119 +#: c3nav/site/templates/site/map.html:153 +#: c3nav/site/templates/site/map.html:162 +#: c3nav/site/templates/site/map.html:183 msgid "Details" msgstr "Details" @@ -586,7 +588,7 @@ msgstr "Raumzugriffserlaubnis" #: c3nav/editor/templates/editor/space.html:9 #: c3nav/mapdata/models/geometry/level.py:124 #: c3nav/mapdata/models/geometry/space.py:81 -#: c3nav/mapdata/utils/locations.py:317 +#: c3nav/mapdata/utils/locations.py:323 msgid "Space" msgstr "Raum" @@ -688,37 +690,37 @@ msgstr "" "Kartenänderungsverarbeitung konnte nicht veranlasst werden da Celery nicht " "konfiguriert ist." -#: c3nav/editor/api.py:411 +#: c3nav/editor/api.py:414 msgid "No matching editor view endpoint found." msgstr "Es wurde keine passende Editor-Endpunkt gefunden." -#: c3nav/editor/api.py:414 +#: c3nav/editor/api.py:417 msgid "Matching editor view point does not provide an API." msgstr "Der entsprechende Editor-Endpunkt bietet diese API nicht an." -#: c3nav/editor/api.py:497 +#: c3nav/editor/api.py:500 msgid "You don't have the permission to activate direct editing." msgstr "Du darfst direktes Bearbeiten nicht aktivieren." -#: c3nav/editor/api.py:501 +#: c3nav/editor/api.py:504 msgid "You cannot activate direct editing if you have an active changeset." msgstr "" "Du kannst direktes Bearbeiten nicht aktivieren, wenn du ein aktives " "Änderungsset hast." -#: c3nav/editor/api.py:532 c3nav/editor/views/changes.py:66 +#: c3nav/editor/api.py:535 c3nav/editor/views/changes.py:66 msgid "You can not activate this change set." msgstr "Du kannst dieses Änderungsset nicht aktivieren." -#: c3nav/editor/api.py:542 c3nav/editor/views/changes.py:400 +#: c3nav/editor/api.py:545 c3nav/editor/views/changes.py:400 msgid "You cannot edit this change set." msgstr "Du kannst dieses Änderungsset nicht bearbeiten." -#: c3nav/editor/api.py:571 c3nav/editor/views/changes.py:56 +#: c3nav/editor/api.py:574 c3nav/editor/views/changes.py:56 msgid "You can not edit changes on this change set." msgstr "Du kannst keine Änderungen dieses Änderungssets bearbeiten." -#: c3nav/editor/api.py:581 c3nav/editor/views/changes.py:52 +#: c3nav/editor/api.py:584 c3nav/editor/views/changes.py:52 msgid "" "You cannot restore this object, because it depends on a deleted object or it " "would violate a unique contraint." @@ -726,41 +728,41 @@ msgstr "" "Du kannst dieses Objekt nicht wiederherstellen weil es ein anderes Objekt " "benötigt oder weil es einer Eindeutigen Beschränkung wiedersprechen würde." -#: c3nav/editor/api.py:589 c3nav/editor/views/changes.py:72 +#: c3nav/editor/api.py:592 c3nav/editor/views/changes.py:72 msgid "You need to log in to propose changes." msgstr "Du musst dich anmelden um Änderungen vorzuschlagen." -#: c3nav/editor/api.py:594 c3nav/editor/views/changes.py:77 +#: c3nav/editor/api.py:597 c3nav/editor/views/changes.py:77 msgid "You need to add a title an a description to propose this change set." msgstr "" "Du musst einen Titel und eine Beschreibung hinzufügen, um dieses " "Änderungsset vorzuschlagen." -#: c3nav/editor/api.py:597 c3nav/editor/views/changes.py:84 +#: c3nav/editor/api.py:600 c3nav/editor/views/changes.py:84 msgid "You cannot propose this change set." msgstr "Du kannst dieses Änderungsset nicht vorschlagen." -#: c3nav/editor/api.py:607 c3nav/editor/views/changes.py:94 +#: c3nav/editor/api.py:610 c3nav/editor/views/changes.py:94 msgid "You cannot unpropose this change set." msgstr "Du kannst diesen Änderungsvorschlag nicht zurücknehmen." -#: c3nav/editor/api.py:617 c3nav/editor/views/changes.py:104 +#: c3nav/editor/api.py:620 c3nav/editor/views/changes.py:104 msgid "You cannot review these changes." msgstr "Du kannst diese Änderungen nicht überprüfen." -#: c3nav/editor/api.py:627 c3nav/editor/views/changes.py:111 +#: c3nav/editor/api.py:630 c3nav/editor/views/changes.py:111 msgid "You cannot reject these changes." msgstr "Du kannst diese Änderungen nicht ablehnen." -#: c3nav/editor/api.py:641 c3nav/editor/views/changes.py:131 +#: c3nav/editor/api.py:644 c3nav/editor/views/changes.py:131 msgid "You cannot unreject these changes." msgstr "Du kannst diese Änderungsablehnung nicht zurücknehmen." -#: c3nav/editor/api.py:651 c3nav/editor/views/changes.py:142 +#: c3nav/editor/api.py:654 c3nav/editor/views/changes.py:142 msgid "You cannot accept and apply these changes." msgstr "Du kannst diese Änderungen nicht akzeptieren und anwenden." -#: c3nav/editor/api.py:661 c3nav/editor/views/changes.py:155 +#: c3nav/editor/api.py:664 c3nav/editor/views/changes.py:155 msgid "You cannot delete this change set." msgstr "Du kannst dieses Änderungsset nicht löschen." @@ -803,7 +805,7 @@ msgid "Change Set" msgstr "Änderungsset" #: c3nav/editor/models/changedobject.py:35 c3nav/editor/models/changeset.py:39 -#: c3nav/editor/views/changes.py:266 c3nav/mapdata/models/report.py:62 +#: c3nav/editor/views/changes.py:266 c3nav/mapdata/models/report.py:32 #: c3nav/site/models.py:14 c3nav/site/models.py:54 msgid "created" msgstr "erstellt" @@ -877,8 +879,8 @@ msgid "last state update" msgstr "letzte Statusänderung" #: c3nav/editor/models/changeset.py:48 c3nav/mapdata/models/base.py:64 -#: c3nav/mapdata/models/graph.py:38 c3nav/mapdata/models/locations.py:256 -#: c3nav/mapdata/models/locations.py:423 c3nav/mapdata/utils/locations.py:345 +#: c3nav/mapdata/models/graph.py:38 c3nav/mapdata/models/locations.py:265 +#: c3nav/mapdata/models/locations.py:432 c3nav/mapdata/utils/locations.py:351 #: c3nav/site/templates/site/report_list.html:19 msgid "Title" msgstr "Titel" @@ -887,8 +889,8 @@ msgstr "Titel" msgid "Description" msgstr "Beschreibung" -#: c3nav/editor/models/changeset.py:51 c3nav/mapdata/models/report.py:72 -#: c3nav/mapdata/models/report.py:167 +#: c3nav/editor/models/changeset.py:51 c3nav/mapdata/models/report.py:42 +#: c3nav/mapdata/models/report.py:174 msgid "assigned to" msgstr "zugewiesen" @@ -900,22 +902,22 @@ msgstr "Kartenänderung" msgid "Change Sets" msgstr "Änderungssets" -#: c3nav/editor/models/changeset.py:801 +#: c3nav/editor/models/changeset.py:805 msgid "Direct editing active" msgstr "Direktes Bearbeiten aktiv" -#: c3nav/editor/models/changeset.py:802 +#: c3nav/editor/models/changeset.py:806 msgid "No objects changed" msgstr "Keine Objekte geändert" -#: c3nav/editor/models/changeset.py:803 +#: c3nav/editor/models/changeset.py:807 #, python-format msgid "%(num)d object changed" msgid_plural "%(num)d objects changed" msgstr[0] "%(num)d Objekt geändert" msgstr[1] "%(num)d Objekte geändert" -#: c3nav/editor/models/changesetupdate.py:12 c3nav/mapdata/models/report.py:162 +#: c3nav/editor/models/changesetupdate.py:12 c3nav/mapdata/models/report.py:169 msgid "datetime" msgstr "Zeitpunkt" @@ -1162,12 +1164,12 @@ msgid "close dialog" msgstr "Dialog schließen" #: c3nav/editor/templates/editor/fragment_nav.html:21 -#: c3nav/site/templates/site/account.html:46 +#: c3nav/site/templates/site/account.html:55 msgid "Log out" msgstr "Abmelden" #: c3nav/editor/templates/editor/fragment_nav.html:23 -#: c3nav/editor/views/account.py:27 c3nav/site/views.py:233 +#: c3nav/editor/views/account.py:27 c3nav/site/views.py:238 msgid "Log in" msgstr "Anmelden" @@ -1210,12 +1212,14 @@ msgstr "Einstellungen für neue Kanten" #: c3nav/editor/templates/editor/index.html:10 #: c3nav/editor/templates/editor/level.html:16 #: c3nav/mapdata/models/geometry/level.py:58 c3nav/mapdata/models/level.py:29 -#: c3nav/mapdata/utils/locations.py:311 +#: c3nav/mapdata/utils/locations.py:317 msgid "Level" msgstr "Etage" #: c3nav/editor/templates/editor/level.html:22 #: c3nav/editor/templates/editor/space.html:14 c3nav/editor/views/edit.py:495 +#: c3nav/site/templates/site/position_create.html:8 +#: c3nav/site/templates/site/position_detail.html:8 msgid "back to overview" msgstr "zurück zur Übersicht" @@ -1294,7 +1298,7 @@ msgid "Activate direct editing" msgstr "Direktes Bearbeiten aktivieren" #: c3nav/editor/templates/editor/user.html:54 c3nav/editor/views/account.py:85 -#: c3nav/site/templates/site/account.html:47 c3nav/site/views.py:298 +#: c3nav/site/templates/site/account.html:56 c3nav/site/views.py:303 msgid "Change password" msgstr "Passwort ändern" @@ -1315,11 +1319,11 @@ msgid "All recent change sets" msgstr "Alle kürzlichen Änderungssets" #: c3nav/editor/views/account.py:30 c3nav/editor/views/account.py:61 -#: c3nav/site/views.py:240 c3nav/site/views.py:275 +#: c3nav/site/views.py:245 c3nav/site/views.py:280 msgid "Create new account" msgstr "Neues Konto erstellen" -#: c3nav/editor/views/account.py:75 c3nav/site/views.py:289 +#: c3nav/editor/views/account.py:75 c3nav/site/views.py:294 msgid "Password successfully changed." msgstr "Passwort erfolgreich geändert." @@ -1508,12 +1512,12 @@ msgstr "Du hast direktes Bearbeiten aktiviert." msgid "You deactivated direct editing." msgstr "Du hast direktes Bearbeiten deaktiviert." -#: c3nav/mapdata/api.py:202 +#: c3nav/mapdata/api.py:201 #, python-format msgid "%(field)s is not an integer." msgstr "%(field)s ist keine ganze Zahl." -#: c3nav/mapdata/api.py:210 +#: c3nav/mapdata/api.py:209 #, python-format msgid "%(model)s not found." msgstr "%(model)s nicht gefunden." @@ -1696,9 +1700,9 @@ msgstr "Werte zurücksetzen" msgid "save result to the stats directory" msgstr "Ergebnis im stats-Ordner speichern" -#: c3nav/mapdata/models/access.py:23 c3nav/mapdata/models/report.py:65 -#: c3nav/mapdata/models/report.py:164 -#: c3nav/site/templates/site/report_detail.html:11 +#: c3nav/mapdata/models/access.py:23 c3nav/mapdata/models/report.py:35 +#: c3nav/mapdata/models/report.py:171 c3nav/site/forms.py:33 +#: c3nav/site/templates/site/report_detail.html:15 #: c3nav/site/templates/site/report_list.html:28 msgid "open" msgstr "offen" @@ -1743,8 +1747,8 @@ msgstr "Zugangserlaubnis-Token" msgid "Access Permission Tokens" msgstr "Zugangserlaubnis-Token" -#: c3nav/mapdata/models/access.py:133 c3nav/site/views.py:84 -#: c3nav/site/views.py:334 +#: c3nav/mapdata/models/access.py:133 c3nav/site/views.py:86 +#: c3nav/site/views.py:339 msgid "Area successfully unlocked." msgid_plural "Areas successfully unlocked." msgstr[0] "Bereich erfolgreich freigeschaltet." @@ -1758,28 +1762,28 @@ msgstr "Zugangserlaubnis-Token" msgid "Access Permission" msgstr "Zugangserlaubnis" -#: c3nav/mapdata/models/base.py:42 c3nav/mapdata/utils/locations.py:308 +#: c3nav/mapdata/models/base.py:42 c3nav/mapdata/utils/locations.py:314 msgid "Type" msgstr "Typ" -#: c3nav/mapdata/models/base.py:83 +#: c3nav/mapdata/models/base.py:87 #, python-brace-format msgid "Title ({lang})" msgstr "Titel ({lang})" -#: c3nav/mapdata/models/base.py:89 +#: c3nav/mapdata/models/base.py:93 msgid "bottom coordinate" msgstr "untere koordinate" -#: c3nav/mapdata/models/base.py:90 +#: c3nav/mapdata/models/base.py:94 msgid "left coordinate" msgstr "linke koordinate" -#: c3nav/mapdata/models/base.py:91 +#: c3nav/mapdata/models/base.py:95 msgid "top coordinate" msgstr "obere koordinate" -#: c3nav/mapdata/models/base.py:92 +#: c3nav/mapdata/models/base.py:96 msgid "right coordinate" msgstr "rechte koordinate" @@ -1915,7 +1919,7 @@ msgid "Area" msgstr "Bereich" #: c3nav/mapdata/models/geometry/space.py:124 -#: c3nav/mapdata/utils/locations.py:323 +#: c3nav/mapdata/utils/locations.py:329 msgid "Areas" msgstr "Bereiche" @@ -1996,7 +2000,7 @@ msgstr "Zielraum" #: c3nav/mapdata/models/geometry/space.py:308 #: c3nav/mapdata/models/geometry/space.py:347 c3nav/mapdata/models/graph.py:48 -#: c3nav/mapdata/models/report.py:69 +#: c3nav/mapdata/models/report.py:39 msgid "description" msgstr "Beschreibung" @@ -2021,7 +2025,7 @@ msgid "Cross descriptions" msgstr "Durchschreitungsbeschreibungen" #: c3nav/mapdata/models/geometry/space.py:386 -#: c3nav/mapdata/models/report.py:165 +#: c3nav/mapdata/models/report.py:172 msgid "comment" msgstr "Kommentar" @@ -2045,7 +2049,7 @@ msgstr "Graphknoten" msgid "Graph Nodes" msgstr "Graphknoten" -#: c3nav/mapdata/models/graph.py:39 c3nav/mapdata/models/locations.py:257 +#: c3nav/mapdata/models/graph.py:39 c3nav/mapdata/models/locations.py:266 msgid "Title (Plural)" msgstr "Titel (Plural)" @@ -2142,7 +2146,7 @@ msgid "default height" msgstr "Standarddeckenhöhe" #. Translators: "letters" means latin letters: a-z and A-Z. -#: c3nav/mapdata/models/locations.py:47 +#: c3nav/mapdata/models/locations.py:51 msgid "" "Enter a valid location slug consisting of lowercase letters, numbers or " "hyphens, not starting or ending with hyphens or containing consecutive " @@ -2152,257 +2156,285 @@ msgstr "" "Bindestrichen besteht und nicht mit einem Bindestrich beginnt oder endet " "oder aufeinanderfolgende Bindestriche enthält." -#: c3nav/mapdata/models/locations.py:62 c3nav/mapdata/models/locations.py:82 -#: c3nav/mapdata/utils/locations.py:310 +#: c3nav/mapdata/models/locations.py:66 c3nav/mapdata/models/locations.py:86 +#: c3nav/mapdata/utils/locations.py:316 msgid "Slug" msgstr "Slug" -#: c3nav/mapdata/models/locations.py:90 c3nav/mapdata/models/locations.py:91 +#: c3nav/mapdata/models/locations.py:94 c3nav/mapdata/models/locations.py:95 msgid "Location with Slug" msgstr "Ort mit Slug" -#: c3nav/mapdata/models/locations.py:96 +#: c3nav/mapdata/models/locations.py:100 msgid "can be searched" msgstr "zur Suche zugelassen" -#: c3nav/mapdata/models/locations.py:97 c3nav/mapdata/models/locations.py:123 +#: c3nav/mapdata/models/locations.py:101 c3nav/mapdata/models/locations.py:132 msgid "can describe" msgstr "beschreibend" -#: c3nav/mapdata/models/locations.py:98 c3nav/mapdata/models/locations.py:124 +#: c3nav/mapdata/models/locations.py:102 c3nav/mapdata/models/locations.py:133 msgid "icon" msgstr "Icon" -#: c3nav/mapdata/models/locations.py:98 +#: c3nav/mapdata/models/locations.py:102 msgid "any material icons name" msgstr "name eines material icons" -#: c3nav/mapdata/models/locations.py:122 +#: c3nav/mapdata/models/locations.py:131 msgid "searchable" msgstr "suchbar" -#: c3nav/mapdata/models/locations.py:162 c3nav/mapdata/models/locations.py:323 +#: c3nav/mapdata/models/locations.py:171 c3nav/mapdata/models/locations.py:332 msgid "Location Groups" msgstr "Ortgruppen" -#: c3nav/mapdata/models/locations.py:164 c3nav/mapdata/models/locations.py:313 +#: c3nav/mapdata/models/locations.py:173 c3nav/mapdata/models/locations.py:322 msgid "label settings" msgstr "Labeleinstellungen" -#: c3nav/mapdata/models/locations.py:165 +#: c3nav/mapdata/models/locations.py:174 msgid "Label override" msgstr "Label überschreiben" -#: c3nav/mapdata/models/locations.py:211 +#: c3nav/mapdata/models/locations.py:220 msgid "Grid Squares" msgstr "Planquadrate" -#: c3nav/mapdata/models/locations.py:211 c3nav/mapdata/utils/locations.py:329 +#: c3nav/mapdata/models/locations.py:220 c3nav/mapdata/utils/locations.py:335 msgid "Grid Square" msgstr "Planquadrat" -#: c3nav/mapdata/models/locations.py:254 c3nav/mapdata/models/source.py:15 +#: c3nav/mapdata/models/locations.py:263 c3nav/mapdata/models/source.py:15 msgid "Name" msgstr "Name" -#: c3nav/mapdata/models/locations.py:255 +#: c3nav/mapdata/models/locations.py:264 msgid "single selection" msgstr "nur eine Auswahl möglich" -#: c3nav/mapdata/models/locations.py:258 +#: c3nav/mapdata/models/locations.py:267 msgid "Help text" msgstr "Hilfehinweis" -#: c3nav/mapdata/models/locations.py:259 +#: c3nav/mapdata/models/locations.py:268 msgid "allow levels" msgstr "bei Etagen erlauben" -#: c3nav/mapdata/models/locations.py:260 +#: c3nav/mapdata/models/locations.py:269 msgid "allow spaces" msgstr "bei Räumen erlauben" -#: c3nav/mapdata/models/locations.py:261 +#: c3nav/mapdata/models/locations.py:270 msgid "allow areas" msgstr "bei Bereichen erlauben" -#: c3nav/mapdata/models/locations.py:262 +#: c3nav/mapdata/models/locations.py:271 msgid "allow pois" msgstr "bei POI erlauben" -#: c3nav/mapdata/models/locations.py:270 +#: c3nav/mapdata/models/locations.py:279 msgid "Location Group Category" msgstr "Ortgruppenkategorie" -#: c3nav/mapdata/models/locations.py:271 +#: c3nav/mapdata/models/locations.py:280 msgid "Location Group Categories" msgstr "Ortgruppenkategorien" -#: c3nav/mapdata/models/locations.py:309 c3nav/mapdata/models/locations.py:344 +#: c3nav/mapdata/models/locations.py:318 c3nav/mapdata/models/locations.py:353 msgid "Category" msgstr "Kategorie" -#: c3nav/mapdata/models/locations.py:311 +#: c3nav/mapdata/models/locations.py:320 msgid "hierarchy" msgstr "Hierarchie" -#: c3nav/mapdata/models/locations.py:314 +#: c3nav/mapdata/models/locations.py:323 msgid "unless location specifies otherwise" msgstr "kann von Orten überschrieben werden" -#: c3nav/mapdata/models/locations.py:315 +#: c3nav/mapdata/models/locations.py:324 msgid "for missing locations" msgstr "für fehlende Orte" -#: c3nav/mapdata/models/locations.py:316 +#: c3nav/mapdata/models/locations.py:325 msgid "can be used when reporting a missing location" msgstr "kann beim melden eines fehlenden Ortges genutzt werden" -#: c3nav/mapdata/models/locations.py:317 +#: c3nav/mapdata/models/locations.py:326 msgid "background color" msgstr "Hintergrundfarbe" -#: c3nav/mapdata/models/locations.py:322 +#: c3nav/mapdata/models/locations.py:331 msgid "Location Group" msgstr "Ortgruppe" -#: c3nav/mapdata/models/locations.py:346 c3nav/mapdata/models/locations.py:361 +#: c3nav/mapdata/models/locations.py:355 c3nav/mapdata/models/locations.py:370 msgid "color" msgstr "Farbe" -#: c3nav/mapdata/models/locations.py:347 +#: c3nav/mapdata/models/locations.py:356 msgid "priority" msgstr "Priorität" -#: c3nav/mapdata/models/locations.py:357 +#: c3nav/mapdata/models/locations.py:366 msgid "search" msgstr "suchen" -#: c3nav/mapdata/models/locations.py:359 +#: c3nav/mapdata/models/locations.py:368 msgid "describe" msgstr "beschreiben" -#: c3nav/mapdata/models/locations.py:363 +#: c3nav/mapdata/models/locations.py:372 msgid "internal" msgstr "intern" -#: c3nav/mapdata/models/locations.py:380 +#: c3nav/mapdata/models/locations.py:389 #, python-brace-format msgid "{category_title}, {num_locations}" msgstr "{category_title}, {num_locations}" -#: c3nav/mapdata/models/locations.py:382 +#: c3nav/mapdata/models/locations.py:391 #, python-format msgid "%(num)d location" msgid_plural "%(num)d locations" msgstr[0] "%(num)d Ort" msgstr[1] "%(num)d Orte" -#: c3nav/mapdata/models/locations.py:405 +#: c3nav/mapdata/models/locations.py:414 msgid "target" msgstr "Ziel" -#: c3nav/mapdata/models/locations.py:424 +#: c3nav/mapdata/models/locations.py:433 msgid "min zoom" msgstr "Mindestzoom" -#: c3nav/mapdata/models/locations.py:427 +#: c3nav/mapdata/models/locations.py:436 msgid "max zoom" msgstr "Maximalzoom" -#: c3nav/mapdata/models/locations.py:430 +#: c3nav/mapdata/models/locations.py:439 msgid "font size" msgstr "Schriftgröße" -#: c3nav/mapdata/models/locations.py:446 c3nav/mapdata/models/locations.py:447 +#: c3nav/mapdata/models/locations.py:455 c3nav/mapdata/models/locations.py:456 msgid "Label Settings" msgstr "Labeleinstellungen" -#: c3nav/mapdata/models/report.py:58 -msgid "location issue" -msgstr "Ortfehler" +#: c3nav/mapdata/models/locations.py:462 +msgid "position secret" +msgstr "position secret" -#: c3nav/mapdata/models/report.py:59 -msgid "missing location" -msgstr "fehlender Ort" +#: c3nav/mapdata/models/locations.py:465 +msgid "Dynamic location" +msgstr "Dynamischer Ort." -#: c3nav/mapdata/models/report.py:60 -msgid "route issue" -msgstr "Routenfehler" +#: c3nav/mapdata/models/locations.py:466 +msgid "Dynamic locations" +msgstr "Dynamische Orte." -#: c3nav/mapdata/models/report.py:63 -msgid "category" -msgstr "Kategorie" +#: c3nav/mapdata/models/locations.py:496 +msgid "name" +msgstr "Name" -#: c3nav/mapdata/models/report.py:66 -msgid "last_update" -msgstr "letzte Anderung" +#: c3nav/mapdata/models/locations.py:498 +msgid "last location update" +msgstr "Letzte Ortänderung" -#: c3nav/mapdata/models/report.py:67 -msgid "title" -msgstr "Titel" - -#: c3nav/mapdata/models/report.py:68 -msgid "a short title for your report" -msgstr "ein kurzer Titel für deine Meldung" - -#: c3nav/mapdata/models/report.py:70 -msgid "tell us precisely what's wrong" -msgstr "Sag uns im Detail was falsch ist" - -#: c3nav/mapdata/models/report.py:74 +#: c3nav/mapdata/models/locations.py:499 c3nav/mapdata/models/report.py:44 msgid "location" msgstr "Ort" -#: c3nav/mapdata/models/report.py:75 +#: c3nav/mapdata/models/locations.py:500 +msgid "api secret" +msgstr "API secret" + +#: c3nav/mapdata/models/locations.py:505 c3nav/mapdata/models/locations.py:506 +msgid "Dynamic position" +msgstr "Dynamische Position" + +#: c3nav/mapdata/models/report.py:28 +msgid "location issue" +msgstr "Ortfehler" + +#: c3nav/mapdata/models/report.py:29 +msgid "missing location" +msgstr "fehlender Ort" + +#: c3nav/mapdata/models/report.py:30 +msgid "route issue" +msgstr "Routenfehler" + +#: c3nav/mapdata/models/report.py:33 +msgid "category" +msgstr "Kategorie" + +#: c3nav/mapdata/models/report.py:36 +msgid "last_update" +msgstr "letzte Anderung" + +#: c3nav/mapdata/models/report.py:37 +msgid "title" +msgstr "Titel" + +#: c3nav/mapdata/models/report.py:38 +msgid "a short title for your report" +msgstr "ein kurzer Titel für deine Meldung" + +#: c3nav/mapdata/models/report.py:40 +msgid "tell us precisely what's wrong" +msgstr "Sag uns im Detail was falsch ist" + +#: c3nav/mapdata/models/report.py:45 msgid "coordinates" msgstr "Koordinaten" -#: c3nav/mapdata/models/report.py:76 +#: c3nav/mapdata/models/report.py:46 msgid "origin" msgstr "Start" -#: c3nav/mapdata/models/report.py:77 +#: c3nav/mapdata/models/report.py:47 msgid "destination" msgstr "Ziel" -#: c3nav/mapdata/models/report.py:78 +#: c3nav/mapdata/models/report.py:48 msgid "route options" msgstr "Routenoptionen" -#: c3nav/mapdata/models/report.py:80 +#: c3nav/mapdata/models/report.py:50 msgid "new location title" msgstr "Neuer Ortstitel" -#: c3nav/mapdata/models/report.py:81 +#: c3nav/mapdata/models/report.py:51 msgid "you have to supply a title in at least one language" msgstr "Du musst einen Titel in mindestens einer Sprache angeben" -#: c3nav/mapdata/models/report.py:82 +#: c3nav/mapdata/models/report.py:52 msgid "location groups" msgstr "Ortgruppen" -#: c3nav/mapdata/models/report.py:84 +#: c3nav/mapdata/models/report.py:54 msgid "select all groups that apply, if any" msgstr "wähle zutreffende Gruppen aus" -#: c3nav/mapdata/models/report.py:92 +#: c3nav/mapdata/models/report.py:62 #: c3nav/site/templates/site/report_detail.html:7 msgid "Report" msgstr "Meldung" -#: c3nav/mapdata/models/report.py:93 +#: c3nav/mapdata/models/report.py:63 msgid "Reports" msgstr "Meldungen" -#: c3nav/mapdata/models/report.py:168 -msgid "public" -msgstr "öffentlich" +#: c3nav/mapdata/models/report.py:175 +msgid "comment is public" +msgstr "Kommentar ist öffentlich" -#: c3nav/mapdata/models/report.py:171 +#: c3nav/mapdata/models/report.py:178 msgid "Report update" msgstr "Meldungsupdate" -#: c3nav/mapdata/models/report.py:172 +#: c3nav/mapdata/models/report.py:179 msgid "Report updates" msgstr "Meldungsupdates" @@ -2442,60 +2474,60 @@ msgstr[1] "%d Kartenänderungen verarbeitet." msgid "Last processed update: %(date)s (#%(id)d)" msgstr "Letztes verarbeitetes Update: %(date)s (#%(id)d)" -#: c3nav/mapdata/utils/locations.py:308 +#: c3nav/mapdata/utils/locations.py:314 msgid "Coordinates" msgstr "Koordinaten" -#: c3nav/mapdata/utils/locations.py:330 +#: c3nav/mapdata/utils/locations.py:336 msgid "Near Area" msgstr "Naher Bereich" -#: c3nav/mapdata/utils/locations.py:336 +#: c3nav/mapdata/utils/locations.py:342 msgid "Near POI" msgstr "Naher POI" -#: c3nav/mapdata/utils/locations.py:342 +#: c3nav/mapdata/utils/locations.py:348 msgid "X Coordinate" msgstr "X-Koordinate" -#: c3nav/mapdata/utils/locations.py:343 +#: c3nav/mapdata/utils/locations.py:349 msgid "Y Coordinate" msgstr "Y-Koordinate" -#: c3nav/mapdata/utils/locations.py:344 +#: c3nav/mapdata/utils/locations.py:350 msgid "Altitude" msgstr "Höhe" -#: c3nav/mapdata/utils/locations.py:346 +#: c3nav/mapdata/utils/locations.py:352 msgid "Subtitle" msgstr "Untertitel" -#: c3nav/mapdata/utils/locations.py:395 +#: c3nav/mapdata/utils/locations.py:401 #, python-format msgid "In %(level)s" msgstr "In %(level)s" -#: c3nav/mapdata/utils/locations.py:401 +#: c3nav/mapdata/utils/locations.py:407 #, python-format msgid "Near %(poi)s" msgstr "Nahe %(poi)s" -#: c3nav/mapdata/utils/locations.py:405 +#: c3nav/mapdata/utils/locations.py:411 #, python-format msgid "near %(area)s" msgstr "nahe %(area)s" -#: c3nav/mapdata/utils/locations.py:407 +#: c3nav/mapdata/utils/locations.py:413 #, python-format msgid "In %(area)s" msgstr "In %(area)s" -#: c3nav/mapdata/utils/locations.py:411 +#: c3nav/mapdata/utils/locations.py:417 #, python-format msgid "Near %(area)s" msgstr "Nahe %(area)s" -#: c3nav/mapdata/utils/locations.py:413 +#: c3nav/mapdata/utils/locations.py:419 #, python-format msgid "In %(space)s" msgstr "In %(space)s" @@ -2539,45 +2571,45 @@ msgstr "Unbekannter Startort." msgid "Unknown destination." msgstr "Unbekannter Zielort." -#: c3nav/routing/locator.py:208 +#: c3nav/routing/locator.py:213 msgid "Invalid Scan. Scans list list not a list." msgstr "Invalider Scan. Scan List Liste ist keine Liste." -#: c3nav/routing/locator.py:214 +#: c3nav/routing/locator.py:219 msgid "Invalid Scan. Scan not a list." msgstr "Invalider Scan. Scan is keine Liste." -#: c3nav/routing/locator.py:227 +#: c3nav/routing/locator.py:232 msgid "Invalid Scan. Scan value not a dictionary." msgstr "Invalider Scan. Scan wert ist kein Dictonary." -#: c3nav/routing/locator.py:230 +#: c3nav/routing/locator.py:235 msgid "Invalid Scan. Missing or forbidden keys." msgstr "Invalider Scan. Fehlender oder Falscher Key." -#: c3nav/routing/locator.py:232 +#: c3nav/routing/locator.py:237 msgid "Invalid Scan. BSSID not a String." msgstr "Invalider Scan. BSSID ist kein String." -#: c3nav/routing/locator.py:235 +#: c3nav/routing/locator.py:240 msgid "Invalid Scan. Invalid BSSID." msgstr "Invalider Scan. Ungültige BSSID." -#: c3nav/routing/locator.py:237 +#: c3nav/routing/locator.py:242 msgid "Invalid Scan. Invalid RSSI/Level." msgstr "Invalider Scan. Ungültiger RSSI." -#: c3nav/routing/locator.py:239 +#: c3nav/routing/locator.py:244 msgid "Invalid Scan. Not an allowed frequency." msgstr "Invalider Scan. Unerlaubte Frequenz." -#: c3nav/routing/locator.py:241 +#: c3nav/routing/locator.py:246 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/fragment_report_meta.html:17 -#: c3nav/site/templates/site/map.html:189 +#: c3nav/site/templates/site/fragment_report_meta.html:29 +#: c3nav/site/templates/site/map.html:196 msgid "Route options" msgstr "Routenoptionen" @@ -2669,14 +2701,27 @@ msgstr "einige Wegtypen vermieden" msgid "default options" msgstr "Standardoptionen" -#: c3nav/settings.py:304 +#: c3nav/settings.py:308 msgid "English" msgstr "Englisch" -#: c3nav/settings.py:305 +#: c3nav/settings.py:309 msgid "German" msgstr "Deutsch" +#: c3nav/site/forms.py:30 +msgid "change status" +msgstr "Status ändern" + +#: c3nav/site/forms.py:32 +msgid "don't change" +msgstr "nicht ändern" + +#: c3nav/site/forms.py:34 c3nav/site/templates/site/report_detail.html:17 +#: c3nav/site/templates/site/report_list.html:30 +msgid "closed" +msgstr "geschlossen" + #: c3nav/site/models.py:15 msgid "active until" msgstr "aktiv bis" @@ -2794,23 +2839,42 @@ msgstr "Du hast Meldungen eingereicht." msgid "Show your reports" msgstr "Deine Meldungen anzeigen" +#: c3nav/site/templates/site/account.html:47 +msgid "You can create custom positions." +msgstr "Du kannst benutzerdefinierte Positionen erstellen." + +#: c3nav/site/templates/site/account.html:50 +msgid "Manage your positions" +msgstr "Positionen verwalten" + #: c3nav/site/templates/site/fragment_report_meta.html:3 msgid "You are reporting an issue with the following location:" msgstr "Du meldest einen Fehler beim folgenden Ort:" #: c3nav/site/templates/site/fragment_report_meta.html:6 +#: c3nav/site/templates/site/fragment_report_meta.html:15 +#: c3nav/site/templates/site/map.html:216 +msgid "open in c3nav" +msgstr "in c3nav öffnen" + +#: c3nav/site/templates/site/fragment_report_meta.html:8 +#: c3nav/site/templates/site/fragment_report_meta.html:17 +msgid "open in editor" +msgstr "Im Editor öffnen" + +#: c3nav/site/templates/site/fragment_report_meta.html:12 msgid "You are reporting an missing location at the following position:" msgstr "Du meldest einen fehlenden Ort an der folgenden Stelle:" -#: c3nav/site/templates/site/fragment_report_meta.html:9 +#: c3nav/site/templates/site/fragment_report_meta.html:21 msgid "You are reporting an issue with the following route:" msgstr "Du meldest einen Fehler bei der folgenden Route:" -#: c3nav/site/templates/site/fragment_report_meta.html:11 +#: c3nav/site/templates/site/fragment_report_meta.html:23 msgid "Origin" msgstr "Start" -#: c3nav/site/templates/site/fragment_report_meta.html:14 +#: c3nav/site/templates/site/fragment_report_meta.html:26 msgid "Destination" msgstr "Ziel" @@ -2842,84 +2906,86 @@ msgstr "Diesen Punkt zeigen" msgid "Show nearby locations" msgstr "Nahegelegene Orte zeigen" -#: c3nav/site/templates/site/map.html:50 +#: c3nav/site/templates/site/map.html:48 c3nav/site/templates/site/map.html:74 +#: c3nav/site/templates/site/map.html:172 +msgid "Report missing location" +msgstr "Fehlenden Ort melden" + +#: c3nav/site/templates/site/map.html:56 msgid "Select" msgstr "Auswählen" -#: c3nav/site/templates/site/map.html:54 c3nav/site/templates/site/map.html:73 -#: c3nav/site/templates/site/map.html:116 +#: c3nav/site/templates/site/map.html:60 c3nav/site/templates/site/map.html:79 +#: c3nav/site/templates/site/map.html:123 msgid "Share" msgstr "Teilen" -#: c3nav/site/templates/site/map.html:58 +#: c3nav/site/templates/site/map.html:64 msgid "from here" msgstr "von hier" -#: c3nav/site/templates/site/map.html:59 +#: c3nav/site/templates/site/map.html:65 msgid "to here" msgstr "hierhin" -#: c3nav/site/templates/site/map.html:64 c3nav/site/templates/site/map.html:161 -#: c3nav/site/templates/site/map.html:182 +#: c3nav/site/templates/site/map.html:70 c3nav/site/templates/site/map.html:168 +#: c3nav/site/templates/site/map.html:189 #: c3nav/site/templates/site/report_create.html:6 msgid "Report issue" msgstr "Fehler melden" -#: c3nav/site/templates/site/map.html:68 c3nav/site/templates/site/map.html:165 -msgid "Report missing location" -msgstr "Fehlenden Ort melden" - -#: c3nav/site/templates/site/map.html:77 +#: c3nav/site/templates/site/map.html:83 msgid "share" msgstr "Teilen" -#: c3nav/site/templates/site/map.html:78 +#: c3nav/site/templates/site/map.html:84 msgid "create shortcut" msgstr "Verknüpfung anlegen" -#: c3nav/site/templates/site/map.html:82 +#: c3nav/site/templates/site/map.html:88 msgid "Wifi-based location" msgstr "WLAN-basierte Ortung" -#: c3nav/site/templates/site/map.html:83 +#: c3nav/site/templates/site/map.html:89 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:86 +#: c3nav/site/templates/site/map.html:92 msgid "Download APK" msgstr "APK herunterladen" -#: c3nav/site/templates/site/map.html:96 c3nav/site/templates/site/map.html:103 +#: c3nav/site/templates/site/map.html:102 +#: c3nav/site/templates/site/map.html:109 msgid "Search any location…" msgstr "Suche einen beliebigen Ort…" -#: c3nav/site/templates/site/map.html:120 +#: c3nav/site/templates/site/map.html:127 msgid "Route" msgstr "Route" -#: c3nav/site/templates/site/map.html:132 -#: c3nav/site/templates/site/map.html:142 +#: c3nav/site/templates/site/map.html:139 +#: c3nav/site/templates/site/map.html:149 msgid "Swap" msgstr "Vertauschen" -#: c3nav/site/templates/site/map.html:136 +#: c3nav/site/templates/site/map.html:143 msgid "Close" msgstr "Schließen" -#: c3nav/site/templates/site/map.html:169 +#: c3nav/site/templates/site/map.html:176 msgid "Open in Editor" msgstr "Im Editor öffnen" -#: c3nav/site/templates/site/map.html:194 +#: c3nav/site/templates/site/map.html:201 msgid "Save and reroute" msgstr "Speichern und neu routen" -#: c3nav/site/templates/site/map.html:195 +#: c3nav/site/templates/site/map.html:202 msgid "Just reroute" msgstr "Nur neu routen" -#: c3nav/site/templates/site/map.html:204 +#: c3nav/site/templates/site/map.html:211 #, python-format msgid "" "Get the c3nav Android app on Google Play oder downloade " "die APK!" -#: c3nav/site/templates/site/map.html:209 -msgid "open in c3nav" -msgstr "in c3nav öffnen" +#: c3nav/site/templates/site/position_create.html:6 +#: c3nav/site/templates/site/position_list.html:16 +msgid "Create position" +msgstr "Position erstellen" +#: c3nav/site/templates/site/position_create.html:13 #: c3nav/site/templates/site/report_create.html:13 +#: c3nav/site/templates/site/report_detail.html:79 msgid "Submit" msgstr "Absenden" -#: c3nav/site/templates/site/report_detail.html:13 -#: c3nav/site/templates/site/report_list.html:30 -msgid "closed" -msgstr "geschlossen" +#: c3nav/site/templates/site/position_detail.html:7 +msgid "Position:" +msgstr "Position:" -#: c3nav/site/templates/site/report_detail.html:17 +#: c3nav/site/templates/site/position_detail.html:11 +msgid "Secret" +msgstr "Secret" + +#: c3nav/site/templates/site/position_detail.html:24 +msgid "reset secret" +msgstr "Secret zurücksetzen" + +#: c3nav/site/templates/site/position_detail.html:25 +msgid "reset API secret" +msgstr "API Secret zurücksetzen" + +#: c3nav/site/templates/site/position_detail.html:26 +msgid "delete this position" +msgstr "diese Position löschen" + +#: c3nav/site/templates/site/position_detail.html:27 +msgid "Update position" +msgstr "Position speichern" + +#: c3nav/site/templates/site/position_list.html:7 +msgid "Your positions" +msgstr "Deine Positionsn" + +#: c3nav/site/templates/site/report_detail.html:9 +#: c3nav/site/templates/site/report_list.html:9 +msgid "show all reports" +msgstr "alle Meldungen anzeigen" + +#: c3nav/site/templates/site/report_detail.html:10 +#: c3nav/site/templates/site/report_list.html:12 +msgid "show open reports" +msgstr "offene Meldungen anzeigen" + +#: c3nav/site/templates/site/report_detail.html:21 msgid "by" msgstr "von" -#: c3nav/site/templates/site/report_detail.html:19 +#: c3nav/site/templates/site/report_detail.html:23 msgid "anonymous submission" msgstr "anonyme Meldung" -#: c3nav/site/templates/site/report_detail.html:25 +#: c3nav/site/templates/site/report_detail.html:29 msgid "public URL to this report" msgstr "öffentliche URL zu dieser Meldung" -#: c3nav/site/templates/site/report_detail.html:39 +#: c3nav/site/templates/site/report_detail.html:43 msgid "(none)" msgstr "(keine)" +#: c3nav/site/templates/site/report_detail.html:57 +msgid "Issue was opened." +msgstr "Meldung wurde geöffnet." + +#: c3nav/site/templates/site/report_detail.html:59 +msgid "Issue was closed." +msgstr "Meldung wurde geschlossen." + +#: c3nav/site/templates/site/report_detail.html:66 +msgid "(public)" +msgstr "(öffentlich)" + +#: c3nav/site/templates/site/report_detail.html:77 +msgid "Update issue" +msgstr "Meldung updaten" + #: c3nav/site/templates/site/report_list.html:8 msgid "Open reports" msgstr "Offene Meldungen" -#: c3nav/site/templates/site/report_list.html:9 -msgid "show all reports" -msgstr "alle Meldungen anzeigen" - #: c3nav/site/templates/site/report_list.html:11 msgid "All reports" msgstr "Alle Meldungen" -#: c3nav/site/templates/site/report_list.html:12 -msgid "show open reports" -msgstr "offene Meldungen anzeigen" - #: c3nav/site/templates/site/report_list.html:20 msgid "State" msgstr "Status" -#: c3nav/site/views.py:76 c3nav/site/views.py:326 +#: c3nav/site/views.py:78 c3nav/site/views.py:331 msgid "You need to log in to unlock areas." msgstr "Du musst dich anmelden um Bereiche freizuschalten." -#: c3nav/site/views.py:212 +#: c3nav/site/views.py:217 msgid "Areas could not be unlocked because the token has expired." msgstr "" "Zugangserlaubnis konnte nicht gewährt werden weil der Code abgelaufen ist." -#: c3nav/site/views.py:255 +#: c3nav/site/views.py:260 msgid "account creation is currently disabled." msgstr "Benutzerregistrierung ist momentan deaktiviert." -#: c3nav/site/views.py:319 +#: c3nav/site/views.py:324 msgid "This token does not exist or was already redeemed." msgstr "Dieser Code existiert nicht oder wurde bereits eingelöst." -#: c3nav/site/views.py:339 +#: c3nav/site/views.py:344 msgid "Unlock area" msgid_plural "Unlock areas" msgstr[0] "Bereich freischalten" msgstr[1] "Bereiche freischalten" -#: c3nav/site/views.py:340 +#: c3nav/site/views.py:345 msgid "You have been invited to unlock the following area:" msgid_plural "You have been invited to unlock the following areas:" msgstr[0] "Du wurdest eingeladen, den folgenden Bereich freizuschalten:" msgstr[1] "Du wurdest eingeladen, die folgenden Bereiche freizuschalten:" -#: c3nav/site/views.py:412 +#: c3nav/site/views.py:418 msgid "Your report was submitted." msgstr "Deine Meldung wurde abgesendet." -#: c3nav/site/views.py:415 +#: c3nav/site/views.py:421 msgid "You can keep track of it from your user dashboard." msgstr "Du kannst sie in deinerm Benutzerdashboard verfolgen." -#: c3nav/site/views.py:417 +#: c3nav/site/views.py:423 msgid "You can keep track of it by revisiting the public URL mentioned below." msgstr "Du kannst sie mit dem unten angegebenen öffentlichen link verfolgen." +#: c3nav/site/views.py:474 +msgid "Report updated." +msgstr "Meldung aktualisiert." + +#: c3nav/site/views.py:498 +msgid "You can't create more than 20 positions." +msgstr "Du kannst nicht mehr als 20 Positionen erstellen." + +#: c3nav/site/views.py:507 +msgid "Position created." +msgstr "Position erstellt." + +#: c3nav/site/views.py:527 +msgid "Position deleted." +msgstr "Position gelöscht." + +#: c3nav/site/views.py:539 +msgid "Position updated." +msgstr "Position geändert." + #~ msgid "Coming soon" #~ msgstr "Coming soon" diff --git a/src/c3nav/mapdata/migrations/0082_dynamiclocation_position.py b/src/c3nav/mapdata/migrations/0082_dynamiclocation_position.py new file mode 100644 index 00000000..2ef2ee48 --- /dev/null +++ b/src/c3nav/mapdata/migrations/0082_dynamiclocation_position.py @@ -0,0 +1,56 @@ +# Generated by Django 2.2.8 on 2019-12-27 12:51 + +import c3nav.mapdata.fields +import c3nav.mapdata.models.locations +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('mapdata', '0081_auto_20191225_1015'), + ] + + operations = [ + migrations.CreateModel( + name='Position', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32, verbose_name='name')), + ('secret', models.CharField(default=c3nav.mapdata.models.locations.get_position_secret, max_length=32, unique=True, verbose_name='secret')), + ('last_location_update', models.DateTimeField(null=True, verbose_name='last location update')), + ('location_id', models.CharField(max_length=48, null=True, verbose_name='location')), + ('api_secret', models.CharField(default=c3nav.mapdata.models.locations.get_position_api_secret, max_length=64, verbose_name='api secret')), + ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dynamic_positions', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Dynamic position', + 'verbose_name_plural': 'Dynamic position', + 'default_related_name': 'dynamic_positions', + }, + ), + migrations.CreateModel( + name='DynamicLocation', + fields=[ + ('locationslug_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='dynamic_locations', serialize=False, to='mapdata.LocationSlug')), + ('title', c3nav.mapdata.fields.I18nField(blank=True, fallback_any=True, fallback_value='{model} {pk}', plural_name='titles', verbose_name='Title')), + ('can_search', models.BooleanField(default=True, verbose_name='can be searched')), + ('can_describe', models.BooleanField(default=True, verbose_name='can describe')), + ('icon', models.CharField(blank=True, help_text='any material icons name', max_length=32, null=True, verbose_name='icon')), + ('label_override', c3nav.mapdata.fields.I18nField(blank=True, fallback_any=True, plural_name='label_overrides', verbose_name='Label override')), + ('position_secret', models.CharField(blank=True, max_length=32, null=True, verbose_name='position secret')), + ('access_restriction', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='dynamic_locations', to='mapdata.AccessRestriction', verbose_name='Access Restriction')), + ('groups', models.ManyToManyField(blank=True, related_name='dynamic_locations', to='mapdata.LocationGroup', verbose_name='Location Groups')), + ('label_settings', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='dynamic_locations', to='mapdata.LabelSettings', verbose_name='label settings')), + ], + options={ + 'verbose_name': 'Dynamic location', + 'verbose_name_plural': 'Dynamic locations', + 'default_related_name': 'dynamic_locations', + }, + bases=('mapdata.locationslug', models.Model), + ), + ] diff --git a/src/c3nav/mapdata/models/locations.py b/src/c3nav/mapdata/models/locations.py index 5174c949..b0b492e7 100644 --- a/src/c3nav/mapdata/models/locations.py +++ b/src/c3nav/mapdata/models/locations.py @@ -1,11 +1,14 @@ +import string from contextlib import suppress from decimal import Decimal from operator import attrgetter +from django.conf import settings from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator from django.db import models from django.db.models import FieldDoesNotExist, Prefetch from django.urls import reverse +from django.utils.crypto import get_random_string from django.utils.functional import cached_property from django.utils.text import format_lazy from django.utils.translation import ugettext_lazy as _ @@ -15,6 +18,7 @@ from c3nav.mapdata.fields import I18nField from c3nav.mapdata.grid import grid from c3nav.mapdata.models.access import AccessRestrictionMixin from c3nav.mapdata.models.base import SerializableMixin, TitledMixin +from c3nav.mapdata.utils.fields import LocationById from c3nav.mapdata.utils.models import get_submodels @@ -452,3 +456,52 @@ class LabelSettings(SerializableMixin, models.Model): verbose_name_plural = _('Label Settings') default_related_name = 'labelsettings' ordering = ('min_zoom', '-font_size') + + +class DynamicLocation(SpecificLocation, models.Model): + position_secret = models.CharField(_('position secret'), max_length=32, null=True, blank=True) + + class Meta: + verbose_name = _('Dynamic location') + verbose_name_plural = _('Dynamic locations') + default_related_name = 'dynamic_locations' + + """ + def _serialize(self, **kwargs): + result = super()._serialize(**kwargs) + return result + + @property + def grid_square(self): + return grid.get_squares_for_bounds(self.geometry.bounds) or '' + + def details_display(self, editor_url=True, **kwargs): + result = super().details_display(**kwargs) + if editor_url: + result['editor_url'] = reverse('editor.areas.edit', kwargs={'space': self.space_id, 'pk': self.pk}) + return result + """ + + +def get_position_secret(): + return get_random_string(32, string.ascii_letters+string.digits) + + +def get_position_api_secret(): + return get_random_string(64, string.ascii_letters+string.digits) + + +class Position(models.Model): + owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + name = models.CharField(_('name'), max_length=32) + secret = models.CharField(_('secret'), unique=True, max_length=32, default=get_position_secret) + last_location_update = models.DateTimeField(_('last location update'), null=True) + location_id = models.CharField(_('location'), null=True, max_length=48) + api_secret = models.CharField(_('api secret'), max_length=64, default=get_position_api_secret) + + coordinates = LocationById() + + class Meta: + verbose_name = _('Dynamic position') + verbose_name_plural = _('Dynamic position') + default_related_name = 'dynamic_positions' diff --git a/src/c3nav/mapdata/models/report.py b/src/c3nav/mapdata/models/report.py index ce63a9c7..0aa73ca2 100644 --- a/src/c3nav/mapdata/models/report.py +++ b/src/c3nav/mapdata/models/report.py @@ -3,7 +3,6 @@ import string from django.conf import settings from django.contrib.auth import get_user_model from django.core.cache import cache -from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.db.models import Q from django.urls import reverse @@ -15,7 +14,7 @@ from c3nav.mapdata.fields import I18nField from c3nav.mapdata.models.geometry.level import LevelGeometryMixin from c3nav.mapdata.models.geometry.space import SpaceGeometryMixin from c3nav.mapdata.models.locations import SpecificLocation -from c3nav.mapdata.utils.locations import get_location_by_id_for_request +from c3nav.mapdata.utils.fields import LocationById from c3nav.mapdata.utils.models import get_submodels from c3nav.site.tasks import send_report_notification @@ -24,39 +23,6 @@ def get_report_secret(): return get_random_string(32, string.ascii_letters) -class LocationById(): - def __init__(self): - super().__init__() - self.name = None - self.cached_id = None - self.cached_value = None - - def __set_name__(self, owner, name): - self.name = name - - def __get__(self, instance, owner=None): - value_id = getattr(instance, self.name+'_id') - if value_id is None: - self.cached_pk = None - self.cached_value = None - return None - - if value_id == self.cached_id: - return self.cached_value - - value = get_location_by_id_for_request(value_id, getattr(instance, 'request', None)) - if value is None: - raise ObjectDoesNotExist - self.cached_id = value_id - self.cached_value = value - return value - - def __set__(self, instance, value): - self.cached_id = value.pk - self.cached_value = value - setattr(instance, self.name+'_id', value.pk) - - class Report(models.Model): CATEGORIES = ( ('location-issue', _('location issue')), diff --git a/src/c3nav/mapdata/utils/fields.py b/src/c3nav/mapdata/utils/fields.py new file mode 100644 index 00000000..9cb19d14 --- /dev/null +++ b/src/c3nav/mapdata/utils/fields.py @@ -0,0 +1,35 @@ +from django.core.exceptions import ObjectDoesNotExist + + +class LocationById(): + def __init__(self): + super().__init__() + self.name = None + self.cached_id = None + self.cached_value = None + + def __set_name__(self, owner, name): + self.name = name + + def __get__(self, instance, owner=None): + value_id = getattr(instance, self.name+'_id') + if value_id is None: + self.cached_pk = None + self.cached_value = None + return None + + if value_id == self.cached_id: + return self.cached_value + + from c3nav.mapdata.utils.locations import get_location_by_id_for_request + value = get_location_by_id_for_request(value_id, getattr(instance, 'request', None)) + if value is None: + raise ObjectDoesNotExist + self.cached_id = value_id + self.cached_value = value + return value + + def __set__(self, instance, value): + self.cached_id = value.pk + self.cached_value = value + setattr(instance, self.name+'_id', value.pk) diff --git a/src/c3nav/site/forms.py b/src/c3nav/site/forms.py index 9481c9fc..45489819 100644 --- a/src/c3nav/site/forms.py +++ b/src/c3nav/site/forms.py @@ -3,6 +3,7 @@ from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ from c3nav.mapdata.forms import I18nModelFormMixin +from c3nav.mapdata.models.locations import Position from c3nav.mapdata.models.report import Report, ReportUpdate @@ -46,3 +47,9 @@ class ReportUpdateForm(ModelForm): class Meta: model = ReportUpdate fields = ['open', 'comment', 'public'] + + +class PositionForm(ModelForm): + class Meta: + model = Position + fields = ['name'] diff --git a/src/c3nav/site/templates/site/account.html b/src/c3nav/site/templates/site/account.html index 574ced43..24737cb4 100644 --- a/src/c3nav/site/templates/site/account.html +++ b/src/c3nav/site/templates/site/account.html @@ -41,6 +41,15 @@

{% endif %} +
+ +

+ {% trans 'You can create custom positions.' %} +

+

+ {% trans 'Manage your positions' %} +

+

{% trans 'Log out' %} diff --git a/src/c3nav/site/templates/site/position_create.html b/src/c3nav/site/templates/site/position_create.html new file mode 100644 index 00000000..0da7b8f2 --- /dev/null +++ b/src/c3nav/site/templates/site/position_create.html @@ -0,0 +1,16 @@ +{% extends 'site/base.html' %} +{% load i18n %} + +{% block content %} +

+

{% trans 'Create position' %}

+ {% include 'site/fragment_messages.html' %} +

« {% trans 'back to overview' %}

+ +
+ {% csrf_token %} + {{ form.as_p }} + +
+
+{% endblock %} diff --git a/src/c3nav/site/templates/site/position_detail.html b/src/c3nav/site/templates/site/position_detail.html new file mode 100644 index 00000000..9ca3d8d9 --- /dev/null +++ b/src/c3nav/site/templates/site/position_detail.html @@ -0,0 +1,30 @@ +{% extends 'site/base.html' %} +{% load i18n %} + +{% block content %} +
+ {% include 'site/fragment_messages.html' %} +

{% trans 'Position:' %} {{ position.name }}

+

« {% trans 'back to overview' %}

+ +

+ {% trans 'Secret' %}: + {{ position.secret }} +

+

+ {% trans 'API secret' %}: + {{ position.api_secret }} +

+ +
+ +
+ {% csrf_token %} + {{ form.as_p }} + + + + +
+
+{% endblock %} diff --git a/src/c3nav/site/templates/site/position_list.html b/src/c3nav/site/templates/site/position_list.html new file mode 100644 index 00000000..ac8d4609 --- /dev/null +++ b/src/c3nav/site/templates/site/position_list.html @@ -0,0 +1,18 @@ +{% extends 'site/base.html' %} +{% load i18n %} + +{% block content %} +
+ {% include 'site/fragment_messages.html' %} +

{% trans 'Your positions' %}

+

(still work in progress, stay tuned for more information)

+ + + + {% trans 'Create position' %} +
+{% endblock %} diff --git a/src/c3nav/site/urls.py b/src/c3nav/site/urls.py index 5f102c9a..1e957aa4 100644 --- a/src/c3nav/site/urls.py +++ b/src/c3nav/site/urls.py @@ -1,8 +1,8 @@ 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, report_create, report_detail, - report_list) + login_view, logout_view, map_index, position_create, position_detail, position_list, + qr_code, register_view, report_create, report_detail, report_list) slug = r'(?P[a-z0-9-_.:]+)' coordinates = r'(?P[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?)' @@ -35,4 +35,7 @@ urlpatterns = [ url(r'^report/l/(?P\d+)/$', report_create, name='site.report_create'), url(r'^report/r/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/$', report_create, name='site.report_create'), + url(r'^positions/$', position_list, name='site.position_list'), + url(r'^positions/create/$', position_create, name='site.position_create'), + url(r'^positions/(?P\d+)/$', position_detail, name='site.position_detail'), ] diff --git a/src/c3nav/site/views.py b/src/c3nav/site/views.py index a3f9a159..6326ac00 100644 --- a/src/c3nav/site/views.py +++ b/src/c3nav/site/views.py @@ -28,14 +28,15 @@ from c3nav.control.forms import AccessPermissionForm, SignedPermissionDataError from c3nav.mapdata.grid import grid from c3nav.mapdata.models import Location, Source from c3nav.mapdata.models.access import AccessPermissionToken -from c3nav.mapdata.models.locations import LocationRedirect, SpecificLocation +from c3nav.mapdata.models.locations import (LocationRedirect, Position, SpecificLocation, get_position_api_secret, + get_position_secret) from c3nav.mapdata.models.report import Report, ReportUpdate from c3nav.mapdata.utils.locations import (get_location_by_id_for_request, get_location_by_slug_for_request, levels_by_short_label_for_request) from c3nav.mapdata.utils.user import can_access_editor, get_user_data from c3nav.mapdata.views import set_tile_access_cookie from c3nav.routing.models import RouteOptions -from c3nav.site.forms import ReportUpdateForm +from c3nav.site.forms import PositionForm, ReportUpdateForm from c3nav.site.models import Announcement, SiteUpdate @@ -433,6 +434,7 @@ def report_create(request, coordinates=None, location=None, origin=None, destina }) +@login_required(login_url='site.login') def report_list(request, filter): page = request.GET.get('page', 1) @@ -481,3 +483,66 @@ def report_detail(request, pk, secret=None): 'form': form, 'update_form': update_form, }) + + +@login_required(login_url='site.login') +def position_list(request): + return render(request, 'site/position_list.html', { + 'positions': Position.objects.filter(owner=request.user), + }) + + +@login_required(login_url='site.login') +def position_create(request): + if Position.objects.filter(owner=request.user).count() >= 20: + messages.error(request, _('You can\'t create more than 20 positions.')) + + position = Position() + position.owner = request.user + + if request.method == 'POST': + form = PositionForm(instance=position, data=request.POST) + if form.is_valid(): + form.save() + messages.success(request, _('Position created.')) + return redirect(reverse('site.position_detail', kwargs={'pk': position.pk})) + else: + form = PositionForm(instance=position) + + return render(request, 'site/position_create.html', { + 'form': form, + }) + + pass + + +@login_required(login_url='site.login') +def position_detail(request, pk): + position = get_object_or_404(Position.objects.filter(owner=request.user), pk=pk) + + if request.method == 'POST': + with transaction.atomic(): + if request.POST.get('delete', None): + position.delete() + messages.success(request, _('Position deleted.')) + return redirect(reverse('site.position_list')) + + if request.POST.get('reset_secret', None): + position.secret = get_position_secret() + + if request.POST.get('reset_api_secret', None): + position.api_secret = get_position_api_secret() + + form = PositionForm(instance=position, data=request.POST) + if form.is_valid(): + form.save() + messages.success(request, _('Position updated.')) + return redirect(reverse('site.position_detail', kwargs={'pk': position.pk})) + else: + form = PositionForm(instance=position) + + return render(request, 'site/position_detail.html', { + 'position': position, + 'form': form, + }) + pass