quests can now be done!

This commit is contained in:
Laura Klünder 2024-12-24 22:58:26 +01:00
parent df777ecc05
commit d811170716
14 changed files with 219 additions and 63 deletions

View file

@ -0,0 +1,20 @@
{% extends 'site/base.html' %}
{% load i18n %}
{% block content %}
<main class="account">
<h3>{{ title }}</h3>
{% if back_url %}
<p>
<a href="{{ back_url }}">&laquo; {% trans 'back' %}</a>
</p>
{% endif %}
<form method="post" action="{{ request.path_info }}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">{% trans 'Submit answer' %}</button>
</form>
</main>
{% endblock %}

View file

@ -0,0 +1,10 @@
{% extends 'site/base.html' %}
{% load i18n %}
{% block content %}
<main class="account">
<h3>{% trans 'Thank you!' %}</h3>
<p>{% trans 'Have a cookie <3 🍪' %}</p>
</main>
{% endblock %}

View file

@ -1,10 +1,12 @@
from django.apps import apps
from django.urls import path
from django.views.generic import TemplateView
from c3nav.editor.views.account import change_password_view, login_view, logout_view, register_view
from c3nav.editor.views.changes import changeset_detail, changeset_edit, changeset_redirect
from c3nav.editor.views.edit import edit, graph_edit, level_detail, list_objects, main_index, sourceimage, space_detail
from c3nav.editor.views.overlays import overlays_list, overlay_features, overlay_feature_edit
from c3nav.editor.views.quest import QuestFormView
from c3nav.editor.views.users import user_detail, user_redirect
@ -55,6 +57,8 @@ urlpatterns = [
path('logout', logout_view, name='editor.logout'),
path('register', register_view, name='editor.register'),
path('change_password', change_password_view, name='editor.change_password'),
path('quests/<str:quest_type>/<str:identifier>/', QuestFormView.as_view(), name='editor.quest'),
path('thanks/', TemplateView.as_view(template_name="editor/thanks.html"), name='editor.thanks'),
path('', main_index, name='editor.index'),
]
urlpatterns.extend(add_editor_urls('Level', with_list=False, explicit_edit=True))

View file

@ -26,14 +26,35 @@ from c3nav.mapdata.utils.user import can_access_editor
@contextmanager
def maybe_lock_changeset_to_edit(request):
def maybe_lock_changeset_to_edit(changeset):
""" Lock the changeset of the given request, if it can be locked (= has ever been saved to the database)"""
if request.changeset.pk:
with request.changeset.lock_to_edit(request=request) as changeset:
request.changeset = changeset
yield
if changeset.pk:
with changeset.lock_to_edit() as locked_changeset:
yield locked_changeset
else:
yield
yield changeset
@contextmanager
def within_changeset(changeset, user):
with maybe_lock_changeset_to_edit(changeset=changeset) as locked_changeset:
# Turn the changes from the changeset into a list of operations
operations = locked_changeset.as_operations
# Enable the overlay manager, temporarily applying the changeset changes
# commit is set to false, meaning all changes will be reset once we leave the manager
with DatabaseOverlayManager.enable(operations=operations, commit=False) as manager:
yield locked_changeset
if manager.operations:
# Add new operations to changeset
locked_changeset.changes.add_operations(manager.operations)
locked_changeset.save()
# Add new changeset update
update = locked_changeset.updates.create(user=user, objects_changed=True)
locked_changeset.last_update = update
locked_changeset.last_change = update
locked_changeset.save()
@contextmanager
@ -71,24 +92,9 @@ def accesses_mapdata(func):
raise ValueError # todo: good error message, but this shouldn't happen
else:
# For non-direct editing, we will interact with the changeset
with maybe_lock_changeset_to_edit(request=request):
# Turn the changes from the changeset into a list of operations
operations = request.changeset.as_operations
# Enable the overlay manager, temporarily applying the changeset changes
# commit is set to false, meaning all changes will be reset once we leave the manager
with DatabaseOverlayManager.enable(operations=operations, commit=False) as manager:
result = func(request, *args, **kwargs)
if manager.operations:
# Add new operations to changeset
request.changeset.changes.add_operations(manager.operations)
request.changeset.save()
# Add new changeset update
update = request.changeset.updates.create(user=request.user, objects_changed=True)
request.changeset.last_update = update
request.changeset.last_change = update
request.changeset.save()
with within_changeset(changeset=request.changeset, user=request.user) as locked_changeset:
request.changeset = locked_changeset
return func(request, *args, **kwargs)
return result
return wrapped

View file

@ -62,7 +62,7 @@ def changeset_detail(request, pk):
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
elif request.POST.get('activate') == '1':
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if changeset.can_activate(request):
changeset.activate(request)
messages.success(request, _('You activated this change set.'))
@ -76,7 +76,7 @@ def changeset_detail(request, pk):
messages.info(request, _('You need to log in to propose changes.'))
return redirect(reverse('editor.login') + '?r=' + request.path)
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if not changeset.title:
form = ChangeSetForm(instance=changeset, data=request.POST)
if not form.is_valid():
@ -108,7 +108,7 @@ def changeset_detail(request, pk):
messages.info(request, _('You need to log in to apply changes.'))
return redirect(reverse('editor.login') + '?r=' + request.path)
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if not changeset.title:
form = ChangeSetForm(instance=changeset, data=request.POST)
if not form.is_valid():
@ -136,7 +136,7 @@ def changeset_detail(request, pk):
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
elif request.POST.get('unpropose') == '1':
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if changeset.can_unpropose(request):
changeset.unpropose(request.user)
messages.success(request, _('You unproposed your changes.'))
@ -146,7 +146,7 @@ def changeset_detail(request, pk):
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
elif request.POST.get('review') == '1':
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if changeset.can_start_review(request):
changeset.start_review(request.user)
messages.success(request, _('You are now reviewing these changes.'))
@ -156,7 +156,7 @@ def changeset_detail(request, pk):
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
elif request.POST.get('reject') == '1':
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if not changeset.can_end_review(request):
messages.error(request, _('You cannot reject these changes.'))
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
@ -176,7 +176,7 @@ def changeset_detail(request, pk):
})
elif request.POST.get('unreject') == '1':
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if not changeset.can_unreject(request):
messages.error(request, _('You cannot unreject these changes.'))
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
@ -187,7 +187,7 @@ def changeset_detail(request, pk):
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
elif request.POST.get('apply') == '1':
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if not changeset.can_end_review(request):
messages.error(request, _('You cannot accept and apply these changes.'))
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))
@ -204,7 +204,7 @@ def changeset_detail(request, pk):
return render(request, 'editor/changeset_apply.html', {})
elif request.POST.get('delete') == '1':
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if not changeset.can_delete(request):
messages.error(request, _('You cannot delete this change set.'))
@ -502,7 +502,7 @@ def changeset_edit(request, pk):
if str(pk) != str(request.changeset.pk):
changeset = get_object_or_404(ChangeSet.qs_for_request(request), pk=pk)
with changeset.lock_to_edit(request) as changeset:
with changeset.lock_to_edit() as changeset:
if not changeset.can_edit(request):
messages.error(request, _('You cannot edit this change set.'))
return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk}))

View file

@ -179,7 +179,7 @@ def overlay_feature_edit(request, level=None, overlay=None, pk=None):
if not new and ((request.POST.get('delete') == '1' and delete is not False) or delete):
# Delete this mapitem!
if request.POST.get('delete_confirm') == '1' or delete:
with request.changeset.lock_to_edit(request) as changeset:
with request.changeset.lock_to_edit() as changeset:
if changeset.can_edit(request):
obj.delete()
else:
@ -210,7 +210,7 @@ def overlay_feature_edit(request, level=None, overlay=None, pk=None):
obj.level = level
obj.overlay = overlay
with request.changeset.lock_to_edit(request) as changeset:
with request.changeset.lock_to_edit() as changeset:
if changeset.can_edit(request):
try:
obj.save()

View file

@ -0,0 +1,41 @@
from functools import cached_property
from django.http import Http404
from django.urls import reverse_lazy
from django.views.generic.edit import FormView
from c3nav.mapdata.quests.base import get_quest_for_request
class QuestFormView(FormView):
template_name = "editor/quest_form.html"
success_url = reverse_lazy("editor.thanks")
@cached_property
def quest(self):
quest = get_quest_for_request(request=self.request,
quest_type=self.kwargs["quest_type"],
identifier=self.kwargs["identifier"])
if quest is None:
raise Http404
return quest
def get_form_class(self):
return self.quest.get_form_class()
def get_form_kwargs(self):
return {
"request": self.request,
**super().get_form_kwargs(),
**self.quest.get_form_kwargs(request=self.request),
}
def get_context_data(self, **kwargs):
return {
**super().get_context_data(**kwargs),
"title": self.quest.quest_type_label,
}
def form_valid(self, form):
form.save()
return super().form_valid(form)