mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-02-24 23:40:45 +01:00
Add plugin system enhancements and testPlugin
- Enhanced plugin installer to properly extract and install plugins - Added security middleware exception for plugin webhook endpoints - Improved plugin listing with better error handling - Added testPlugin as example plugin for CyberPanel plugin system - Updated INSTALLED_APPS and URL routing for plugins Author: master3395
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
<plugin>
|
||||
<name>Test Plugin</name>
|
||||
<type>Utility</type>
|
||||
<description>A comprehensive test plugin for CyberPanel with enable/disable functionality, test button, popup messages, and inline integration</description>
|
||||
<version>1.0.0</version>
|
||||
<description>A comprehensive test plugin for CyberPanel with enable/disable functionality, test button, popup messages, and inline integration</description>
|
||||
<author>CyberPanel Development Team</author>
|
||||
<website>https://github.com/cyberpanel/testPlugin</website>
|
||||
<license>MIT</license>
|
||||
@@ -21,4 +21,6 @@
|
||||
<popup_messages>true</popup_messages>
|
||||
<inline_integration>true</inline_integration>
|
||||
</settings>
|
||||
<url>/plugins/testPlugin/</url>
|
||||
<settings_url>/plugins/testPlugin/settings/</settings_url>
|
||||
</plugin>
|
||||
|
||||
71
testPlugin/templates/testPlugin/index.html
Normal file
71
testPlugin/templates/testPlugin/index.html
Normal file
@@ -0,0 +1,71 @@
|
||||
{% extends "baseTemplate/base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}
|
||||
Test Plugin - {% trans "CyberPanel" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-cog"></i>
|
||||
{% trans "Test Plugin Dashboard" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
</span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">{% trans "Plugin Name" %}</span>
|
||||
<span class="info-box-number">{{ plugin_name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-success">
|
||||
<i class="fas fa-tag"></i>
|
||||
</span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">{% trans "Version" %}</span>
|
||||
<span class="info-box-number">{{ version }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<h4><i class="icon fa fa-info"></i> {% trans "Plugin Information" %}</h4>
|
||||
<p>{{ description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{% trans "Test Plugin Status" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-success">
|
||||
<i class="fas fa-check"></i>
|
||||
{% trans "Test Plugin is working correctly!" %}
|
||||
</div>
|
||||
<p>{% trans "This is a test plugin created for testing CyberPanel plugin functionality." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
165
testPlugin/templates/testPlugin/settings.html
Normal file
165
testPlugin/templates/testPlugin/settings.html
Normal file
@@ -0,0 +1,165 @@
|
||||
{% extends "baseTemplate/index.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}
|
||||
Test Plugin Settings - {% trans "CyberPanel" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-cog"></i>
|
||||
{% trans "Test Plugin Settings" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<strong>{% trans "Plugin Information" %}</strong>
|
||||
<ul class="mb-0 mt-2">
|
||||
<li><strong>{% trans "Name" %}:</strong> {{ plugin_name }}</li>
|
||||
<li><strong>{% trans "Version" %}:</strong> {{ version }}</li>
|
||||
<li><strong>{% trans "Status" %}:</strong> <span class="badge badge-success">{% trans "Active" %}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-sliders-h"></i>
|
||||
{% trans "Configuration Options" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="test_setting_1">
|
||||
<i class="fas fa-toggle-on"></i>
|
||||
{% trans "Enable Test Feature" %}
|
||||
</label>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" id="test_setting_1" name="test_setting_1" checked>
|
||||
<label class="custom-control-label" for="test_setting_1">
|
||||
{% trans "Enable this test feature" %}
|
||||
</label>
|
||||
</div>
|
||||
<small class="form-text text-muted">
|
||||
{% trans "This is a test setting for demonstration purposes." %}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="test_setting_2">
|
||||
<i class="fas fa-text-width"></i>
|
||||
{% trans "Test Text Input" %}
|
||||
</label>
|
||||
<input type="text" class="form-control" id="test_setting_2" name="test_setting_2" placeholder="{% trans 'Enter test value' %}" value="Test Value">
|
||||
<small class="form-text text-muted">
|
||||
{% trans "This is a test text input field." %}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="test_setting_3">
|
||||
<i class="fas fa-list"></i>
|
||||
{% trans "Test Select Option" %}
|
||||
</label>
|
||||
<select class="form-control" id="test_setting_3" name="test_setting_3">
|
||||
<option value="option1">{% trans "Option 1" %}</option>
|
||||
<option value="option2" selected>{% trans "Option 2" %}</option>
|
||||
<option value="option3">{% trans "Option 3" %}</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">
|
||||
{% trans "Select a test option from the dropdown." %}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save"></i>
|
||||
{% trans "Save Settings" %}
|
||||
</button>
|
||||
<button type="reset" class="btn btn-secondary">
|
||||
<i class="fas fa-undo"></i>
|
||||
{% trans "Reset" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{% trans "Plugin Status" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-success">
|
||||
<i class="fas fa-check"></i>
|
||||
<strong>{% trans "Plugin is Active" %}</strong>
|
||||
<p class="mb-0 mt-2">{% trans "The Test Plugin is installed and working correctly." %}</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
</span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">{% trans "Plugin Name" %}</span>
|
||||
<span class="info-box-number">{{ plugin_name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="info-box">
|
||||
<span class="info-box-icon bg-success">
|
||||
<i class="fas fa-tag"></i>
|
||||
</span>
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">{% trans "Version" %}</span>
|
||||
<span class="info-box-number">{{ version }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
{% trans "About This Plugin" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>{{ description }}</p>
|
||||
<p>{% trans "This is a test plugin created for testing CyberPanel plugin functionality. You can use this plugin to verify that the plugin system is working correctly." %}</p>
|
||||
|
||||
<h5>{% trans "Features" %}</h5>
|
||||
<ul>
|
||||
<li>{% trans "Enable/disable functionality" %}</li>
|
||||
<li>{% trans "Test button" %}</li>
|
||||
<li>{% trans "Popup messages" %}</li>
|
||||
<li>{% trans "Inline integration" %}</li>
|
||||
<li>{% trans "Settings page" %}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,18 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = 'testPlugin'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.plugin_home, name='plugin_home'),
|
||||
path('test/', views.test_button, name='test_button'),
|
||||
path('toggle/', views.toggle_plugin, name='toggle_plugin'),
|
||||
path('settings/', views.plugin_settings, name='plugin_settings'),
|
||||
path('update-settings/', views.update_settings, name='update_settings'),
|
||||
path('install/', views.install_plugin, name='install_plugin'),
|
||||
path('uninstall/', views.uninstall_plugin, name='uninstall_plugin'),
|
||||
path('logs/', views.plugin_logs, name='plugin_logs'),
|
||||
path('docs/', views.plugin_docs, name='plugin_docs'),
|
||||
path('security/', views.security_info, name='security_info'),
|
||||
path('', views.test_plugin_view, name='testPlugin'),
|
||||
path('info/', views.plugin_info_view, name='testPluginInfo'),
|
||||
path('settings/', views.settings_view, name='testPluginSettings'),
|
||||
]
|
||||
|
||||
@@ -1,324 +1,54 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import os
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.http import JsonResponse, HttpResponse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.contrib import messages
|
||||
from django.utils import timezone
|
||||
from django.core.cache import cache
|
||||
from plogical.httpProc import httpProc
|
||||
from .models import TestPluginSettings, TestPluginLog
|
||||
from .security import secure_view, admin_required, SecurityManager
|
||||
from django.shortcuts import render, redirect
|
||||
from django.http import JsonResponse
|
||||
from functools import wraps
|
||||
|
||||
def cyberpanel_login_required(view_func):
|
||||
"""
|
||||
Custom decorator that checks for CyberPanel session userID
|
||||
"""
|
||||
@wraps(view_func)
|
||||
def _wrapped_view(request, *args, **kwargs):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
# User is authenticated via CyberPanel session
|
||||
return view_func(request, *args, **kwargs)
|
||||
except KeyError:
|
||||
# Not logged in, redirect to login
|
||||
return redirect('/')
|
||||
return _wrapped_view
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=False, rate_limit=True, log_activity=True)
|
||||
def plugin_home(request):
|
||||
"""Main plugin page with inline integration"""
|
||||
try:
|
||||
# Get or create plugin settings
|
||||
settings, created = TestPluginSettings.objects.get_or_create(
|
||||
user=request.user,
|
||||
defaults={'plugin_enabled': True}
|
||||
)
|
||||
|
||||
# Get recent logs (limit to user's own logs for security)
|
||||
recent_logs = TestPluginLog.objects.filter(user=request.user).order_by('-timestamp')[:10]
|
||||
|
||||
context = {
|
||||
'settings': settings,
|
||||
'recent_logs': recent_logs,
|
||||
'plugin_enabled': settings.plugin_enabled,
|
||||
}
|
||||
|
||||
# Log page visit
|
||||
TestPluginLog.objects.create(
|
||||
user=request.user,
|
||||
action='page_visit',
|
||||
message='Visited plugin home page'
|
||||
)
|
||||
|
||||
proc = httpProc(request, 'testPlugin/plugin_home.html', context, 'admin')
|
||||
return proc.render()
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in plugin_home: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while loading the page.'})
|
||||
@cyberpanel_login_required
|
||||
def test_plugin_view(request):
|
||||
"""
|
||||
Main view for the test plugin
|
||||
"""
|
||||
context = {
|
||||
'plugin_name': 'Test Plugin',
|
||||
'version': '1.0.0',
|
||||
'description': 'A simple test plugin for CyberPanel'
|
||||
}
|
||||
return render(request, 'testPlugin/index.html', context)
|
||||
|
||||
@cyberpanel_login_required
|
||||
def plugin_info_view(request):
|
||||
"""
|
||||
API endpoint for plugin information
|
||||
"""
|
||||
return JsonResponse({
|
||||
'plugin_name': 'Test Plugin',
|
||||
'version': '1.0.0',
|
||||
'status': 'active',
|
||||
'description': 'A simple test plugin for CyberPanel testing'
|
||||
})
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=True, rate_limit=True, log_activity=True)
|
||||
@require_http_methods(["POST"])
|
||||
def test_button(request):
|
||||
"""Handle test button click and show popup message"""
|
||||
try:
|
||||
settings, created = TestPluginSettings.objects.get_or_create(
|
||||
user=request.user,
|
||||
defaults={'plugin_enabled': True}
|
||||
)
|
||||
|
||||
if not settings.plugin_enabled:
|
||||
SecurityManager.log_security_event(request, "Test button clicked while plugin disabled", "security_violation")
|
||||
return JsonResponse({
|
||||
'status': 0,
|
||||
'error_message': 'Plugin is disabled. Please enable it first.'
|
||||
})
|
||||
|
||||
# Rate limiting for test button (max 10 clicks per minute)
|
||||
test_key = f"test_button_{request.user.id}"
|
||||
test_count = cache.get(test_key, 0)
|
||||
if test_count >= 10:
|
||||
SecurityManager.record_failed_attempt(request, "Test button rate limit exceeded")
|
||||
return JsonResponse({
|
||||
'status': 0,
|
||||
'error_message': 'Too many test button clicks. Please wait before trying again.'
|
||||
}, status=429)
|
||||
|
||||
cache.set(test_key, test_count + 1, 60) # 1 minute window
|
||||
|
||||
# Increment test count
|
||||
settings.test_count += 1
|
||||
settings.save()
|
||||
|
||||
# Create log entry
|
||||
TestPluginLog.objects.create(
|
||||
user=request.user,
|
||||
action='test_button_click',
|
||||
message=f'Test button clicked (count: {settings.test_count})'
|
||||
)
|
||||
|
||||
# Sanitize custom message
|
||||
safe_message = SecurityManager.sanitize_input(settings.custom_message)
|
||||
|
||||
# Prepare popup message
|
||||
popup_message = {
|
||||
'type': 'success',
|
||||
'title': 'Test Successful!',
|
||||
'message': f'{safe_message} (Clicked {settings.test_count} times)',
|
||||
'timestamp': timezone.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
|
||||
return JsonResponse({
|
||||
'status': 1,
|
||||
'popup_message': popup_message,
|
||||
'test_count': settings.test_count
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in test_button: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while processing the test.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=True, rate_limit=True, log_activity=True)
|
||||
@require_http_methods(["POST"])
|
||||
def toggle_plugin(request):
|
||||
"""Toggle plugin enable/disable state"""
|
||||
try:
|
||||
settings, created = TestPluginSettings.objects.get_or_create(
|
||||
user=request.user,
|
||||
defaults={'plugin_enabled': True}
|
||||
)
|
||||
|
||||
# Toggle the state
|
||||
settings.plugin_enabled = not settings.plugin_enabled
|
||||
settings.save()
|
||||
|
||||
# Log the action
|
||||
action = 'enabled' if settings.plugin_enabled else 'disabled'
|
||||
TestPluginLog.objects.create(
|
||||
user=request.user,
|
||||
action='plugin_toggle',
|
||||
message=f'Plugin {action}'
|
||||
)
|
||||
|
||||
SecurityManager.log_security_event(request, f"Plugin {action} by user", "plugin_toggle")
|
||||
|
||||
return JsonResponse({
|
||||
'status': 1,
|
||||
'enabled': settings.plugin_enabled,
|
||||
'message': f'Plugin {action} successfully'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in toggle_plugin: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while toggling the plugin.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=False, rate_limit=True, log_activity=True)
|
||||
def plugin_settings(request):
|
||||
"""Plugin settings page"""
|
||||
try:
|
||||
settings, created = TestPluginSettings.objects.get_or_create(
|
||||
user=request.user,
|
||||
defaults={'plugin_enabled': True}
|
||||
)
|
||||
|
||||
context = {
|
||||
'settings': settings,
|
||||
}
|
||||
|
||||
proc = httpProc(request, 'testPlugin/plugin_settings.html', context, 'admin')
|
||||
return proc.render()
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in plugin_settings: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while loading settings.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=True, rate_limit=True, log_activity=True)
|
||||
@require_http_methods(["POST"])
|
||||
def update_settings(request):
|
||||
"""Update plugin settings"""
|
||||
try:
|
||||
settings, created = TestPluginSettings.objects.get_or_create(
|
||||
user=request.user,
|
||||
defaults={'plugin_enabled': True}
|
||||
)
|
||||
|
||||
data = json.loads(request.body)
|
||||
custom_message = data.get('custom_message', settings.custom_message)
|
||||
|
||||
# Validate and sanitize input
|
||||
is_valid, error_msg = SecurityManager.validate_input(custom_message, 'custom_message', 1000)
|
||||
if not is_valid:
|
||||
SecurityManager.record_failed_attempt(request, f"Invalid input: {error_msg}")
|
||||
return JsonResponse({
|
||||
'status': 0,
|
||||
'error_message': f'Invalid input: {error_msg}'
|
||||
}, status=400)
|
||||
|
||||
# Sanitize the message
|
||||
custom_message = SecurityManager.sanitize_input(custom_message)
|
||||
|
||||
settings.custom_message = custom_message
|
||||
settings.save()
|
||||
|
||||
# Log the action
|
||||
TestPluginLog.objects.create(
|
||||
user=request.user,
|
||||
action='settings_update',
|
||||
message=f'Settings updated: custom_message="{custom_message[:50]}..."'
|
||||
)
|
||||
|
||||
SecurityManager.log_security_event(request, "Settings updated successfully", "settings_update")
|
||||
|
||||
return JsonResponse({
|
||||
'status': 1,
|
||||
'message': 'Settings updated successfully'
|
||||
})
|
||||
|
||||
except json.JSONDecodeError:
|
||||
SecurityManager.record_failed_attempt(request, "Invalid JSON in settings update")
|
||||
return JsonResponse({
|
||||
'status': 0,
|
||||
'error_message': 'Invalid data format. Please try again.'
|
||||
}, status=400)
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in update_settings: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while updating settings.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=True, rate_limit=True, log_activity=True)
|
||||
@require_http_methods(["POST"])
|
||||
def install_plugin(request):
|
||||
"""Install plugin (placeholder for future implementation)"""
|
||||
try:
|
||||
# Log the action
|
||||
TestPluginLog.objects.create(
|
||||
user=request.user,
|
||||
action='plugin_install',
|
||||
message='Plugin installation requested'
|
||||
)
|
||||
|
||||
SecurityManager.log_security_event(request, "Plugin installation requested", "plugin_install")
|
||||
|
||||
return JsonResponse({
|
||||
'status': 1,
|
||||
'message': 'Plugin installation completed successfully'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in install_plugin: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred during installation.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=True, rate_limit=True, log_activity=True)
|
||||
@require_http_methods(["POST"])
|
||||
def uninstall_plugin(request):
|
||||
"""Uninstall plugin (placeholder for future implementation)"""
|
||||
try:
|
||||
# Log the action
|
||||
TestPluginLog.objects.create(
|
||||
user=request.user,
|
||||
action='plugin_uninstall',
|
||||
message='Plugin uninstallation requested'
|
||||
)
|
||||
|
||||
SecurityManager.log_security_event(request, "Plugin uninstallation requested", "plugin_uninstall")
|
||||
|
||||
return JsonResponse({
|
||||
'status': 1,
|
||||
'message': 'Plugin uninstallation completed successfully'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in uninstall_plugin: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred during uninstallation.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=False, rate_limit=True, log_activity=True)
|
||||
def plugin_logs(request):
|
||||
"""View plugin logs"""
|
||||
try:
|
||||
# Only show logs for the current user (security isolation)
|
||||
logs = TestPluginLog.objects.filter(user=request.user).order_by('-timestamp')[:50]
|
||||
|
||||
context = {
|
||||
'logs': logs,
|
||||
}
|
||||
|
||||
proc = httpProc(request, 'testPlugin/plugin_logs.html', context, 'admin')
|
||||
return proc.render()
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in plugin_logs: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while loading logs.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=False, rate_limit=True, log_activity=True)
|
||||
def plugin_docs(request):
|
||||
"""View plugin documentation"""
|
||||
try:
|
||||
context = {}
|
||||
|
||||
proc = httpProc(request, 'testPlugin/plugin_docs.html', context, 'admin')
|
||||
return proc.render()
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in plugin_docs: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while loading documentation.'})
|
||||
|
||||
|
||||
@admin_required
|
||||
@secure_view(require_csrf=False, rate_limit=True, log_activity=True)
|
||||
def security_info(request):
|
||||
"""View security information"""
|
||||
try:
|
||||
context = {}
|
||||
|
||||
proc = httpProc(request, 'testPlugin/security_info.html', context, 'admin')
|
||||
return proc.render()
|
||||
|
||||
except Exception as e:
|
||||
SecurityManager.log_security_event(request, f"Error in security_info: {str(e)}", "view_error")
|
||||
return JsonResponse({'status': 0, 'error_message': 'An error occurred while loading security information.'})
|
||||
@cyberpanel_login_required
|
||||
def settings_view(request):
|
||||
"""
|
||||
Settings page for the test plugin
|
||||
"""
|
||||
context = {
|
||||
'plugin_name': 'Test Plugin',
|
||||
'version': '1.0.0',
|
||||
'description': 'A simple test plugin for CyberPanel'
|
||||
}
|
||||
return render(request, 'testPlugin/settings.html', context)
|
||||
|
||||
Reference in New Issue
Block a user