issue submission forms
This commit is contained in:
parent
e7fc0f24ae
commit
52c02a4101
18 changed files with 652 additions and 79 deletions
16
src/c3nav/site/forms.py
Normal file
16
src/c3nav/site/forms.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from django.forms import ModelForm
|
||||
|
||||
from c3nav.mapdata.forms import I18nModelFormMixin
|
||||
from c3nav.mapdata.models.report import Report
|
||||
|
||||
|
||||
class ReportIssueForm(I18nModelFormMixin, ModelForm):
|
||||
class Meta:
|
||||
model = Report
|
||||
fields = ['title', 'description']
|
||||
|
||||
|
||||
class ReportMissingLocationForm(I18nModelFormMixin, ModelForm):
|
||||
class Meta:
|
||||
model = Report
|
||||
fields = ['title', 'description', 'created_title', 'created_groups']
|
|
@ -547,6 +547,9 @@ main.show-options #resultswrapper #route-options {
|
|||
padding: 5px 10px 5px 53px;
|
||||
height: 55px;
|
||||
}
|
||||
.location.location-form-value {
|
||||
margin: -10px -10px 5px -10px;
|
||||
}
|
||||
.location .icon {
|
||||
font-size: 36px;
|
||||
position: absolute;
|
||||
|
@ -1256,6 +1259,25 @@ main .narrow p, main .narrow form, main .narrow button {
|
|||
main .narrow form button {
|
||||
width: 100%;
|
||||
}
|
||||
main form > p, #modal form > p {
|
||||
margin-bottom: 15px;
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.helptext {
|
||||
display: block;
|
||||
margin-top: -15px;
|
||||
font-style: italic;
|
||||
color: #999999;
|
||||
}
|
||||
textarea {
|
||||
resize: none;
|
||||
height: 100px;
|
||||
}
|
||||
select {
|
||||
height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-permissions-form label {
|
||||
font-weight: 400;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<form method="post" action="{{ request.path_info }}?{{ request.META.QUERY_STRING }}">
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
{{ form.as_p }}
|
||||
<button type="submit">{{ title }}</button>
|
||||
{% if bottom_link_url %}
|
||||
<a href="{{ bottom_link_url }}?{{ request.META.QUERY_STRING }}">{{ bottom_link_text }}</a>
|
||||
|
|
5
src/c3nav/site/templates/site/fragment_location.html
Normal file
5
src/c3nav/site/templates/site/fragment_location.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
<div class="location{% if form_value %} location-form-value{% endif %}">
|
||||
<i class="icon material-icons">{% if location.get_icon %}{{ location.get_icon }}{% else %}place{% endif %}</i>
|
||||
<span>{{ location.title }}</span>
|
||||
<small>{% if add_subtitle %}{{ add_subtitle }}, {% endif %}{{ location.subtitle }}</small>
|
||||
</div>
|
22
src/c3nav/site/templates/site/fragment_report_meta.html
Normal file
22
src/c3nav/site/templates/site/fragment_report_meta.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
{% load i18n %}
|
||||
{% if report.category == 'location-issue' %}
|
||||
<p><strong>{% trans 'You are reporting an issue with the following location:' %}</strong></p>
|
||||
{% include 'site/fragment_location.html' with form_value=1 location=report.location %}
|
||||
{% elif report.category == 'missing-location' %}
|
||||
<p><strong>{% trans 'You are reporting an missing location at the following position:' %}</strong></p>
|
||||
{% include 'site/fragment_location.html' with form_value=1 location=report.coordinates add_subtitle=report.coordinates_id %}
|
||||
{% elif report.category == 'route-issue' %}
|
||||
<p><strong>{% trans 'You are reporting an issue with the following route:' %}</strong></p>
|
||||
|
||||
<label>{% trans 'Origin' %}:</label>
|
||||
{% include 'site/fragment_location.html' with form_value=1 location=report.origin %}
|
||||
|
||||
<label>{% trans 'Destination' %}:</label>
|
||||
{% include 'site/fragment_location.html' with form_value=1 location=report.destination %}
|
||||
|
||||
<label>{% trans 'Route options' %}:</label>
|
||||
{% for option in options.serialize %}
|
||||
{{ option.label }}: {{ option.value_display }}<br>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
|
@ -1,10 +0,0 @@
|
|||
{% extends 'site/base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<main class="account">
|
||||
<h2>{% trans 'Coming soon' %}</h2>
|
||||
|
||||
{% include 'site/fragment_messages.html' %}
|
||||
</main>
|
||||
{% endblock %}
|
16
src/c3nav/site/templates/site/report_create.html
Normal file
16
src/c3nav/site/templates/site/report_create.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends 'site/base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<main class="account">
|
||||
<h2>{% trans 'Report issue' %}</h2>
|
||||
{% include 'site/fragment_messages.html' %}
|
||||
|
||||
<form method="post" action="{{ request.path_info }}?{{ request.META.QUERY_STRING }}">
|
||||
{% csrf_token %}
|
||||
{% include 'site/fragment_report_meta.html' %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit">{% trans 'Submit' %}</button>
|
||||
</form>
|
||||
</main>
|
||||
{% endblock %}
|
44
src/c3nav/site/templates/site/report_detail.html
Normal file
44
src/c3nav/site/templates/site/report_detail.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
{% extends 'site/base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<main class="account">
|
||||
<h2>{% trans 'Report' %}: {{ report.title }}</h2>
|
||||
<p><em>
|
||||
{% if report.open %}
|
||||
<strong class="green">{% trans 'open' %}</strong>
|
||||
{% else %}
|
||||
<strong class="red">{% trans 'closed' %}</strong>
|
||||
{% endif %}
|
||||
–
|
||||
{% if report.author %}
|
||||
{% trans 'anonymous submission' %}
|
||||
{% else %}
|
||||
{% trans 'by' %} {{ request.author.username }}
|
||||
{% endif %}
|
||||
–
|
||||
{{ report.created }}
|
||||
</em></p>
|
||||
{% include 'site/fragment_messages.html' %}
|
||||
{% include 'site/fragment_report_meta.html' %}
|
||||
|
||||
{% for field in form %}
|
||||
{% if field.name != 'title' %}
|
||||
<p>
|
||||
<strong>{{ field.label }}:</strong><br>
|
||||
{% if field.name == 'description' %}
|
||||
{{ report.description | linebreaksbr }}
|
||||
{% elif field.name == 'created_groups' %}
|
||||
{% for group in report.created_groups.all %}
|
||||
{{ group.title }}<br>
|
||||
{% empty %}
|
||||
<em>{% trans '(none)' %}</em>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ field.value }}
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -1,7 +1,7 @@
|
|||
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_view)
|
||||
login_view, logout_view, map_index, qr_code, register_view, report_create, report_detail)
|
||||
|
||||
slug = r'(?P<slug>[a-z0-9-_.:]+)'
|
||||
coordinates = r'(?P<coordinates>[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?)'
|
||||
|
@ -27,7 +27,10 @@ urlpatterns = [
|
|||
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'),
|
||||
url(r'^report/(?P<pk>\d+)/$', report_detail, name='site.report_detail'),
|
||||
url(r'^report/(?P<pk>\d+)/(?P<secret>[^/]+)/$', report_detail, name='site.report_detail'),
|
||||
url(r'^report/l/%s/$' % coordinates, report_create, name='site.report_create'),
|
||||
url(r'^report/l/(?P<location>\d+)/$', report_create, name='site.report_create'),
|
||||
url(r'^report/r/(?P<origin>[^/]+)/(?P<destination>[^/]+)/(?P<options>[^/]+)/$',
|
||||
report_create, name='site.report_create'),
|
||||
]
|
||||
|
|
|
@ -9,11 +9,12 @@ from django.contrib.auth import login, logout
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm, UserCreationForm
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
from django.core.exceptions import ObjectDoesNotExist, SuspiciousOperation
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db import transaction
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest
|
||||
from django.middleware import csrf
|
||||
from django.shortcuts import redirect, render
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -27,9 +28,12 @@ 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.utils.locations import get_location_by_slug_for_request, levels_by_short_label_for_request
|
||||
from c3nav.mapdata.models.report import Report
|
||||
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.models import Announcement, SiteUpdate
|
||||
|
||||
|
||||
|
@ -350,6 +354,86 @@ def about_view(request):
|
|||
})
|
||||
|
||||
|
||||
def get_report_location_for_request(pk, request):
|
||||
location = get_location_by_id_for_request(pk, request)
|
||||
if location is None:
|
||||
raise Http404
|
||||
return location
|
||||
|
||||
|
||||
@never_cache
|
||||
def report_view(request, coordinates=None, location=None, origin=None, destination=None, options=None):
|
||||
return render(request, 'site/report.html', {})
|
||||
def report_create(request, coordinates=None, location=None, origin=None, destination=None, options=None):
|
||||
report = Report()
|
||||
report.request = request
|
||||
|
||||
if coordinates:
|
||||
report.category = 'missing-location'
|
||||
report.coordinates_id = coordinates
|
||||
try:
|
||||
report.coordinates
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404
|
||||
elif location:
|
||||
report.category = 'location-issue'
|
||||
report.location = get_report_location_for_request(location, request)
|
||||
if report.location is None:
|
||||
raise Http404
|
||||
report.location = location
|
||||
elif origin:
|
||||
report.category = 'route-issue'
|
||||
report.origin_id = origin
|
||||
report.destination_id = destination
|
||||
try:
|
||||
# noinspection PyStatementEffect
|
||||
report.origin
|
||||
# noinspection PyStatementEffect
|
||||
report.destination
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404
|
||||
try:
|
||||
options = RouteOptions.unserialize_string(options)
|
||||
except Exception:
|
||||
raise SuspiciousOperation
|
||||
report.options = options.serialize_string()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = report.form_cls(instance=report, data=request.POST)
|
||||
if form.is_valid():
|
||||
report = form.instance
|
||||
if request.user.is_authenticated:
|
||||
report.author = request.user
|
||||
report.save()
|
||||
|
||||
success_messages = [_('Your report was submitted.')]
|
||||
success_kwargs = {'pk': report.pk}
|
||||
if request.user.is_authenticated:
|
||||
success_messages.append(_('You can keep track of it from your user dashboard.'))
|
||||
else:
|
||||
success_messages.append(_('You can keep track of it by revisiting the public URL mentioned below.'))
|
||||
success_kwargs = {'secret': report.secret}
|
||||
messages.success(request, ' '.join(str(s) for s in success_messages))
|
||||
return redirect(reverse('site.report_detail', kwargs=success_kwargs))
|
||||
else:
|
||||
form = report.form_cls(instance=report)
|
||||
|
||||
return render(request, 'site/report_create.html', {
|
||||
'report': report,
|
||||
'options': options,
|
||||
'form': form,
|
||||
})
|
||||
|
||||
|
||||
def report_detail(request, pk, secret=None):
|
||||
if secret:
|
||||
qs = Report.objects.filter(secret=secret)
|
||||
else:
|
||||
qs = Report.qs_for_request(request)
|
||||
report = get_object_or_404(qs, pk=pk)
|
||||
report.request = request
|
||||
|
||||
form = report.form_cls(instance=report)
|
||||
|
||||
return render(request, 'site/report_detail.html', {
|
||||
'report': report,
|
||||
'form': form,
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue