forked from CGM_Public/pretix_original
136 lines
4.9 KiB
Python
136 lines
4.9 KiB
Python
import logging
|
|
|
|
import celery.exceptions
|
|
from celery.result import AsyncResult
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.http import JsonResponse
|
|
from django.shortcuts import redirect, render
|
|
from django.utils.translation import ugettext as _
|
|
|
|
from pretix.celery_app import app
|
|
|
|
logger = logging.getLogger('pretix.base.async')
|
|
|
|
|
|
class AsyncAction:
|
|
task = None
|
|
success_url = None
|
|
error_url = None
|
|
known_errortypes = []
|
|
|
|
def do(self, *args):
|
|
if not isinstance(self.task, app.Task):
|
|
raise TypeError('Method has no task attached')
|
|
|
|
res = self.task.apply_async(args=args)
|
|
|
|
if 'ajax' in self.request.GET or 'ajax' in self.request.POST:
|
|
data = self._return_ajax_result(res)
|
|
data['check_url'] = self.get_check_url(res.id, True)
|
|
return JsonResponse(data)
|
|
else:
|
|
if res.ready():
|
|
if res.successful() and not isinstance(res.info, Exception):
|
|
return self.success(res.info)
|
|
else:
|
|
return self.error(res.info)
|
|
return redirect(self.get_check_url(res.id, False))
|
|
|
|
def get_success_url(self, value):
|
|
return self.success_url
|
|
|
|
def get_error_url(self):
|
|
return self.error_url
|
|
|
|
def get_check_url(self, task_id, ajax):
|
|
return self.request.path + '?async_id=%s' % task_id + ('&ajax=1' if ajax else '')
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if 'async_id' in request.GET and settings.HAS_CELERY:
|
|
return self.get_result(request)
|
|
return self.http_method_not_allowed(request)
|
|
|
|
def _return_ajax_result(self, res, timeout=.5):
|
|
if not res.ready():
|
|
try:
|
|
res.get(timeout=timeout, propagate=False)
|
|
except celery.exceptions.TimeoutError:
|
|
pass
|
|
|
|
ready = res.ready()
|
|
data = {
|
|
'async_id': res.id,
|
|
'ready': ready
|
|
}
|
|
if ready:
|
|
if res.successful() and not isinstance(res.info, Exception):
|
|
smes = self.get_success_message(res.info)
|
|
if smes:
|
|
messages.success(self.request, smes)
|
|
# TODO: Do not store message if the ajax client states that it will not redirect
|
|
# but handle the mssage itself
|
|
data.update({
|
|
'redirect': self.get_success_url(res.info),
|
|
'success': True,
|
|
'message': str(self.get_success_message(res.info))
|
|
})
|
|
else:
|
|
messages.error(self.request, self.get_error_message(res.info))
|
|
# TODO: Do not store message if the ajax client states that it will not redirect
|
|
# but handle the mssage itself
|
|
data.update({
|
|
'redirect': self.get_error_url(),
|
|
'success': False,
|
|
'message': str(self.get_error_message(res.info))
|
|
})
|
|
return data
|
|
|
|
def get_result(self, request):
|
|
res = AsyncResult(request.GET.get('async_id'))
|
|
if 'ajax' in self.request.GET:
|
|
return JsonResponse(self._return_ajax_result(res, timeout=0.25))
|
|
else:
|
|
if res.ready():
|
|
if res.successful() and not isinstance(res.info, Exception):
|
|
return self.success(res.info)
|
|
else:
|
|
return self.error(res.info)
|
|
return render(request, 'pretixpresale/waiting.html')
|
|
|
|
def success(self, value):
|
|
smes = self.get_success_message(value)
|
|
if smes:
|
|
messages.success(self.request, smes)
|
|
if "ajax" in self.request.POST or "ajax" in self.request.GET:
|
|
return JsonResponse({
|
|
'ready': True,
|
|
'success': True,
|
|
'redirect': self.get_success_url(value),
|
|
'message': str(self.get_success_message(value))
|
|
})
|
|
return redirect(self.get_success_url(value))
|
|
|
|
def error(self, exception):
|
|
messages.error(self.request, self.get_error_message(exception))
|
|
if "ajax" in self.request.POST or "ajax" in self.request.GET:
|
|
return JsonResponse({
|
|
'ready': True,
|
|
'success': False,
|
|
'redirect': self.get_error_url(),
|
|
'message': str(self.get_error_message(exception))
|
|
})
|
|
return redirect(self.get_error_url())
|
|
|
|
def get_error_message(self, exception):
|
|
if isinstance(exception, dict) and exception['exc_type'] in self.known_errortypes:
|
|
return exception['exc_message']
|
|
elif exception.__class__.__name__ in self.known_errortypes:
|
|
return str(exception)
|
|
else:
|
|
logger.error('Unexpected exception: %r' % exception)
|
|
return _('An unexpected error has occured.')
|
|
|
|
def get_success_message(self, value):
|
|
return _('The task has been completed.')
|