mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
[FR] Update to OpenAPI from CoreAPI (#4178)
* [FR] Update to OpenAPI from CoreAPI Fixes #3226 * factor request function out * add schema export task * add api-docs * add action to check if diff occured * also wait for docstyle * use full command * add envs for inventree * update inventree before running * use relative path * remove schema action * remove tags to fit 3.0 parsers * fix url base name for reloads * revert change in plugin resolver * remove unused tags * add rapidoc too * declare api regex * fix as suggested by @martonmiklos in https://github.com/inventree/InvenTree/pull/4178#discussion_r1167279443 * set inventree logo * remove Rapidoc
This commit is contained in:
parent
b0f6021002
commit
9d5522c18c
@ -26,6 +26,7 @@ from sentry_sdk.integrations.django import DjangoIntegration
|
||||
|
||||
from . import config
|
||||
from .config import get_boolean_setting, get_custom_file, get_setting
|
||||
from .version import inventreeApiVersion
|
||||
|
||||
INVENTREE_NEWS_URL = 'https://inventree.org/news/feed.atom'
|
||||
|
||||
@ -233,6 +234,7 @@ INSTALLED_APPS = [
|
||||
'django_otp.plugins.otp_static', # Backup codes
|
||||
|
||||
'allauth_2fa', # MFA flow for allauth
|
||||
'drf_spectacular', # API documentation
|
||||
|
||||
'django_ical', # For exporting calendars
|
||||
]
|
||||
@ -356,7 +358,7 @@ REST_FRAMEWORK = {
|
||||
'rest_framework.permissions.DjangoModelPermissions',
|
||||
'InvenTree.permissions.RolePermission',
|
||||
),
|
||||
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
|
||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||
'DEFAULT_METADATA_CLASS': 'InvenTree.metadata.InvenTreeMetadata',
|
||||
'DEFAULT_RENDERER_CLASSES': [
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
@ -367,6 +369,15 @@ if DEBUG:
|
||||
# Enable browsable API if in DEBUG mode
|
||||
REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'].append('rest_framework.renderers.BrowsableAPIRenderer')
|
||||
|
||||
SPECTACULAR_SETTINGS = {
|
||||
'TITLE': 'InvenTree API',
|
||||
'DESCRIPTION': 'API for InvenTree - the intuitive open source inventory management system',
|
||||
'LICENSE': {'MIT': 'https://github.com/inventree/InvenTree/blob/master/LICENSE'},
|
||||
'EXTERNAL_DOCS': {'docs': 'https://docs.inventree.org', 'web': 'https://inventree.org'},
|
||||
'VERSION': inventreeApiVersion(),
|
||||
'SERVE_INCLUDE_SCHEMA': False,
|
||||
}
|
||||
|
||||
WSGI_APPLICATION = 'InvenTree.wsgi.application'
|
||||
|
||||
"""
|
||||
|
@ -9,7 +9,7 @@ from django.contrib import admin
|
||||
from django.urls import include, path, re_path
|
||||
from django.views.generic.base import RedirectView
|
||||
|
||||
from rest_framework.documentation import include_docs_urls
|
||||
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView
|
||||
|
||||
from build.api import build_api_urls
|
||||
from build.urls import build_urls
|
||||
@ -62,9 +62,12 @@ apipatterns = [
|
||||
# Plugin endpoints
|
||||
path('', include(plugin_api_urls)),
|
||||
|
||||
# Webhook endpoints
|
||||
# Common endpoints enpoint
|
||||
path('', include(common_api_urls)),
|
||||
|
||||
# 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'),
|
||||
|
||||
@ -136,7 +139,7 @@ backendpatterns = [
|
||||
re_path(r'^auth/?', auth_request),
|
||||
|
||||
re_path(r'^api/', include(apipatterns)),
|
||||
re_path(r'^api-doc/', include_docs_urls(title='InvenTree API')),
|
||||
re_path(r'^api-doc/', SpectacularRedocView.as_view(url_name='schema'), name='api-doc'),
|
||||
]
|
||||
|
||||
frontendpatterns = [
|
||||
|
@ -9,7 +9,6 @@ import subprocess
|
||||
|
||||
import django
|
||||
|
||||
import common.models
|
||||
from InvenTree.api_version import INVENTREE_API_VERSION
|
||||
|
||||
# InvenTree software version
|
||||
@ -18,11 +17,15 @@ INVENTREE_SW_VERSION = "0.12.0 dev"
|
||||
|
||||
def inventreeInstanceName():
|
||||
"""Returns the InstanceName settings for the current database."""
|
||||
import common.models
|
||||
|
||||
return common.models.InvenTreeSetting.get_setting("INVENTREE_INSTANCE", "")
|
||||
|
||||
|
||||
def inventreeInstanceTitle():
|
||||
"""Returns the InstanceTitle for the current database."""
|
||||
import common.models
|
||||
|
||||
if common.models.InvenTreeSetting.get_setting("INVENTREE_INSTANCE_TITLE", False):
|
||||
return common.models.InvenTreeSetting.get_setting("INVENTREE_INSTANCE", "")
|
||||
else:
|
||||
@ -66,6 +69,7 @@ def isInvenTreeUpToDate():
|
||||
|
||||
A background task periodically queries GitHub for latest version, and stores it to the database as "_INVENTREE_LATEST_VERSION"
|
||||
"""
|
||||
import common.models
|
||||
latest = common.models.InvenTreeSetting.get_setting('_INVENTREE_LATEST_VERSION', backup_value=None, create=False)
|
||||
|
||||
# No record for "latest" version - we must assume we are up to date!
|
||||
|
@ -27,6 +27,7 @@ django-user-sessions # user sessions in DB
|
||||
django-weasyprint # django weasyprint integration
|
||||
djangorestframework # DRF framework
|
||||
django-xforwardedfor-middleware # IP forwarding metadata
|
||||
drf-spectacular # DRF API documentation
|
||||
feedparser # RSS newsfeed parser
|
||||
gunicorn # Gunicorn web server
|
||||
pdf2image # PDF to image conversion
|
||||
|
@ -8,6 +8,8 @@ arrow==1.2.3
|
||||
# via django-q
|
||||
asgiref==3.6.0
|
||||
# via django
|
||||
attrs==22.2.0
|
||||
# via jsonschema
|
||||
babel==2.12.1
|
||||
# via py-moneyed
|
||||
bleach[css]==6.0.0
|
||||
@ -70,6 +72,7 @@ django==3.2.18
|
||||
# django-weasyprint
|
||||
# django-xforwardedfor-middleware
|
||||
# djangorestframework
|
||||
# drf-spectacular
|
||||
django-allauth==0.54.0
|
||||
# via
|
||||
# -r requirements.in
|
||||
@ -129,6 +132,10 @@ django-weasyprint==2.2.0
|
||||
django-xforwardedfor-middleware==2.0
|
||||
# via -r requirements.in
|
||||
djangorestframework==3.14.0
|
||||
# via
|
||||
# -r requirements.in
|
||||
# drf-spectacular
|
||||
drf-spectacular==0.25.1
|
||||
# via -r requirements.in
|
||||
et-xmlfile==1.1.0
|
||||
# via openpyxl
|
||||
@ -146,10 +153,14 @@ idna==3.4
|
||||
# via requests
|
||||
importlib-metadata==6.1.0
|
||||
# via markdown
|
||||
inflection==0.5.1
|
||||
# via drf-spectacular
|
||||
itypes==1.2.0
|
||||
# via coreapi
|
||||
jinja2==3.1.2
|
||||
# via coreschema
|
||||
jsonschema==4.17.3
|
||||
# via drf-spectacular
|
||||
markdown==3.4.3
|
||||
# via django-markdownify
|
||||
markuppy==1.14
|
||||
@ -186,6 +197,8 @@ pyphen==0.14.0
|
||||
# via weasyprint
|
||||
pypng==0.20220715.0
|
||||
# via qrcode
|
||||
pyrsistent==0.19.3
|
||||
# via jsonschema
|
||||
python-barcode[images]==0.14.0
|
||||
# via -r requirements.in
|
||||
python-dateutil==2.8.2
|
||||
@ -204,7 +217,9 @@ pytz==2023.3
|
||||
# djangorestframework
|
||||
# icalendar
|
||||
pyyaml==6.0
|
||||
# via tablib
|
||||
# via
|
||||
# drf-spectacular
|
||||
# tablib
|
||||
qrcode[pil]==7.4.2
|
||||
# via
|
||||
# -r requirements.in
|
||||
@ -252,7 +267,9 @@ tinycss2==1.1.1
|
||||
typing-extensions==4.5.0
|
||||
# via qrcode
|
||||
uritemplate==4.1.1
|
||||
# via coreapi
|
||||
# via
|
||||
# coreapi
|
||||
# drf-spectacular
|
||||
urllib3==1.26.15
|
||||
# via
|
||||
# requests
|
||||
|
34
tasks.py
34
tasks.py
@ -88,6 +88,22 @@ def manage(c, cmd, pty: bool = False):
|
||||
), pty=pty)
|
||||
|
||||
|
||||
def check_file_existance(filename: str, overwrite: bool = False):
|
||||
"""Checks if a file exists and asks the user if it should be overwritten.
|
||||
|
||||
Args:
|
||||
filename (str): Name of the file to check.
|
||||
overwrite (bool, optional): Overwrite the file without asking. Defaults to False.
|
||||
"""
|
||||
if Path(filename).is_file() and overwrite is False:
|
||||
response = input("Warning: file already exists. Do you want to overwrite? [y/N]: ")
|
||||
response = str(response).strip().lower()
|
||||
|
||||
if response not in ['y', 'yes']:
|
||||
print("Cancelled export operation")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Install tasks
|
||||
@task
|
||||
def plugins(c):
|
||||
@ -305,13 +321,7 @@ def export_records(c, filename='data.json', overwrite=False, include_permissions
|
||||
|
||||
print(f"Exporting database records to file '{filename}'")
|
||||
|
||||
if Path(filename).is_file() and overwrite is False:
|
||||
response = input("Warning: file already exists. Do you want to overwrite? [y/N]: ")
|
||||
response = str(response).strip().lower()
|
||||
|
||||
if response not in ['y', 'yes']:
|
||||
print("Cancelled export operation")
|
||||
sys.exit(1)
|
||||
check_file_existance(filename, overwrite)
|
||||
|
||||
tmpfile = f"{filename}.tmp"
|
||||
|
||||
@ -621,3 +631,13 @@ def coverage(c):
|
||||
|
||||
# Generate coverage report
|
||||
c.run('coverage html -i')
|
||||
|
||||
|
||||
@task(help={
|
||||
'filename': "Output filename (default = 'schema.yml')",
|
||||
'overwrite': "Overwrite existing files without asking first (default = off/False)",
|
||||
})
|
||||
def schema(c, filename='schema.yml', overwrite=False):
|
||||
"""Export current API schema."""
|
||||
check_file_existance(filename, overwrite)
|
||||
manage(c, f'spectacular --file {filename}')
|
||||
|
Loading…
Reference in New Issue
Block a user