mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Plugin loading fixes (#5572)
* Add config function to return external plugins dir * Enable AppMixin support relative to external plugins directory * Fix for urls.py - URL patterns were causing custom app mixin plugins to fail reverse lookup in admin interface - Brought admin URLs up one level * simplify urls.py * Fix plugin registry code which registers plugin URLs - As we have updated InvenTree.urls.py we need to adjust this logic too * Adds redirect for favicon.ico * Handle empty plugins dir
This commit is contained in:
parent
cf4df3402c
commit
47f341d2b5
@ -281,6 +281,12 @@ def get_plugin_file():
|
||||
return plugin_file
|
||||
|
||||
|
||||
def get_plugin_dir():
|
||||
"""Returns the path of the custom plugins directory"""
|
||||
|
||||
return get_setting('INVENTREE_PLUGIN_DIR', 'plugin_dir')
|
||||
|
||||
|
||||
def get_secret_key():
|
||||
"""Return the secret key value which will be used by django.
|
||||
|
||||
|
@ -189,10 +189,6 @@ classic_frontendpatterns = [
|
||||
re_path(r'^about/', AboutView.as_view(), name='about'),
|
||||
re_path(r'^stats/', DatabaseStatsView.as_view(), name='stats'),
|
||||
|
||||
# admin sites
|
||||
re_path(f'^{settings.INVENTREE_ADMIN_URL}/error_log/', include('error_report.urls')),
|
||||
re_path(f'^{settings.INVENTREE_ADMIN_URL}/', admin.site.urls, name='inventree-admin'),
|
||||
|
||||
# DB user sessions
|
||||
path('accounts/sessions/other/delete/', view=CustomSessionDeleteOtherView.as_view(), name='session_delete_other', ),
|
||||
re_path(r'^accounts/sessions/(?P<pk>\w+)/delete/$', view=CustomSessionDeleteView.as_view(), name='session_delete', ),
|
||||
@ -213,22 +209,26 @@ classic_frontendpatterns = [
|
||||
|
||||
new_frontendpatterns = platform_urls
|
||||
|
||||
# Load patterns for frontend according to settings
|
||||
frontendpatterns = []
|
||||
if settings.ENABLE_CLASSIC_FRONTEND:
|
||||
frontendpatterns.append(re_path('', include(classic_frontendpatterns)))
|
||||
if settings.ENABLE_PLATFORM_FRONTEND:
|
||||
frontendpatterns.append(re_path('', include(new_frontendpatterns)))
|
||||
urlpatterns = [
|
||||
# admin sites
|
||||
re_path(f'^{settings.INVENTREE_ADMIN_URL}/error_log/', include('error_report.urls')),
|
||||
re_path(f'^{settings.INVENTREE_ADMIN_URL}/', admin.site.urls, name='inventree-admin'),
|
||||
]
|
||||
|
||||
urlpatterns += backendpatterns
|
||||
|
||||
frontendpatterns = []
|
||||
|
||||
if settings.ENABLE_CLASSIC_FRONTEND:
|
||||
frontendpatterns += classic_frontendpatterns
|
||||
if settings.ENABLE_PLATFORM_FRONTEND:
|
||||
frontendpatterns += new_frontendpatterns
|
||||
|
||||
urlpatterns += frontendpatterns
|
||||
|
||||
# Append custom plugin URLs (if plugin support is enabled)
|
||||
if settings.PLUGINS_ENABLED:
|
||||
frontendpatterns.append(get_plugin_urls())
|
||||
|
||||
urlpatterns = [
|
||||
re_path('', include(frontendpatterns)),
|
||||
re_path('', include(backendpatterns)),
|
||||
]
|
||||
urlpatterns.append(get_plugin_urls())
|
||||
|
||||
# Server running in "DEBUG" mode?
|
||||
if settings.DEBUG:
|
||||
@ -245,5 +245,10 @@ if settings.DEBUG:
|
||||
path('__debug__/', include(debug_toolbar.urls)),
|
||||
] + urlpatterns
|
||||
|
||||
# Redirect for favicon.ico
|
||||
urlpatterns.append(
|
||||
path('favicon.ico', RedirectView.as_view(url=f'{settings.STATIC_ROOT}/img/favicon/favicon.ico'))
|
||||
)
|
||||
|
||||
# Send any unknown URLs to the parts page
|
||||
urlpatterns += [re_path(r'^.*$', RedirectView.as_view(url='/index/', permanent=False), name='index')]
|
||||
|
@ -1,11 +1,14 @@
|
||||
"""Plugin mixin class for AppMixin."""
|
||||
import logging
|
||||
from importlib import reload
|
||||
from pathlib import Path
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
|
||||
from InvenTree.config import get_plugin_dir
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
@ -156,12 +159,22 @@ class AppMixin:
|
||||
- a local file / dir
|
||||
- a package
|
||||
"""
|
||||
try:
|
||||
# for local path plugins
|
||||
plugin_path = '.'.join(plugin.path().relative_to(settings.BASE_DIR).parts)
|
||||
except ValueError: # pragma: no cover
|
||||
path = plugin.path()
|
||||
custom_plugins_dir = get_plugin_dir()
|
||||
|
||||
if path.is_relative_to(settings.BASE_DIR):
|
||||
# Plugins which are located relative to the base code directory
|
||||
plugin_path = '.'.join(path.relative_to(settings.BASE_DIR).parts)
|
||||
elif custom_plugins_dir and path.is_relative_to(custom_plugins_dir):
|
||||
# Plugins which are located relative to the custom plugins directory
|
||||
plugin_path = '.'.join(path.relative_to(custom_plugins_dir).parts)
|
||||
|
||||
# Ensure that the parent directory is added also
|
||||
plugin_path = Path(custom_plugins_dir).parts[-1] + '.' + plugin_path
|
||||
else:
|
||||
# plugin is shipped as package - extract plugin module name
|
||||
plugin_path = plugin.__module__.split('.')[0]
|
||||
|
||||
return plugin_path
|
||||
|
||||
# endregion
|
||||
|
@ -17,14 +17,14 @@ from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.db.utils import IntegrityError, OperationalError, ProgrammingError
|
||||
from django.urls import clear_url_caches, include, re_path
|
||||
from django.urls import clear_url_caches, re_path
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from maintenance_mode.core import (get_maintenance_mode, maintenance_mode_on,
|
||||
set_maintenance_mode)
|
||||
|
||||
from InvenTree.config import get_setting
|
||||
from InvenTree.config import get_plugin_dir
|
||||
from InvenTree.ready import canAppAccessDatabase
|
||||
|
||||
from .helpers import (IntegrationPluginError, get_entrypoints, get_plugins,
|
||||
@ -239,7 +239,7 @@ class PluginsRegistry:
|
||||
if settings.TESTING:
|
||||
custom_dirs = os.getenv('INVENTREE_PLUGIN_TEST_DIR', None)
|
||||
else: # pragma: no cover
|
||||
custom_dirs = get_setting('INVENTREE_PLUGIN_DIR', 'plugin_dir')
|
||||
custom_dirs = get_plugin_dir()
|
||||
|
||||
# Load from user specified directories (unless in testing mode)
|
||||
dirs.append('plugins')
|
||||
@ -577,19 +577,28 @@ class PluginsRegistry:
|
||||
self.plugins_full: Dict[str, InvenTreePlugin] = {}
|
||||
|
||||
def _update_urls(self):
|
||||
from InvenTree.urls import frontendpatterns as urlpattern
|
||||
from InvenTree.urls import urlpatterns as global_pattern
|
||||
"""Due to the order in which plugins are loaded, the patterns in urls.py may be out of date.
|
||||
|
||||
This function updates the patterns in urls.py to ensure that the correct patterns are loaded,
|
||||
and then refreshes the django url cache.
|
||||
|
||||
Note that we also have to refresh the admin site URLS,
|
||||
as any custom AppMixin plugins require admin integration
|
||||
"""
|
||||
|
||||
from InvenTree.urls import urlpatterns
|
||||
from plugin.urls import get_plugin_urls
|
||||
|
||||
for index, url in enumerate(urlpattern):
|
||||
if hasattr(url, 'app_name'):
|
||||
if url.app_name == 'admin':
|
||||
urlpattern[index] = re_path(r'^admin/', admin.site.urls, name='inventree-admin')
|
||||
elif url.app_name == 'plugin':
|
||||
urlpattern[index] = get_plugin_urls()
|
||||
for index, url in enumerate(urlpatterns):
|
||||
|
||||
# Replace frontendpatterns
|
||||
global_pattern[0] = re_path('', include(urlpattern))
|
||||
app_name = getattr(url, 'app_name', None)
|
||||
|
||||
if app_name == 'admin':
|
||||
urlpatterns[index] = re_path(r'^admin/', admin.site.urls, name='inventree-admin')
|
||||
if app_name == 'plugin':
|
||||
urlpatterns[index] = get_plugin_urls()
|
||||
|
||||
# Refresh the URL cache
|
||||
clear_url_caches()
|
||||
# endregion
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user