diff --git a/boot.sh b/boot.sh
index edd81506d..bced70dd5 100755
--- a/boot.sh
+++ b/boot.sh
@@ -10,6 +10,8 @@ GUNICORN_WORKERS="${GUNICORN_WORKERS:-3}"
GUNICORN_THREADS="${GUNICORN_THREADS:-2}"
GUNICORN_LOG_LEVEL="${GUNICORN_LOG_LEVEL:-'info'}"
+PLUGINS_BUILD="${PLUGINS_BUILD:-0}"
+
if [ "${TANDOOR_PORT}" -eq 80 ]; then
echo "TANDOOR_PORT set to 8080 because 80 is now taken by the integrated nginx"
TANDOOR_PORT=8080
@@ -82,9 +84,15 @@ echo "Database is ready"
echo "Migrating database"
-
python manage.py migrate
+if [ "${PLUGINS_BUILD}" -eq 1 ]; then
+ echo "Running yarn build at startup because PLUGINS_BUILD is enabled"
+ cd vue3
+ yarn build
+ cd ..
+fi
+
echo "Collecting static files, this may take a while..."
python manage.py collectstatic --noinput
diff --git a/cookbook/templates/system.html b/cookbook/templates/system.html
index 7647bfeee..ee673671e 100644
--- a/cookbook/templates/system.html
+++ b/cookbook/templates/system.html
@@ -53,6 +53,17 @@
{% endblocktrans %}
{% endif %}
+
{% trans 'Plugins' %}
+ Clone the plugin using git into the recipe/plugin/ folder (Docker mount /opt/recipe/recipes/plugins to the host system and clone into it).
+
+
{% trans 'Media Serving' %} {% if gunicorn_media %}
{% trans 'Warning' %}{% else %}{% trans 'Ok' %}{% endif %}
{% if gunicorn_media %}
diff --git a/cookbook/urls.py b/cookbook/urls.py
index d91bfecfa..cbc58bbe7 100644
--- a/cookbook/urls.py
+++ b/cookbook/urls.py
@@ -80,8 +80,9 @@ urlpatterns = [
path('switch-space/', views.switch_space, name='view_switch_space'),
path('no-perm/', views.no_perm, name='view_no_perm'),
path('invite/', views.invite_link, name='view_invite'),
- path('system/', views.system, name='view_system'),
+ path('system/', views.system, name='view_system'),
+ path('plugin/update/', views.plugin_update, name='view_plugin_update'),
path('abuse/', views.report_share_abuse, name='view_report_share_abuse'),
diff --git a/cookbook/views/views.py b/cookbook/views/views.py
index 1c8748ad0..04f973704 100644
--- a/cookbook/views/views.py
+++ b/cookbook/views/views.py
@@ -1,5 +1,6 @@
import os
import re
+import subprocess
from datetime import datetime, timedelta
from io import StringIO
from uuid import UUID
@@ -13,7 +14,7 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
from django.contrib.auth.password_validation import validate_password
from django.core.cache import caches
-from django.core.exceptions import ValidationError
+from django.core.exceptions import ValidationError, PermissionDenied
from django.core.management import call_command
from django.db import models
from django.http import HttpResponseRedirect, JsonResponse, HttpResponse
@@ -24,6 +25,7 @@ from django.utils.datetime_safe import date
from django.utils.translation import gettext as _
from django_scopes import scopes_disabled
from drf_spectacular.views import SpectacularRedocView, SpectacularSwaggerView
+from google.api_core.exceptions import BadRequest
from cookbook.forms import Recipe, SpaceCreateForm, SpaceJoinForm, User, UserCreateForm
from cookbook.helper.HelperFunctions import str2bool
@@ -266,6 +268,22 @@ def system(request):
})
+def plugin_update(request):
+ if not request.user.is_superuser:
+ raise PermissionDenied
+
+ if not 'module' in request.GET:
+ raise BadRequest
+
+ for p in PLUGINS:
+ if p['module'] == request.GET['module']:
+ update_response = subprocess.check_output(['git', 'pull'], cwd=p['base_path'])
+ print(update_response)
+ return HttpResponseRedirect(reverse('view_system'))
+
+ return HttpResponseRedirect(reverse('view_system'))
+
+
def setup(request):
with scopes_disabled():
if User.objects.count() > 0 or 'django.contrib.auth.backends.RemoteUserBackend' in settings.AUTHENTICATION_BACKENDS:
diff --git a/recipes/settings.py b/recipes/settings.py
index d9cd8606b..a98d550e5 100644
--- a/recipes/settings.py
+++ b/recipes/settings.py
@@ -221,10 +221,7 @@ try:
'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 '',
'api_router_name': plugin_class.api_router_name if hasattr(plugin_class, 'api_router_name') else '',
- 'nav_main': plugin_class.nav_main if hasattr(plugin_class, 'nav_main') else '',
- 'nav_dropdown': plugin_class.nav_dropdown if hasattr(plugin_class, 'nav_dropdown') else '',
}
PLUGINS.append(plugin_config)
print(f'PLUGIN {d} loaded')
@@ -534,28 +531,6 @@ if REDIS_HOST:
# Vue webpack settings
VUE_DIR = os.path.join(BASE_DIR, 'vue')
-WEBPACK_LOADER = {
- 'DEFAULT': {
- 'CACHE': not DEBUG,
- 'BUNDLE_DIR_NAME': 'vue/', # must end with slash
- 'STATS_FILE': os.path.join(VUE_DIR, 'webpack-stats.json'),
- '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': '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'],
- }
-
DJANGO_VITE = {
"default": {
"dev_mode": False,