mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 20:16:44 +00:00
Expose API version descriptors for admins via API (#5865)
* Added endpoint to expose API version descriptors for admins * Refactored tests and moved them to seperate file * Switched to raw string * add coverage exclusion * ignore imports (possible fix to multiline imports) * Add OpenApi Schema * removed changes regarding coverage * moved new functions to `version` to keep api_version a pure static file * clean up diff
This commit is contained in:
parent
0af08da6f8
commit
c34e14baec
@ -6,7 +6,8 @@ from django.http import JsonResponse
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from django_q.models import OrmQ
|
from django_q.models import OrmQ
|
||||||
from rest_framework import permissions
|
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||||
|
from rest_framework import permissions, serializers
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
@ -21,8 +22,9 @@ from plugin.serializers import MetadataSerializer
|
|||||||
from users.models import ApiToken
|
from users.models import ApiToken
|
||||||
|
|
||||||
from .email import is_email_configured
|
from .email import is_email_configured
|
||||||
from .mixins import RetrieveUpdateAPI
|
from .mixins import ListAPI, RetrieveUpdateAPI
|
||||||
from .status import check_system_health, is_worker_running
|
from .status import check_system_health, is_worker_running
|
||||||
|
from .version import inventreeApiText
|
||||||
from .views import AjaxView
|
from .views import AjaxView
|
||||||
|
|
||||||
|
|
||||||
@ -57,6 +59,34 @@ class VersionView(APIView):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class VersionSerializer(serializers.Serializer):
|
||||||
|
"""Serializer for a single version."""
|
||||||
|
version = serializers.CharField()
|
||||||
|
date = serializers.CharField()
|
||||||
|
gh = serializers.CharField()
|
||||||
|
text = serializers.CharField()
|
||||||
|
latest = serializers.BooleanField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class for VersionSerializer."""
|
||||||
|
fields = ['version', 'date', 'gh', 'text', 'latest']
|
||||||
|
|
||||||
|
|
||||||
|
class VersionApiSerializer(serializers.Serializer):
|
||||||
|
"""Serializer for the version api endpoint."""
|
||||||
|
VersionSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
|
class VersionTextView(ListAPI):
|
||||||
|
"""Simple JSON endpoint for InvenTree version text."""
|
||||||
|
permission_classes = [permissions.IsAdminUser]
|
||||||
|
|
||||||
|
@extend_schema(responses={200: OpenApiResponse(response=VersionApiSerializer)})
|
||||||
|
def list(self, request, *args, **kwargs):
|
||||||
|
"""Return information about the InvenTree server."""
|
||||||
|
return JsonResponse(inventreeApiText())
|
||||||
|
|
||||||
|
|
||||||
class InfoView(AjaxView):
|
class InfoView(AjaxView):
|
||||||
"""Simple JSON endpoint for InvenTree information.
|
"""Simple JSON endpoint for InvenTree information.
|
||||||
|
|
||||||
|
@ -3,10 +3,9 @@
|
|||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 148
|
INVENTREE_API_VERSION = 148
|
||||||
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
"""
|
INVENTREE_API_TEXT = """
|
||||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
|
||||||
|
|
||||||
v148 -> 2023-11-06 : https://github.com/inventree/InvenTree/pull/5872
|
v148 -> 2023-11-06 : https://github.com/inventree/InvenTree/pull/5872
|
||||||
- Allow "quantity" to be specified when installing an item into another item
|
- Allow "quantity" to be specified when installing an item into another item
|
||||||
|
|
||||||
|
41
InvenTree/InvenTree/test_api_version.py
Normal file
41
InvenTree/InvenTree/test_api_version.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""Tests for api_version."""
|
||||||
|
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from InvenTree.api_version import INVENTREE_API_VERSION
|
||||||
|
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||||
|
from InvenTree.version import inventreeApiText, parse_version_text
|
||||||
|
|
||||||
|
|
||||||
|
class ApiVersionTests(InvenTreeAPITestCase):
|
||||||
|
"""Tests for api_version functions and APIs."""
|
||||||
|
|
||||||
|
def test_api(self):
|
||||||
|
"""Test that the API text is correct."""
|
||||||
|
url = reverse('api-version-text')
|
||||||
|
response = self.client.get(url, format='json')
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
self.assertEqual(len(data), 10)
|
||||||
|
|
||||||
|
def test_inventree_api_text(self):
|
||||||
|
"""Test that the inventreeApiText function works expected."""
|
||||||
|
# Normal run
|
||||||
|
resp = inventreeApiText()
|
||||||
|
self.assertEqual(len(resp), 10)
|
||||||
|
|
||||||
|
# More responses
|
||||||
|
resp = inventreeApiText(20)
|
||||||
|
self.assertEqual(len(resp), 20)
|
||||||
|
|
||||||
|
# Specific version
|
||||||
|
resp = inventreeApiText(start_version=5)
|
||||||
|
self.assertEqual(list(resp)[0], 'v5')
|
||||||
|
|
||||||
|
def test_parse_version_text(self):
|
||||||
|
"""Test that api version text is correctly parsed."""
|
||||||
|
resp = parse_version_text()
|
||||||
|
|
||||||
|
# Check that all texts are parsed
|
||||||
|
self.assertEqual(len(resp), INVENTREE_API_VERSION - 1)
|
@ -36,7 +36,8 @@ from plugin.urls import get_plugin_urls
|
|||||||
from stock.urls import stock_urls
|
from stock.urls import stock_urls
|
||||||
from web.urls import urlpatterns as platform_urls
|
from web.urls import urlpatterns as platform_urls
|
||||||
|
|
||||||
from .api import APISearchView, InfoView, NotFoundView, VersionView
|
from .api import (APISearchView, InfoView, NotFoundView, VersionTextView,
|
||||||
|
VersionView)
|
||||||
from .magic_login import GetSimpleLoginView
|
from .magic_login import GetSimpleLoginView
|
||||||
from .social_auth_urls import (EmailListView, EmailPrimaryView,
|
from .social_auth_urls import (EmailListView, EmailPrimaryView,
|
||||||
EmailRemoveView, EmailVerifyView,
|
EmailRemoveView, EmailVerifyView,
|
||||||
@ -79,6 +80,7 @@ apipatterns = [
|
|||||||
re_path('schema/', SpectacularAPIView.as_view(custom_settings={'SCHEMA_PATH_PREFIX': '/api/'}), name='schema'),
|
re_path('schema/', SpectacularAPIView.as_view(custom_settings={'SCHEMA_PATH_PREFIX': '/api/'}), name='schema'),
|
||||||
|
|
||||||
# InvenTree information endpoints
|
# InvenTree information endpoints
|
||||||
|
path("version-text", VersionTextView.as_view(), name="api-version-text"), # version text
|
||||||
path('version/', VersionView.as_view(), name='api-version'), # version info
|
path('version/', VersionView.as_view(), name='api-version'), # version info
|
||||||
path('', InfoView.as_view(), name='api-inventree-info'), # server info
|
path('', InfoView.as_view(), name='api-inventree-info'), # server info
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ from django.conf import settings
|
|||||||
|
|
||||||
from dulwich.repo import NotGitRepository, Repo
|
from dulwich.repo import NotGitRepository, Repo
|
||||||
|
|
||||||
from .api_version import INVENTREE_API_VERSION
|
from .api_version import INVENTREE_API_TEXT, INVENTREE_API_VERSION
|
||||||
|
|
||||||
# InvenTree software version
|
# InvenTree software version
|
||||||
INVENTREE_SW_VERSION = "0.13.0 dev"
|
INVENTREE_SW_VERSION = "0.13.0 dev"
|
||||||
@ -142,6 +142,52 @@ def inventreeApiVersion():
|
|||||||
return INVENTREE_API_VERSION
|
return INVENTREE_API_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
def parse_version_text():
|
||||||
|
"""Parse the version text to structured data."""
|
||||||
|
patched_data = INVENTREE_API_TEXT.split("\n\n")
|
||||||
|
# Remove first newline on latest version
|
||||||
|
patched_data[0] = patched_data[0].replace("\n", "", 1)
|
||||||
|
|
||||||
|
version_data = {}
|
||||||
|
for version in patched_data:
|
||||||
|
data = version.split("\n")
|
||||||
|
|
||||||
|
version_split = data[0].split(' -> ')
|
||||||
|
version_detail = version_split[1].split(':', 1) if len(version_split) > 1 else ['', ]
|
||||||
|
new_data = {
|
||||||
|
"version": version_split[0].strip(),
|
||||||
|
"date": version_detail[0].strip(),
|
||||||
|
"gh": version_detail[1].strip() if len(version_detail) > 1 else None,
|
||||||
|
"text": data[1:],
|
||||||
|
"latest": False,
|
||||||
|
}
|
||||||
|
version_data[new_data["version"]] = new_data
|
||||||
|
return version_data
|
||||||
|
|
||||||
|
|
||||||
|
INVENTREE_API_TEXT_DATA = parse_version_text()
|
||||||
|
"""Pre-processed API version text."""
|
||||||
|
|
||||||
|
|
||||||
|
def inventreeApiText(versions: int = 10, start_version: int = 0):
|
||||||
|
"""Returns API version descriptors.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
versions: Number of versions to return. Default: 10
|
||||||
|
start_version: first version to report. Defaults to return the latest {versions} versions.
|
||||||
|
"""
|
||||||
|
version_data = INVENTREE_API_TEXT_DATA
|
||||||
|
|
||||||
|
# Define the range of versions to return
|
||||||
|
if start_version == 0:
|
||||||
|
start_version = INVENTREE_API_VERSION - versions
|
||||||
|
|
||||||
|
return {
|
||||||
|
f"v{a}": version_data.get(f"v{a}", None)
|
||||||
|
for a in range(start_version, start_version + versions)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def inventreeDjangoVersion():
|
def inventreeDjangoVersion():
|
||||||
"""Returns the version of Django library."""
|
"""Returns the version of Django library."""
|
||||||
return django.get_version()
|
return django.get_version()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user