diff --git a/scheduler/jobs/helpers.py b/scheduler/jobs/helpers.py
new file mode 100644
index 0000000000000000000000000000000000000000..7323cb6d3a3e11bf074c404827b306597960a180
--- /dev/null
+++ b/scheduler/jobs/helpers.py
@@ -0,0 +1,70 @@
+# (c) 2020 MPIB ,
+#
+# This file is part of castellum-scheduler.
+#
+# castellum-scheduler is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from time import sleep
+
+from django.db import DatabaseError
+
+from .models import Job
+
+
+def request(data, timeout=10, interval=1):
+ job = Job.objects.create(data=data)
+ t = 0
+ while True:
+ sleep(interval)
+ t += interval
+ job = Job.objects.get(pk=job.pk)
+
+ if job.state == Job.FINISHED:
+ job.delete()
+ return True
+ if job.state == Job.ERROR:
+ job.delete()
+ return False
+ if t > timeout:
+ job.delete()
+ raise TimeoutError
+
+
+def listen(interval=1):
+ while True:
+ for job in Job.objects.filter(state=Job.NEW):
+ try:
+ job.state = Job.STARTED
+ job.save(force_update=True)
+ except DatabaseError:
+ # Job has already timed out
+ continue
+ yield job.pk, job.data
+
+ sleep(interval)
+
+
+def response(pk, success):
+ try:
+ job = Job.objects.get(pk=pk, state=Job.STARTED)
+ except Job.DoesNotExist:
+ raise KeyError
+
+ job.state = Job.FINISHED if success else Job.ERROR
+ try:
+ job.save(force_update=True)
+ except DatabaseError:
+ # Job has already timed out
+ pass
diff --git a/scheduler/jobs/migrations/0001_initial.py b/scheduler/jobs/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..411fc2ba69d374116f8c3a91047ea0bf95c45324
--- /dev/null
+++ b/scheduler/jobs/migrations/0001_initial.py
@@ -0,0 +1,22 @@
+# Generated by Django 3.2.6 on 2021-08-24 15:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Job',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('data', models.TextField(blank=True)),
+ ('state', models.SmallIntegerField(choices=[(0, 'new'), (1, 'started'), (2, 'finished'), (3, 'errored')], default=0)),
+ ],
+ ),
+ ]
diff --git a/scheduler/jobs/migrations/__init__.py b/scheduler/jobs/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scheduler/jobs/models.py b/scheduler/jobs/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..95a6a780b6d1518b600d58116f1d36b1dd062bea
--- /dev/null
+++ b/scheduler/jobs/models.py
@@ -0,0 +1,34 @@
+# (c) 2020 MPIB ,
+#
+# This file is part of castellum-scheduler.
+#
+# castellum-scheduler is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from django.db import models
+
+
+class Job(models.Model):
+ NEW = 0
+ STARTED = 1
+ FINISHED = 2
+ ERROR = 3
+
+ data = models.TextField(blank=True)
+ state = models.SmallIntegerField(choices=[
+ (NEW, 'new'),
+ (STARTED, 'started'),
+ (FINISHED, 'finished'),
+ (ERROR, 'errored'),
+ ], default=NEW)
diff --git a/scheduler/jobs/views.py b/scheduler/jobs/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b7e20dbae877409079732a739ac18fc621da011
--- /dev/null
+++ b/scheduler/jobs/views.py
@@ -0,0 +1,50 @@
+# (c) 2020 MPIB ,
+#
+# This file is part of castellum-scheduler.
+#
+# castellum-scheduler is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from django.conf import settings
+from django.core.exceptions import PermissionDenied
+from django.http import Http404
+from django.http import HttpResponse
+from django.http import StreamingHttpResponse
+from django.utils.decorators import method_decorator
+from django.views.decorators.csrf import csrf_exempt
+from django.views.generic import View
+
+from . import helpers
+
+
+@method_decorator(csrf_exempt, 'dispatch')
+class JobView(View):
+ def dispatch(self, request, *args, **kwargs):
+ if request.headers.get('Authorization') != 'token ' + settings.API_TOKEN:
+ raise PermissionDenied
+ return super().dispatch(request, *args, **kwargs)
+
+ def stream(self):
+ for id, data in helpers.listen():
+ yield 'id: {}\ndata: {}\n\n'.format(id, data)
+
+ def get(self, request, *args, **kwargs):
+ return StreamingHttpResponse(self.stream(), content_type='text/event-stream')
+
+ def post(self, request, *args, **kwargs):
+ try:
+ helpers.response(request.GET['id'], 'success' in request.GET)
+ except KeyError:
+ raise Http404
+ return HttpResponse(status=204)
diff --git a/scheduler/main/views.py b/scheduler/main/views.py
index be429cac7d0d42f8e457b205a151a90a76b1661c..87253f81c806a798abc97ec0c6e7d962e62de752 100644
--- a/scheduler/main/views.py
+++ b/scheduler/main/views.py
@@ -16,6 +16,7 @@
# License along with Castellum. If not, see
# .
+import json
from collections import OrderedDict
from django.conf import settings
@@ -36,7 +37,7 @@ from django.views.generic import ListView
from django.views.generic import UpdateView
from django.views.generic import View
-import requests
+from scheduler.jobs import helpers as jobs
from .forms import ScheduleForm
from .models import Invitation
@@ -124,12 +125,13 @@ class InvitationUpdateView(UpdateView):
def form_valid(self, form, *args):
ok = True
response = super().form_valid(form, *args)
- if settings.PING_URL:
- r = requests.post(settings.PING_URL.format(
- schedule_id=self.object.schedule.id,
- token=self.object.token,
- ))
- ok = r.ok
+ try:
+ ok = jobs.request(json.dumps({
+ 'schedule': self.object.schedule.id,
+ 'token': self.object.token,
+ }))
+ except TimeoutError:
+ ok = False
if ok:
messages.success(self.request, _('Your booking has been saved.'))
else:
diff --git a/scheduler/settings/default.py b/scheduler/settings/default.py
index 8a263da9c2069c75859fa6d3771a1d1d8aa227a2..0d7d28fc9892fc46e66ec3cb1ce19132f262aee5 100644
--- a/scheduler/settings/default.py
+++ b/scheduler/settings/default.py
@@ -16,6 +16,7 @@ INSTALLED_APPS = [
'django.contrib.flatpages',
'bootstrap4',
'scheduler.main',
+ 'scheduler.jobs',
]
SITE_ID = 1
diff --git a/scheduler/urls.py b/scheduler/urls.py
index 01e3418a3dd0c7cf78d5616765a0229b8981f709..2862516dc5fffdd1e5e3ddfe07419af1331936fc 100644
--- a/scheduler/urls.py
+++ b/scheduler/urls.py
@@ -24,6 +24,7 @@ from django.urls import path
from django.urls import re_path
from django.views.i18n import JavaScriptCatalog
+from .jobs.views import JobView
from .main.views import InvitationApiView
from .main.views import InvitationUpdateView
from .main.views import ScheduleCreateView
@@ -47,6 +48,7 @@ urlpatterns = [
InvitationApiView.as_view(),
name='api-invitation',
),
+ path('api/jobs/', JobView.as_view(), name='jobs'),
path('login/', LoginView.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
path('admin/', admin.site.urls),
diff --git a/setup.cfg b/setup.cfg
index 426fb32d7601381f5b7a14c8be868f7214b4450f..c291ebcd12529c5f8cee33428cf1eb3c9e385c8e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -11,7 +11,6 @@ install_requires =
Django == 3.2.6
django-bootstrap4 == 3.0.1
django-npm == 1.0.0
- requests == 2.26.0
[options.extras_require]
test =