2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-12-24 21:23:26 +00:00

Merge branch 'master' of https://github.com/inventree/InvenTree into matmair/issue2279

This commit is contained in:
Matthias
2022-01-12 02:13:50 +01:00
96 changed files with 12549 additions and 10196 deletions

View File

@@ -5,14 +5,102 @@ Provides a JSON API for common components.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import json
from django.http.response import HttpResponse
from django.utils.decorators import method_decorator
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from django.conf.urls import url, include
from rest_framework.views import APIView
from rest_framework.exceptions import NotAcceptable, NotFound
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters, generics, permissions
from rest_framework import serializers
from django_q.tasks import async_task
import common.models
import common.serializers
from InvenTree.helpers import inheritors
class CsrfExemptMixin(object):
"""
Exempts the view from CSRF requirements.
"""
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(CsrfExemptMixin, self).dispatch(*args, **kwargs)
class WebhookView(CsrfExemptMixin, APIView):
"""
Endpoint for receiving webhooks.
"""
authentication_classes = []
permission_classes = []
model_class = common.models.WebhookEndpoint
run_async = False
def post(self, request, endpoint, *args, **kwargs):
# get webhook definition
self._get_webhook(endpoint, request, *args, **kwargs)
# check headers
headers = request.headers
try:
payload = json.loads(request.body)
except json.decoder.JSONDecodeError as error:
raise NotAcceptable(error.msg)
# validate
self.webhook.validate_token(payload, headers, request)
# process data
message = self.webhook.save_data(payload, headers, request)
if self.run_async:
async_task(self._process_payload, message.id)
else:
self._process_result(
self.webhook.process_payload(message, payload, headers),
message,
)
# return results
data = self.webhook.get_return(payload, headers, request)
return HttpResponse(data)
def _process_payload(self, message_id):
message = common.models.WebhookMessage.objects.get(message_id=message_id)
self._process_result(
self.webhook.process_payload(message, message.body, message.header),
message,
)
def _process_result(self, result, message):
if result:
message.worked_on = result
message.save()
else:
message.delete()
def _escalate_object(self, obj):
classes = inheritors(obj.__class__)
for cls in classes:
mdl_name = cls._meta.model_name
if hasattr(obj, mdl_name):
return getattr(obj, mdl_name)
return obj
def _get_webhook(self, endpoint, request, *args, **kwargs):
try:
webhook = self.model_class.objects.get(endpoint_id=endpoint)
self.webhook = self._escalate_object(webhook)
self.webhook.init(request, *args, **kwargs)
return self.webhook.process_webhook()
except self.model_class.DoesNotExist:
raise NotFound()
class SettingsList(generics.ListAPIView):
@@ -181,7 +269,6 @@ class NotificationDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = common.models.NotificationMessage.objects.all()
serializer_class = common.serializers.NotificationMessageSerializer
permission_classes = [
UserSettingsPermissions,
]
@@ -249,6 +336,8 @@ settings_api_urls = [
]
common_api_urls = [
# Webhooks
path('webhook/<slug:endpoint>/', WebhookView.as_view(), name='api-webhook'),
# Notifications
url(r'^notifications/', include([