diff --git a/InvenTree/InvenTree/api.py b/InvenTree/InvenTree/api.py index d2524f9fc4..ab239e23f3 100644 --- a/InvenTree/InvenTree/api.py +++ b/InvenTree/InvenTree/api.py @@ -11,21 +11,52 @@ from rest_framework.response import Response from rest_framework.serializers import ValidationError from rest_framework.views import APIView +import InvenTree.version import users.models from InvenTree.filters import SEARCH_ORDER_FILTER from InvenTree.mixins import ListCreateAPI from InvenTree.permissions import RolePermission from part.templatetags.inventree_extras import plugins_info from plugin.serializers import MetadataSerializer +from users.models import ApiToken from .email import is_email_configured from .mixins import RetrieveUpdateAPI from .status import check_system_health, is_worker_running -from .version import (inventreeApiVersion, inventreeDatabase, - inventreeInstanceName, inventreeVersion) from .views import AjaxView +class VersionView(APIView): + """Simple JSON endpoint for InvenTree version information.""" + + permission_classes = [ + permissions.IsAdminUser, + ] + + def get(self, request, *args, **kwargs): + """Return information about the InvenTree server.""" + return JsonResponse({ + 'dev': InvenTree.version.isInvenTreeDevelopmentVersion(), + 'up_to_date': InvenTree.version.isInvenTreeUpToDate(), + 'version': { + 'server': InvenTree.version.inventreeVersion(), + 'api': InvenTree.version.inventreeApiVersion(), + 'commit_hash': InvenTree.version.inventreeCommitHash(), + 'commit_date': InvenTree.version.inventreeCommitDate(), + 'commit_branch': InvenTree.version.inventreeBranch(), + 'python': InvenTree.version.inventreePythonVersion(), + 'django': InvenTree.version.inventreeDjangoVersion() + }, + 'links': { + 'doc': InvenTree.version.inventreeDocUrl(), + 'code': InvenTree.version.inventreeGithubUrl(), + 'credit': InvenTree.version.inventreeCreditsUrl(), + 'app': InvenTree.version.inventreeAppUrl(), + 'bug': f'{InvenTree.version.inventreeGithubUrl()}/issues' + } + }) + + class InfoView(AjaxView): """Simple JSON endpoint for InvenTree information. @@ -40,11 +71,16 @@ class InfoView(AjaxView): def get(self, request, *args, **kwargs): """Serve current server information.""" + is_staff = request.user.is_staff + if not is_staff and request.user.is_anonymous: + # Might be Token auth - check if so + is_staff = self.check_auth_header(request) + data = { 'server': 'InvenTree', - 'version': inventreeVersion(), - 'instance': inventreeInstanceName(), - 'apiVersion': inventreeApiVersion(), + 'version': InvenTree.version.inventreeVersion(), + 'instance': InvenTree.version.inventreeInstanceName(), + 'apiVersion': InvenTree.version.inventreeApiVersion(), 'worker_running': is_worker_running(), 'worker_pending_tasks': self.worker_pending_tasks(), 'plugins_enabled': settings.PLUGINS_ENABLED, @@ -52,12 +88,35 @@ class InfoView(AjaxView): 'email_configured': is_email_configured(), 'debug_mode': settings.DEBUG, 'docker_mode': settings.DOCKER, - 'system_health': check_system_health() if request.user.is_staff else None, - 'database': inventreeDatabase()if request.user.is_staff else None + 'system_health': check_system_health() if is_staff else None, + 'database': InvenTree.version.inventreeDatabase()if is_staff else None, + 'platform': InvenTree.version.inventreePlatform() if is_staff else None, + 'installer': InvenTree.version.inventreeInstaller() if is_staff else None, + 'target': InvenTree.version.inventreeTarget()if is_staff else None, } return JsonResponse(data) + def check_auth_header(self, request): + """Check if user is authenticated via a token in the header.""" + # TODO @matmair: remove after refacgtor of Token check is done + headers = request.headers.get('Authorization', request.headers.get('authorization')) + if not headers: + return False + + auth = headers.strip() + if not (auth.lower().startswith('token') and len(auth.split()) == 2): + return False + + token_key = auth.split()[1] + try: + token = ApiToken.objects.get(key=token_key) + if token.active and token.user and token.user.is_staff: + return True + except ApiToken.DoesNotExist: + pass + return False + class NotFoundView(AjaxView): """Simple JSON view when accessing an invalid API view.""" diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 3697898dea..04e1dbf7f9 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 143 +INVENTREE_API_VERSION = 144 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v144 -> 2023-10-23: https://github.com/inventree/InvenTree/pull/5811 + - Adds version information API endpoint + v143 -> 2023-10-29: https://github.com/inventree/InvenTree/pull/5810 - Extends the status endpoint to include information about system status and health diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 82a21fd331..5c62db8c75 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -36,7 +36,7 @@ from plugin.urls import get_plugin_urls from stock.urls import stock_urls from web.urls import urlpatterns as platform_urls -from .api import APISearchView, InfoView, NotFoundView +from .api import APISearchView, InfoView, NotFoundView, VersionView from .magic_login import GetSimpleLoginView from .social_auth_urls import SocialProviderListView, social_auth_urlpatterns from .views import (AboutView, AppearanceSelectView, CustomConnectionsView, @@ -76,8 +76,9 @@ apipatterns = [ # OpenAPI Schema re_path('schema/', SpectacularAPIView.as_view(custom_settings={'SCHEMA_PATH_PREFIX': '/api/'}), name='schema'), - # InvenTree information endpoint - path('', InfoView.as_view(), name='api-inventree-info'), + # InvenTree information endpoints + path('version/', VersionView.as_view(), name='api-version'), # version info + path('', InfoView.as_view(), name='api-inventree-info'), # server info # Auth API endpoints path('auth/', include([ diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 72b6455ca6..cb64def136 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -97,6 +97,27 @@ def inventreeDocsVersion(): return INVENTREE_SW_VERSION # pragma: no cover +def inventreeDocUrl(): + """Return URL for InvenTree documentation site.""" + tag = inventreeDocsVersion() + return f"https://docs.inventree.org/en/{tag}" + + +def inventreeAppUrl(): + """Return URL for InvenTree app site.""" + return f'{inventreeDocUrl()}/app/app', + + +def inventreeCreditsUrl(): + """Return URL for InvenTree credits site.""" + return "https://docs.inventree.org/en/latest/credits/" + + +def inventreeGithubUrl(): + """Return URL for InvenTree github site.""" + return "https://github.com/InvenTree/InvenTree/" + + def isInvenTreeUpToDate(): """Test if the InvenTree instance is "up to date" with the latest version. @@ -126,6 +147,11 @@ def inventreeDjangoVersion(): return django.get_version() +def inventreePythonVersion(): + """Returns the version of python""" + return sys.version.split(' ')[0] + + def inventreeCommitHash(): """Returns the git commit hash for the running codebase.""" # First look in the environment variables, i.e. if running in docker diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index 8e7e488bad..9abd6748bf 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -2,7 +2,6 @@ import logging import os -import sys from datetime import date, datetime from django import template @@ -222,7 +221,7 @@ def inventree_base_url(*args, **kwargs): @register.simple_tag() def python_version(*args, **kwargs): """Return the current python version.""" - return sys.version.split(' ')[0] + return version.inventreePythonVersion() @register.simple_tag() @@ -302,21 +301,25 @@ def inventree_platform(*args, **kwargs): @register.simple_tag() def inventree_github_url(*args, **kwargs): """Return URL for InvenTree github site.""" - return "https://github.com/InvenTree/InvenTree/" + return version.inventreeGithubUrl() @register.simple_tag() def inventree_docs_url(*args, **kwargs): """Return URL for InvenTree documentation site.""" - tag = version.inventreeDocsVersion() + return version.inventreeDocUrl() - return f"https://docs.inventree.org/en/{tag}" + +@register.simple_tag() +def inventree_app_url(*args, **kwargs): + """Return URL for InvenTree app site.""" + return version.inventreeAppUrl() @register.simple_tag() def inventree_credits_url(*args, **kwargs): """Return URL for InvenTree credits site.""" - return "https://docs.inventree.org/en/latest/credits/" + return version.inventreeCreditsUrl() @register.simple_tag() diff --git a/InvenTree/templates/about.html b/InvenTree/templates/about.html index 0c02ade0e1..7a71c10483 100644 --- a/InvenTree/templates/about.html +++ b/InvenTree/templates/about.html @@ -77,7 +77,7 @@