add do_submit task management stuff

This commit is contained in:
Laura Klünder 2016-10-04 20:41:03 +02:00
parent 1d56f10ec1
commit cd99ba1c0a
6 changed files with 131 additions and 58 deletions

View file

@ -5,7 +5,7 @@ from django.conf import settings
from django.urls.base import reverse
from django.utils.translation import ugettext_lazy as _
from c3nav.editor.tasks import check_access_token, request_access_token
from c3nav.editor.tasks import check_access_token, request_access_token, submit_edit
from c3nav.mapdata.models import Package
@ -114,6 +114,11 @@ class Hoster(ABC):
session_data['checking_progress_id'] = task.id
self._handle_checking_task(request, task, session_data)
def submit_edit(self, request, data):
session_data = self._get_session_data(request)
task = submit_edit.apply_async(access_token=session_data['access_token'], data=data)
return task
@abstractmethod
def get_auth_uri(self, request):
"""
@ -133,7 +138,7 @@ class Hoster(ABC):
"""
Task method for requesting the access token asynchroniously.
Returns a dict with a 'state' key containing the new hoster state, an optional 'error' key containing an
error message and an optional 'access_token' keys containing a new access token.
error message and an optional 'access_token' key containing a new access token.
"""
pass
@ -144,3 +149,13 @@ class Hoster(ABC):
Returns a dict with a 'state' key containing the new hoster state.
"""
pass
@abstractmethod
def do_submit_edit(self, access_token, data):
"""
Task method for submitting an edit (e.g. creating a pull request).
Returns a dict with a 'success' key that contains a boolean, an optional 'error' key containing an error
message and an optional 'url' key containing an URL to the created pull request.
"""
pass

View file

@ -80,3 +80,6 @@ class GithubHoster(Hoster):
return {'state': 'missing_permissions'}
return {'state': 'logged_in'}
def do_submit_edit(self, access_token, data):
raise NotImplementedError

View file

@ -75,3 +75,6 @@ class GitlabHoster(Hoster):
return {'state': 'logged_out'}
return {'state': 'logged_in'}
def do_submit_edit(self, access_token, data):
raise NotImplementedError

View file

@ -11,3 +11,9 @@ def request_access_token(hoster, *args, **kwargs):
def check_access_token(hoster, access_token):
from c3nav.editor.hosters import hosters
return hosters[hoster].do_check_access_token(access_token)
@app.task()
def submit_edit(hoster, access_token, data):
from c3nav.editor.hosters import hosters
return hosters[hoster].do_submit_edit(access_token, data)

View file

@ -3,58 +3,78 @@
{% load bootstrap3 %}
{% block content %}
{% if hoster %}
{% if hoster_error %}
<div class="alert alert-danger" role="alert">
<p>{{ hoster_error }}</p>
</div>
{% endif %}
{% if hoster_state == 'logged_in' %}
<h2>Propose Changes</h2>
<p>Please provide a short helpful title for your change.</p>
<form action="{% url 'editor.finalize' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="data" value="{{ data }}">
{% bootstrap_form commit_form %}
{% if not task %}
{% buttons %}
<button type="submit" class="btn btn-lg btn-primary">Create Pull Request</button><br>
<small><em>
{{ hoster.name }} {{ hoster.base_url }}
</em></small>
{% endbuttons %}
</form>
{% elif hoster_state == 'checking' %}
<h2>Sign in with {{ hoster.title }}</h2>
<form action="{% url 'editor.finalize' %}" method="POST" data-check-hoster="{{ hoster.name }}">
{% csrf_token %}
<input type="hidden" name="data" value="{{ data }}">
<p><img src="{% static 'img/loader.gif' %}"></p>
<p><em>Checking authentication, please wait…</em></p>
</form>
{% else %}
{% if hoster_state == 'misssing_permissions' %}
<h2>Missing {{ hoster.title }} Permissions</h2>
<p>c3nav is missing permissions that it needs to propose your edit.</p>
<p>Please click the button below to grant the missing permissions.</p>
{% else %}
<h2>Sign in with {{ hoster.title }}</h2>
<p>Please sign in to continue and propose your edit.</p>
{% if hoster_error %}
<div class="alert alert-danger" role="alert">
<p>{{ hoster_error }}</p>
</div>
{% endif %}
{% if hoster_state == 'logged_in' %}
<h2>Propose Changes</h2>
<p>Please provide a short helpful title for your change.</p>
<form action="{% url 'editor.finalize' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="data" value="{{ data }}">
<input type="hidden" name="action" value="submit">
<input type="hidden" name="editor_submit_token" value="{{ editor_submit_token }}">
{% bootstrap_form commit_form %}
{% buttons %}
<button type="submit" class="btn btn-lg btn-primary">Create Pull Request</button><br>
<small><em>
{{ hoster.name }} {{ hoster.base_url }}
</em></small>
{% endbuttons %}
</form>
{% elif hoster_state == 'checking' %}
<h2>Sign in with {{ hoster.title }}</h2>
<form action="{% url 'editor.finalize' %}" method="POST" data-check-hoster="{{ hoster.name }}">
{% csrf_token %}
<input type="hidden" name="data" value="{{ data }}">
<p><img src="{% static 'img/loader.gif' %}"></p>
<p><em>Checking authentication, please wait…</em></p>
</form>
{% else %}
{% if hoster_state == 'misssing_permissions' %}
<h2>Missing {{ hoster.title }} Permissions</h2>
<p>c3nav is missing permissions that it needs to propose your edit.</p>
<p>Please click the button below to grant the missing permissions.</p>
{% else %}
<h2>Sign in with {{ hoster.title }}</h2>
<p>Please sign in to continue and propose your edit.</p>
{% endif %}
<form action="{% url 'editor.finalize' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="data" value="{{ data }}">
<input type="hidden" name="action" value="oauth">
<p>
<button type="submit" class="btn btn-lg btn-primary">Sign in with {{ hoster.title }}</button><br>
<small><em>
{{ hoster.name }} {{ hoster.base_url }}
</em></small>
</p>
</form>
{% endif %}
<p>Alternatively, you can copy your edit below and send it to the maps maintainer.</p>
{% else %}
{% if not task.ready or redirect %}
<h2>Creating Pull Request…</h2>
<form action="{% url 'editor.finalize' %}" method="POST"{% if redirect %} name="redirect"{% else %} data-check-task="{{ task.id }}"{% endif %}>
{% csrf_token %}
<input type="hidden" name="data" value="{{ data }}">
<input type="hidden" name="action" value="result">
<input type="hidden" name="task" value="{{ task.id }}">
<p><img src="{% static 'img/loader.gif' %}"></p>
<p><em>Creating Pull Request…</em></p>
</form>
{% else %}
<h2>Pull Request created</h2>
<p>You can find it here:</p>
{% endif %}
<form action="{% url 'editor.finalize' %}" method="POST" data-task="{{ task }}">
{% csrf_token %}
<input type="hidden" name="data" value="{{ data }}">
<input type="hidden" name="action" value="oauth">
<p>
<button type="submit" class="btn btn-lg btn-primary">Sign in with {{ hoster.title }}</button><br>
<small><em>
{{ hoster.name }} {{ hoster.base_url }}
</em></small>
</p>
</form>
{% endif %}
<p>Alternatively, you can copy your edit below and send it to the maps maintainer.</p>
{% else %}
<h2>Copy your edit</h2>
<p>In order to propose your edit, please copy it and send it to the maps maintainer.</p>

View file

@ -1,12 +1,16 @@
import string
from django.conf import settings
from django.core import signing
from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.http.response import Http404
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.crypto import get_random_string
from django.views.decorators.http import require_POST
from c3nav.editor.forms import CommitForm, FeatureForm
from c3nav.editor.hosters import get_hoster_for_package, hosters
from c3nav.editor.tasks import submit_edit
from c3nav.mapdata.models.feature import FEATURE_TYPES, Feature
from c3nav.mapdata.models.package import Package
from c3nav.mapdata.packageio.write import json_encode
@ -112,22 +116,41 @@ def finalize(request):
hoster = get_hoster_for_package(package)
action = request.POST.get('action')
if 'commit_msg' in request.POST or action == 'submit':
form = CommitForm(request.POST)
else:
form = CommitForm({'commit_msg': data['commit_msg']})
task = None
new_submit_token = False
if action == 'check':
hoster.check_state(request)
elif action == 'oauth':
hoster.set_tmp_data(request, raw_data)
return redirect(hoster.get_auth_uri(request))
elif action == 'submit' and hoster.get_state(request) == 'logged_in':
if request.POST.get('editor_submit_token', '') != request.session.get('editor_submit_token', None):
raise SuspiciousOperation('Invalid submit token.')
if form.is_valid():
new_submit_token = True
data['commit_msg'] = form.cleaned_data['commit_msg']
task = hoster.submit_edit(request, data)
elif action == 'result':
if 'task' not in request.POST:
raise SuspiciousOperation('Missing task id.')
task = submit_edit.AsyncResult(task_id=request.POST['task'])
try:
task.ready()
except:
raise Http404()
if 'editor_submit_token' not in request.session or new_submit_token:
request.session['editor_submit_token'] = get_random_string(42, string.ascii_letters + string.digits)
hoster_state = hoster.get_state(request)
hoster_error = hoster.get_error(request) if hoster_state == 'logged_out' else None
if request.method == 'POST' and 'commit_msg' in request.POST:
form = CommitForm(request.POST)
if form.is_valid() and hoster_state == 'logged_in':
pass
else:
form = CommitForm({'commit_msg': data['commit_msg']})
return render(request, 'editor/finalize.html', {
'data': raw_data,
'action': data['action'],
@ -137,6 +160,9 @@ def finalize(request):
'hoster': hoster,
'hoster_state': hoster_state,
'hoster_error': hoster_error,
'redirect': action == 'submit' and not settings.CELERY_ALWAYS_EAGER,
'editor_submit_token': request.session['editor_submit_token'],
'task': {'id': task.id, 'ready': task.ready(), 'result': task.result} if task is not None else None,
'file_path': data['file_path'],
'file_contents': data.get('content')
})