diff --git a/.gitignore b/.gitignore
index b0d71b26..ad9c1fc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,6 +78,7 @@ postgresql/
/docker-compose.override.yml
vue/node_modules
+plugins
.vscode/
vetur.config.js
cookbook/static/vue
diff --git a/.idea/recipes.iml b/.idea/recipes.iml
index 1b96c9d8..8a0e59c8 100644
--- a/.idea/recipes.iml
+++ b/.idea/recipes.iml
@@ -18,7 +18,7 @@
-
+
diff --git a/recipes/settings.py b/recipes/settings.py
index 3dd93bf2..8fed7258 100644
--- a/recipes/settings.py
+++ b/recipes/settings.py
@@ -13,6 +13,8 @@ import ast
import json
import os
import re
+import sys
+import traceback
from django.contrib import messages
from django.utils.translation import gettext_lazy as _
@@ -117,6 +119,34 @@ INSTALLED_APPS = [
'treebeard',
]
+PLUGINS = []
+try:
+ for d in os.listdir(os.path.join(BASE_DIR, 'recipes', 'plugins')):
+ if d != '__pycache__':
+ try:
+ apps_path = f'recipes.plugins.{d}.apps'
+ __import__(apps_path)
+ app_config_classname = dir(sys.modules[apps_path])[1]
+ plugin_module = f'recipes.plugins.{d}.apps.{app_config_classname}'
+ if plugin_module not in INSTALLED_APPS:
+ INSTALLED_APPS.append(plugin_module)
+ plugin_class = getattr(sys.modules[apps_path], app_config_classname)
+ plugin_config = {
+ 'name': plugin_class.verbose_name if hasattr(plugin_class, 'verbose_name') else plugin_class.name,
+ 'module': f'recipes.plugins.{d}',
+ 'base_path': os.path.join(BASE_DIR, 'recipes', 'plugins', d),
+ 'base_url': plugin_class.base_url,
+ 'bundle_name': plugin_class.bundle_name if hasattr(plugin_class, 'bundle_name') else '',
+ }
+ PLUGINS.append(plugin_config)
+ except Exception:
+ if DEBUG:
+ traceback.print_exc()
+ print(f'ERROR failed to initialize plugin {d}')
+except Exception:
+ if DEBUG:
+ print('ERROR failed to initialize plugins')
+
SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split(',') if os.getenv('SOCIAL_PROVIDERS') else []
SOCIALACCOUNT_EMAIL_VERIFICATION = 'none'
INSTALLED_APPS = INSTALLED_APPS + SOCIAL_PROVIDERS
@@ -362,9 +392,20 @@ WEBPACK_LOADER = {
'POLL_INTERVAL': 0.1,
'TIMEOUT': None,
'IGNORE': [r'.+\.hot-update.js', r'.+\.map'],
- }
+ },
}
+for p in PLUGINS:
+ if p['bundle_name'] != '':
+ WEBPACK_LOADER[p['bundle_name']] = {
+ 'CACHE': not DEBUG,
+ 'BUNDLE_DIR_NAME': f'{p["base_path"]}/vue/', # must end with slash
+ 'STATS_FILE': os.path.join(p["base_path"], 'vue', 'webpack-stats.json'),
+ 'POLL_INTERVAL': 0.1,
+ 'TIMEOUT': None,
+ 'IGNORE': [r'.+\.hot-update.js', r'.+\.map'],
+ }
+
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/
diff --git a/recipes/urls.py b/recipes/urls.py
index ffe02e90..660cbd2e 100644
--- a/recipes/urls.py
+++ b/recipes/urls.py
@@ -14,6 +14,8 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
+import traceback
+
from django.conf import settings
from django.contrib import admin
from django.urls import include, path, re_path
@@ -42,3 +44,15 @@ if settings.ENABLE_METRICS:
if settings.GUNICORN_MEDIA or settings.DEBUG:
urlpatterns += re_path(r'^media/(?P.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
urlpatterns += re_path(r'^jsreverse.json$', reverse_views.urls_js, name='js_reverse'),
+
+for p in settings.PLUGINS:
+ try:
+ urlpatterns += path(p['base_url'], include(f'{p["module"]}.urls')),
+ except ModuleNotFoundError as e:
+ if settings.DEBUG:
+ print(e.msg)
+ print(f'ERROR failed loading plugin <{p["name"]}> urls, did you forget creating urls.py in your plugin?')
+ except Exception as e:
+ if settings.DEBUG:
+ print(f'ERROR failed loading urls for plugin <{p["name"]}>')
+ traceback.format_exc()