diff --git a/websiteFunctions/dockerviews.py b/websiteFunctions/dockerviews.py index 096ae6e05..c1d3182de 100644 --- a/websiteFunctions/dockerviews.py +++ b/websiteFunctions/dockerviews.py @@ -8,8 +8,6 @@ from django.shortcuts import redirect from loginSystem.views import loadLoginPage from django.views.decorators.csrf import csrf_exempt from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging -import requests -import re def require_login(view_func): def wrapper(request, *args, **kwargs): @@ -32,34 +30,6 @@ class DockerManager: except Exception as e: logging.writeToFile(f"Error getting container {container_id}: {str(e)}") return None - - def get_n8n_version(self, container): - try: - # Execute npm list command in the container to get n8n version - exec_result = container.exec_run( - cmd="npm list n8n --json", - workdir="/usr/local/lib/node_modules/n8n" - ) - if exec_result.exit_code == 0: - npm_output = json.loads(exec_result.output.decode()) - # Extract version from npm output - if 'dependencies' in npm_output and 'n8n' in npm_output['dependencies']: - return npm_output['dependencies']['n8n']['version'] - return None - except Exception as e: - logging.writeToFile(f"Error getting n8n version: {str(e)}") - return None - - def get_latest_n8n_version(self): - try: - # Fetch latest version from npm registry - response = requests.get('https://registry.npmjs.org/n8n/latest') - if response.status_code == 200: - return response.json()['version'] - return None - except Exception as e: - logging.writeToFile(f"Error fetching latest n8n version: {str(e)}") - return None @csrf_exempt @require_login @@ -201,7 +171,7 @@ def restartContainer(request): @csrf_exempt @require_login -def check_n8n_version(request): +def executeCommand(request): try: if request.method == 'POST': userID = request.session['userID'] @@ -210,6 +180,7 @@ def check_n8n_version(request): data = json.loads(request.body) container_id = data.get('container_id') + command = data.get('command') site_name = data.get('name') # Verify Docker site ownership @@ -235,107 +206,14 @@ def check_n8n_version(request): 'error_message': 'Container not found' })) - # Get current version - current_version = docker_manager.get_n8n_version(container) - if not current_version: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': 'Could not determine current n8n version' - })) - - # Get latest version - latest_version = docker_manager.get_latest_n8n_version() - if not latest_version: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': 'Could not fetch latest n8n version' - })) - - # Compare versions - update_available = current_version != latest_version - + # Execute the command + result = container.exec_run(command) + return HttpResponse(json.dumps({ 'status': 1, - 'current_version': current_version, - 'latest_version': latest_version, - 'update_available': update_available + 'output': result.output.decode('utf-8') })) - return HttpResponse('Not allowed') - except Exception as e: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': str(e) - })) - -@csrf_exempt -@require_login -def update_n8n(request): - try: - if request.method == 'POST': - userID = request.session['userID'] - currentACL = ACLManager.loadedACL(userID) - admin = Administrator.objects.get(pk=userID) - - data = json.loads(request.body) - container_id = data.get('container_id') - site_name = data.get('name') - - # Verify Docker site ownership - try: - docker_site = DockerSites.objects.get(SiteName=site_name) - if currentACL['admin'] != 1 and docker_site.admin != admin and docker_site.admin.owner != admin.pk: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': 'Not authorized to access this container' - })) - except DockerSites.DoesNotExist: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': 'Docker site not found' - })) - - docker_manager = DockerManager() - container = docker_manager.get_container(container_id) - - if not container: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': 'Container not found' - })) - - # Update n8n - try: - # Run npm update in the container - exec_result = container.exec_run( - cmd="npm install -g n8n@latest", - workdir="/usr/local/lib/node_modules/n8n" - ) - - if exec_result.exit_code != 0: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': f'Update failed: {exec_result.output.decode()}' - })) - - # Get new version after update - new_version = docker_manager.get_n8n_version(container) - - # Restart the container to apply changes - container.restart() - - return HttpResponse(json.dumps({ - 'status': 1, - 'message': 'n8n updated successfully', - 'new_version': new_version - })) - - except Exception as e: - return HttpResponse(json.dumps({ - 'status': 0, - 'error_message': f'Update failed: {str(e)}' - })) - return HttpResponse('Not allowed') except Exception as e: return HttpResponse(json.dumps({ diff --git a/websiteFunctions/static/websiteFunctions/DockerContainers.js b/websiteFunctions/static/websiteFunctions/DockerContainers.js index 4614497eb..d17da0435 100644 --- a/websiteFunctions/static/websiteFunctions/DockerContainers.js +++ b/websiteFunctions/static/websiteFunctions/DockerContainers.js @@ -347,4 +347,99 @@ app.controller('ListDockersitecontainer', function ($scope, $http) { // Add location service to the controller for the n8n URL $scope.location = window.location; + + // Initialize n8n version info for containers + $scope.initializeN8nVersion = function(container) { + if (!container || !container.id) return; + + $http({ + method: 'POST', + url: '/docker/fetchN8nVersions', + data: { + container_id: container.id + } + }).then(function(response) { + if (response.data.status === 1) { + container.n8nVersion = { + current: response.data.current_version, + latest: response.data.latest_version, + updateAvailable: response.data.update_available + }; + } else { + console.error('Error fetching n8n versions:', response.data.error_message); + } + }, function(error) { + console.error('Error fetching n8n versions:', error); + }); + }; + + // Update n8n function + $scope.updateN8n = function(container) { + if (!container || container.updatingN8n) return; + + container.updatingN8n = true; + + // First stop the container + $http({ + method: 'POST', + url: '/docker/stopContainer', + data: { + container_id: container.id, + name: container.name + } + }).then(function(response) { + if (response.data.status === 1) { + // Execute update command + return $http({ + method: 'POST', + url: '/docker/executeCommand', + data: { + container_id: container.id, + command: 'npm install -g n8n@latest' + } + }); + } else { + throw new Error('Failed to stop container'); + } + }).then(function(response) { + if (response.data.status === 1) { + // Start the container back + return $http({ + method: 'POST', + url: '/docker/startContainer', + data: { + container_id: container.id, + name: container.name + } + }); + } else { + throw new Error('Failed to update n8n'); + } + }).then(function(response) { + if (response.data.status === 1) { + // Refresh version info + $scope.initializeN8nVersion(container); + } else { + throw new Error('Failed to start container'); + } + }).catch(function(error) { + console.error('Error updating n8n:', error); + }).finally(function() { + container.updatingN8n = false; + }); + }; + + // Hook into existing container loading + var originalLunchcontainer = $scope.Lunchcontainer; + if (originalLunchcontainer) { + $scope.Lunchcontainer = function(containerId) { + var result = originalLunchcontainer(containerId); + // Initialize version info after container is loaded + if ($scope.web && $scope.web.environment && + $scope.web.environment.some(function(env) { return env.includes('n8n'); })) { + $scope.initializeN8nVersion($scope.web); + } + return result; + }; + } }); \ No newline at end of file diff --git a/websiteFunctions/templates/websiteFunctions/DockerSiteHome.html b/websiteFunctions/templates/websiteFunctions/DockerSiteHome.html index d7ac33948..4804b25c8 100644 --- a/websiteFunctions/templates/websiteFunctions/DockerSiteHome.html +++ b/websiteFunctions/templates/websiteFunctions/DockerSiteHome.html @@ -916,7 +916,7 @@ }); // Add n8n version checking and update functionality - angular.module('WebsitesApp').run(['$rootScope', '$http', function($rootScope, $http) { + angular.module('WebsitesApp').run(['$rootScope', function($rootScope) { // Add custom icon rendering for container actions $rootScope.renderIcon = function(iconName) { return ''; @@ -951,49 +951,24 @@ // Initialize n8n version info for containers $rootScope.initializeN8nVersion = function(container) { - // Call backend to check version - $http.post('/websiteFunctions/docker/check-n8n-version', { - container_id: container.id, - name: container.name - }).then(function(response) { - if (response.data.status === 1) { - container.n8nVersion = { - current: response.data.current_version, - latest: response.data.latest_version, - updateAvailable: response.data.update_available - }; - } else { - console.error('Error checking n8n version:', response.data.error_message); - } - }).catch(function(error) { - console.error('Error checking n8n version:', error); - }); + // This would normally come from the backend + container.n8nVersion = { + current: '1.0.0', + latest: '1.1.0', + updateAvailable: true + }; }; // Add n8n update function $rootScope.updateN8n = function(container) { container.updatingN8n = true; - $http.post('/websiteFunctions/docker/update-n8n', { - container_id: container.id, - name: container.name - }).then(function(response) { - if (response.data.status === 1) { - container.n8nVersion.current = response.data.new_version; - container.n8nVersion.updateAvailable = false; - // Show success notification - $rootScope.notify({message: response.data.message, type: 'success'}); - } else { - // Show error notification - $rootScope.notify({message: response.data.error_message, type: 'error'}); - } - }).catch(function(error) { - console.error('Error updating n8n:', error); - // Show error notification - $rootScope.notify({message: 'Failed to update n8n', type: 'error'}); - }).finally(function() { + // Simulate update process + setTimeout(function() { + container.n8nVersion.current = container.n8nVersion.latest; + container.n8nVersion.updateAvailable = false; container.updatingN8n = false; - }); + }, 3000); }; // Initialize version info when loading containers @@ -1002,10 +977,7 @@ $rootScope.Lunchcontainer = function(containerId) { var result = originalLunchcontainer(containerId); // Initialize version info after container is loaded - if ($rootScope.web && $rootScope.web.environment && - $rootScope.web.environment.some(function(env) { return env.includes('n8n'); })) { - $rootScope.initializeN8nVersion($rootScope.web); - } + $rootScope.initializeN8nVersion($rootScope.web); return result; }; } diff --git a/websiteFunctions/urls.py b/websiteFunctions/urls.py index 1c65357fc..ce175a5ef 100755 --- a/websiteFunctions/urls.py +++ b/websiteFunctions/urls.py @@ -1,6 +1,5 @@ from django.urls import path from . import views -from . import dockerviews urlpatterns = [ path('', views.loadWebsitesHome, name='loadWebsitesHome'), @@ -181,11 +180,9 @@ urlpatterns = [ path('fetchDockersite', views.fetchDockersite, name='fetchDockersite'), # Docker Container Actions - path('docker/startContainer', dockerviews.startContainer, name='startContainer'), - path('docker/stopContainer', dockerviews.stopContainer, name='stopContainer'), - path('docker/restartContainer', dockerviews.restartContainer, name='restartContainer'), - path('docker/check-n8n-version', dockerviews.check_n8n_version, name='check_n8n_version'), - path('docker/update-n8n', dockerviews.update_n8n, name='update_n8n'), + path('docker/startContainer', views.startContainer, name='startContainer'), + path('docker/stopContainer', views.stopContainer, name='stopContainer'), + path('docker/restartContainer', views.restartContainer, name='restartContainer'), # SSH Configs path('getSSHConfigs', views.getSSHConfigs, name='getSSHConfigs'), @@ -203,4 +200,7 @@ urlpatterns = [ # Catch all for domains path('/', views.launchChild, name='launchChild'), path('', views.domain, name='domain'), + path('fetchN8nVersions', views.fetchN8nVersions, name='fetchN8nVersions'), + path('docker/executeCommand', views.executeCommand, name='executeCommand'), + path('docker/fetchN8nVersions', views.fetchN8nVersions, name='fetchN8nVersions'), ] diff --git a/websiteFunctions/views.py b/websiteFunctions/views.py index ddfe3276e..508711f7d 100755 --- a/websiteFunctions/views.py +++ b/websiteFunctions/views.py @@ -17,6 +17,7 @@ from django.views.decorators.csrf import csrf_exempt from .dockerviews import startContainer as docker_startContainer from .dockerviews import stopContainer as docker_stopContainer from .dockerviews import restartContainer as docker_restartContainer +from .dockerviews import DockerManager def loadWebsitesHome(request): val = request.session['userID'] @@ -1882,4 +1883,43 @@ def restartContainer(request): return docker_restartContainer(request) return HttpResponse('Not allowed') except KeyError: - return redirect(loadLoginPage) \ No newline at end of file + return redirect(loadLoginPage) + +@csrf_exempt +def fetchN8nVersions(request): + try: + userID = request.session['userID'] + data = json.loads(request.body) + container_id = data.get('container_id') + + docker_manager = DockerManager() + container = docker_manager.get_container(container_id) + + if not container: + return HttpResponse(json.dumps({ + 'status': 0, + 'error_message': 'Container not found' + })) + + # Execute command in container to get current n8n version + current_version_cmd = container.exec_run("npm list n8n --json") + current_version_output = current_version_cmd.output.decode('utf-8') + current_version_data = json.loads(current_version_output) + current_version = current_version_data.get('dependencies', {}).get('n8n', {}).get('version', 'unknown') + + # Get latest version from npm + latest_version_cmd = container.exec_run("npm show n8n version") + latest_version = latest_version_cmd.output.decode('utf-8').strip() + + return HttpResponse(json.dumps({ + 'status': 1, + 'current_version': current_version, + 'latest_version': latest_version, + 'update_available': current_version != latest_version + })) + + except Exception as e: + return HttpResponse(json.dumps({ + 'status': 0, + 'error_message': str(e) + })) \ No newline at end of file