mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-12-16 05:19:43 +01:00
- Updated multiple HTML templates to include rel="noopener" on links that open in a new tab, improving security by preventing potential reverse tabnabbing attacks. - This change affects various templates across the backup, base, file manager, mail server, and website functions sections.
1625 lines
58 KiB
HTML
1625 lines
58 KiB
HTML
{% extends "baseTemplate/index.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% trans "Plugin Development Guide - CyberPanel" %}{% endblock %}
|
|
|
|
{% block header_scripts %}
|
|
<style>
|
|
.docs-wrapper {
|
|
background: transparent;
|
|
padding: 20px;
|
|
}
|
|
|
|
.docs-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.docs-header {
|
|
background: var(--bg-primary, white);
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
margin-bottom: 25px;
|
|
box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.08));
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}
|
|
|
|
.docs-content {
|
|
background: var(--bg-primary, white);
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.08));
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}
|
|
|
|
.docs-nav {
|
|
display: flex;
|
|
gap: 15px;
|
|
margin-bottom: 30px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.nav-button {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
color: var(--text-primary, #2f3640);
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
padding: 12px 20px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.nav-button:hover {
|
|
background: #5856d6;
|
|
color: white;
|
|
text-decoration: none;
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.nav-button.active {
|
|
background: #5856d6;
|
|
color: white;
|
|
}
|
|
|
|
.docs-section {
|
|
display: none;
|
|
}
|
|
|
|
.docs-section.active {
|
|
display: block;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 24px;
|
|
font-weight: 700;
|
|
color: var(--text-primary, #2f3640);
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #5856d6;
|
|
}
|
|
|
|
.section-content {
|
|
line-height: 1.6;
|
|
color: var(--text-secondary, #64748b);
|
|
}
|
|
|
|
.section-content h1,
|
|
.section-content h2,
|
|
.section-content h3 {
|
|
color: var(--text-primary, #2f3640);
|
|
margin-top: 30px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.section-content h1 {
|
|
font-size: 28px;
|
|
border-bottom: 2px solid #5856d6;
|
|
padding-bottom: 10px;
|
|
}
|
|
|
|
.section-content h2 {
|
|
font-size: 22px;
|
|
color: #5856d6;
|
|
}
|
|
|
|
.section-content h3 {
|
|
font-size: 18px;
|
|
}
|
|
|
|
.section-content code {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 14px;
|
|
color: #e83e8c;
|
|
}
|
|
|
|
.section-content pre {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
overflow-x: auto;
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
margin: 15px 0;
|
|
}
|
|
|
|
.section-content pre code {
|
|
background: none;
|
|
padding: 0;
|
|
color: var(--text-primary, #2f3640);
|
|
}
|
|
|
|
.section-content ul,
|
|
.section-content ol {
|
|
margin: 15px 0;
|
|
padding-left: 25px;
|
|
}
|
|
|
|
.section-content li {
|
|
margin: 8px 0;
|
|
}
|
|
|
|
.section-content blockquote {
|
|
border-left: 4px solid #5856d6;
|
|
padding-left: 20px;
|
|
margin: 20px 0;
|
|
font-style: italic;
|
|
color: var(--text-secondary, #64748b);
|
|
}
|
|
|
|
.feature-list {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 20px;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.feature-item {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}
|
|
|
|
.feature-item h4 {
|
|
color: #5856d6;
|
|
margin-bottom: 10px;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.back-button {
|
|
background: #6c757d;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 6px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
text-decoration: none;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.back-button:hover {
|
|
background: #5a6268;
|
|
color: white;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.toc {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
margin-bottom: 30px;
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}
|
|
|
|
.toc h3 {
|
|
color: #5856d6;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.toc ul {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.toc li {
|
|
margin: 8px 0;
|
|
}
|
|
|
|
.toc a {
|
|
color: var(--text-secondary, #64748b);
|
|
text-decoration: none;
|
|
transition: color 0.3s ease;
|
|
}
|
|
|
|
.toc a:hover {
|
|
color: #5856d6;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.docs-wrapper {
|
|
padding: 15px;
|
|
}
|
|
|
|
.docs-nav {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.nav-button {
|
|
justify-content: center;
|
|
}
|
|
|
|
.feature-list {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="docs-wrapper">
|
|
<div class="docs-container">
|
|
<!-- Docs Header -->
|
|
<div class="docs-header">
|
|
<h1>
|
|
<i class="fas fa-book" style="margin-right: 12px; color: #5856d6;"></i>
|
|
{% trans "Plugin Development Documentation" %}
|
|
</h1>
|
|
<p>{% trans "Complete guide for developing, installing, and managing CyberPanel plugins" %}</p>
|
|
</div>
|
|
|
|
<!-- Navigation -->
|
|
<div class="docs-nav">
|
|
<a href="#" class="nav-button active" data-section="quick-guide">
|
|
<i class="fas fa-rocket"></i>
|
|
{% trans "Quick Start" %}
|
|
</a>
|
|
<a href="#" class="nav-button" data-section="official-guide">
|
|
<i class="fas fa-graduation-cap"></i>
|
|
{% trans "Official Guide" %}
|
|
</a>
|
|
<a href="#" class="nav-button" data-section="full-guide">
|
|
<i class="fas fa-book-open"></i>
|
|
{% trans "Advanced Guide" %}
|
|
</a>
|
|
<a href="#" class="nav-button" data-section="os-compatibility">
|
|
<i class="fas fa-desktop"></i>
|
|
{% trans "OS Compatibility" %}
|
|
</a>
|
|
<a href="{% url 'testPlugin:plugin_home' %}" class="nav-button">
|
|
<i class="fas fa-arrow-left"></i>
|
|
{% trans "Back to Plugin" %}
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Quick Installation Guide -->
|
|
<div class="docs-section active" id="quick-guide">
|
|
<div class="docs-content">
|
|
<h1 class="section-title">Quick Installation Guide - CyberPanel Test Plugin</h1>
|
|
|
|
<div class="feature-list">
|
|
<div class="feature-item">
|
|
<h4>🚀 One-Command Installation</h4>
|
|
<p>Install the test plugin with a single command using curl or wget.</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>📦 Manual Installation</h4>
|
|
<p>Download and install manually with step-by-step instructions.</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>⚙️ Easy Management</h4>
|
|
<p>Simple install/uninstall process with proper cleanup.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>One-Command Installation</h2>
|
|
<pre><code># Install the test plugin with a single command
|
|
curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash</code></pre>
|
|
|
|
<h2>Manual Installation</h2>
|
|
<ol>
|
|
<li><strong>Download the plugin</strong>
|
|
<pre><code>git clone https://github.com/cyberpanel/testPlugin.git
|
|
cd testPlugin</code></pre>
|
|
</li>
|
|
<li><strong>Run the installation script</strong>
|
|
<pre><code>chmod +x install.sh
|
|
./install.sh</code></pre>
|
|
</li>
|
|
<li><strong>Access the plugin</strong>
|
|
<ul>
|
|
<li>URL: <code>https://your-domain:8090/testPlugin/</code></li>
|
|
<li>Login with your CyberPanel admin credentials</li>
|
|
</ul>
|
|
</li>
|
|
</ol>
|
|
|
|
<h2>Features Included</h2>
|
|
<div class="feature-list">
|
|
<div class="feature-item">
|
|
<h4>✅ Enable/Disable Toggle</h4>
|
|
<p>Toggle the plugin on/off with a beautiful switch</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>✅ Test Button</h4>
|
|
<p>Click to show popup messages from the side</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>✅ Settings Page</h4>
|
|
<p>Configure custom messages and preferences</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>✅ Activity Logs</h4>
|
|
<p>View all plugin activities with filtering</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>✅ Inline Integration</h4>
|
|
<p>Loads within CyberPanel interface</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>✅ Responsive Design</h4>
|
|
<p>Works perfectly on all devices</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Uninstallation</h2>
|
|
<pre><code># Uninstall the plugin
|
|
./install.sh --uninstall</code></pre>
|
|
|
|
<h2>Troubleshooting</h2>
|
|
<p>If you encounter any issues:</p>
|
|
<ol>
|
|
<li><strong>Check CyberPanel logs</strong>
|
|
<pre><code>tail -f /home/cyberpanel/logs/cyberpanel.log</code></pre>
|
|
</li>
|
|
<li><strong>Restart CyberPanel services</strong>
|
|
<pre><code>systemctl restart lscpd
|
|
systemctl restart cyberpanel</code></pre>
|
|
</li>
|
|
<li><strong>Verify installation</strong>
|
|
<pre><code>ls -la /home/cyberpanel/plugins/testPlugin
|
|
ls -la /usr/local/CyberCP/testPlugin</code></pre>
|
|
</li>
|
|
</ol>
|
|
|
|
<blockquote>
|
|
<strong>Note:</strong> This plugin is designed for testing and development purposes. Always backup your system before installing any plugins.
|
|
</blockquote>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Official CyberPanel Plugin Development Guide -->
|
|
<div class="docs-section" id="official-guide">
|
|
<div class="docs-content">
|
|
<h1 class="section-title">Getting Started with CyberPanel Plugin Development</h1>
|
|
|
|
<div class="feature-list">
|
|
<div class="feature-item">
|
|
<h4>🎯 Official Documentation</h4>
|
|
<p>Based on the official CyberPanel plugin development guide from the CyberPanel team.</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>📚 Step-by-Step Tutorial</h4>
|
|
<p>Complete walkthrough from development environment setup to plugin installation.</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>🔧 Signal Integration</h4>
|
|
<p>Learn how to hook into CyberPanel events and respond to core functionality.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<blockquote>
|
|
<strong>Source:</strong> This guide is based on the official CyberPanel documentation and the <a href="https://github.com/usmannasir/beautiful_names" target="_blank" rel="noopener">beautiful_names plugin repository</a>.
|
|
</blockquote>
|
|
|
|
<h2>Prerequisites</h2>
|
|
<ul>
|
|
<li><strong>Python</strong> - Clear understanding of Python Programming Language</li>
|
|
<li><strong>Django</strong> - Experience with Django framework</li>
|
|
<li><strong>HTML (Basic)</strong> - Basic HTML knowledge</li>
|
|
<li><strong>CSS (Basic)</strong> - Basic CSS knowledge</li>
|
|
</ul>
|
|
|
|
<p><strong>Note:</strong> You can use plain JavaScript in your plugins or any JavaScript framework. You just have to follow the norms of Django framework, because CyberPanel plugin is just another Django app.</p>
|
|
|
|
<h2>Step 1: Set up your Development Environment</h2>
|
|
|
|
<h3>Clone CyberPanel Repository</h3>
|
|
<pre><code>git clone https://github.com/usmannasir/cyberpanel/ --single-branch v1.7.2-plugin</code></pre>
|
|
|
|
<h3>Create a Django App</h3>
|
|
<pre><code>cd v1.7.2-plugin
|
|
django-admin startapp pluginName</code></pre>
|
|
|
|
<p>Choose your plugin name wisely as it's of great importance. Once the Django app is created, you need to define a meta file for your plugin so that CyberPanel can read information about your plugin.</p>
|
|
|
|
<h3>Create Meta File</h3>
|
|
<pre><code>cd pluginName
|
|
nano meta.xml</code></pre>
|
|
|
|
<p>Paste the following content in the meta.xml file:</p>
|
|
<pre><code><?xml version="1.0" encoding="UTF-8"?>
|
|
<cyberpanelPluginConfig>
|
|
<name>customplugin</name>
|
|
<type>plugin</type>
|
|
<description>Plugin to make custom changes</description>
|
|
<version>0</version>
|
|
</cyberpanelPluginConfig></code></pre>
|
|
|
|
<h2>Step 2: Creating a Signal File and Adjusting Settings</h2>
|
|
|
|
<h3>Create Signals File</h3>
|
|
<p>Create a signals.py file (you can name it anything, but signals.py is recommended). You can leave this file empty for now.</p>
|
|
|
|
<h3>Configure apps.py</h3>
|
|
<p>In your apps.py file, you need to import the signals file inside the ready function:</p>
|
|
<pre><code>def ready(self):
|
|
import signals</code></pre>
|
|
|
|
<h3>Configure __init__.py</h3>
|
|
<p>You need to specify a default_app_config variable in this file:</p>
|
|
<pre><code>default_app_config = 'examplePlugin.apps.ExamplepluginConfig'</code></pre>
|
|
|
|
<h3>Create urls.py</h3>
|
|
<p>Inside your app root directory, create urls.py and paste this content:</p>
|
|
<pre><code>from django.conf.urls import url
|
|
import views
|
|
|
|
urlpatterns = [
|
|
url(r'^$', views.examplePlugin, name='examplePlugin'),
|
|
]</code></pre>
|
|
|
|
<p><strong>Important:</strong> Replace <code>examplePlugin</code> with your plugin name. This URL definition is very important for CyberPanel to register your plugin page.</p>
|
|
|
|
<h3>Optional Files</h3>
|
|
<p>You can create these optional files for database model management:</p>
|
|
<ul>
|
|
<li><strong>pre_install</strong> - Executed before installation of plugin</li>
|
|
<li><strong>post_install</strong> - Executed after installation of plugin</li>
|
|
</ul>
|
|
|
|
<p>If your file is Python code, don't forget to include this line at the top:</p>
|
|
<pre><code>#!/usr/local/CyberCP/bin/python2</code></pre>
|
|
|
|
<h2>Step 3: Responding to Events</h2>
|
|
|
|
<p>To plug into events fired by CyberPanel core, you can respond to various events happening in the core. Visit the <a href="http://cyberpanel.net/docs/2-list-of-signals-events-files/" target="_blank" rel="noopener">signal file documentation</a> for a complete list of events.</p>
|
|
|
|
<h3>Example Events</h3>
|
|
<ul>
|
|
<li><strong>preWebsiteCreation</strong> - Fired before CyberPanel starts the creation of website</li>
|
|
<li><strong>postWebsiteDeletion</strong> - Fired after core finished the deletion of website</li>
|
|
</ul>
|
|
|
|
<h3>Responding to Events</h3>
|
|
<p>Here's how you can respond to the <code>postWebsiteDeletion</code> event:</p>
|
|
<pre><code>from django.dispatch import receiver
|
|
from django.http import HttpResponse
|
|
from websiteFunctions.signals import postWebsiteDeletion
|
|
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
|
|
|
|
@receiver(postWebsiteDeletion)
|
|
def rcvr(sender, **kwargs):
|
|
request = kwargs['request']
|
|
logging.writeToFile('Hello World from Example Plugin.')
|
|
return HttpResponse('Hello World from Example Plugin.')</code></pre>
|
|
|
|
<h3>Return Values</h3>
|
|
<ul>
|
|
<li><strong>HttpResponse object</strong> - CyberPanel core will stop further processing and return your response to browser</li>
|
|
<li><strong>int 200</strong> - CyberPanel core will continue processing, assuming the event was successfully executed</li>
|
|
</ul>
|
|
|
|
<h2>Step 4: Packing, Shipping and Installing Plugin</h2>
|
|
|
|
<h3>Package Your Plugin</h3>
|
|
<p>After completing your plugin, zip your Django app. The zip file name should be your plugin name (e.g., <code>examplePlugin.zip</code>), otherwise installation will fail.</p>
|
|
|
|
<h3>Installation</h3>
|
|
<p>First, upload your plugin to <code>/usr/local/CyberCP/pluginInstaller</code>:</p>
|
|
<pre><code>cd /usr/local/CyberCP/pluginInstaller
|
|
python pluginInstaller.py install --pluginName examplePlugin</code></pre>
|
|
|
|
<h3>Uninstall</h3>
|
|
<pre><code>cd /usr/local/CyberCP/pluginInstaller
|
|
python pluginInstaller.py remove --pluginName examplePlugin</code></pre>
|
|
|
|
<h2>Beautiful Names Plugin Example</h2>
|
|
<p>CyberPanel has released an official plugin called <a href="https://github.com/usmannasir/beautiful_names" target="_blank" rel="noopener">Beautiful Names</a> that removes the <code>admin_</code> prefix from Package and FTP account names. This plugin serves as a great example of how to create CyberPanel plugins.</p>
|
|
|
|
<h3>Installation of Beautiful Names</h3>
|
|
<pre><code>cd /usr/local/CyberCP/pluginInstaller
|
|
wget https://cyberpanel.net/beautifulNames.zip
|
|
python pluginInstaller.py install --pluginName beautifulNames</code></pre>
|
|
|
|
<h3>Uninstall Beautiful Names</h3>
|
|
<pre><code>cd /usr/local/CyberCP/pluginInstaller
|
|
python pluginInstaller.py remove --pluginName beautifulNames</code></pre>
|
|
|
|
<h2>Plugin Installation Facility</h2>
|
|
<p>The plugin installation facility is in beta and not available with the official install yet. To install plugins, you need to install CyberPanel via the test version:</p>
|
|
<pre><code>sh <(curl https://mirror.cyberpanel.net/install-test.sh || wget -O - https://mirror.cyberpanel.net/install-test.sh)</code></pre>
|
|
|
|
<h2>Additional Resources</h2>
|
|
<ul>
|
|
<li><a href="http://cyberpanel.net/docs/2-list-of-signals-events-files/" target="_blank" rel="noopener">Complete List of Signals and Events</a></li>
|
|
<li><a href="https://github.com/usmannasir/beautiful_names" target="_blank" rel="noopener">Beautiful Names Plugin Repository</a></li>
|
|
<li><a href="https://github.com/usmannasir/cyberpanel" target="_blank" rel="noopener">CyberPanel GitHub Repository</a></li>
|
|
</ul>
|
|
|
|
<blockquote>
|
|
<strong>Note:</strong> This guide is based on the official CyberPanel documentation. For the most up-to-date information, always refer to the official sources.
|
|
</blockquote>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Full Development Guide -->
|
|
<div class="docs-section" id="full-guide">
|
|
<div class="docs-content">
|
|
<h1 class="section-title">CyberPanel Plugin Development Guide</h1>
|
|
|
|
<div class="toc">
|
|
<h3>Table of Contents</h3>
|
|
<ul>
|
|
<li><a href="#install-plugins">How to Install Plugins</a></li>
|
|
<li><a href="#uninstall-plugins">How to Uninstall Plugins</a></li>
|
|
<li><a href="#meta-xml">How to Add meta.xml</a></li>
|
|
<li><a href="#add-buttons">How to Add Buttons for Pages</a></li>
|
|
<li><a href="#add-toggles">How to Add Toggles</a></li>
|
|
<li><a href="#install-uninstall-buttons">How to Add Install/Uninstall Buttons</a></li>
|
|
<li><a href="#enable-disable-buttons">How to Add Enable/Disable Buttons</a></li>
|
|
<li><a href="#avoid-sidebar-breaking">How to Avoid Breaking the Sidebar</a></li>
|
|
<li><a href="#inline-loading">How to Make Plugins Load Inline</a></li>
|
|
<li><a href="#plugin-structure">Plugin Structure Overview</a></li>
|
|
<li><a href="#best-practices">Best Practices</a></li>
|
|
<li><a href="#troubleshooting">Troubleshooting</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="install-plugins">
|
|
<h2>How to Install Plugins</h2>
|
|
|
|
<h3>Method 1: Using the Installation Script (Recommended)</h3>
|
|
<pre><code># Download and run the installation script
|
|
curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash
|
|
|
|
# Or download first, then run
|
|
wget https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh
|
|
chmod +x install.sh
|
|
./install.sh</code></pre>
|
|
|
|
<h3>Method 2: Manual Installation</h3>
|
|
<ol>
|
|
<li><strong>Create Plugin Directory Structure</strong>
|
|
<pre><code>mkdir -p /home/cyberpanel/plugins/yourPlugin
|
|
mkdir -p /usr/local/CyberCP/yourPlugin</code></pre>
|
|
</li>
|
|
<li><strong>Copy Plugin Files</strong>
|
|
<pre><code>cp -r yourPlugin/* /usr/local/CyberCP/yourPlugin/
|
|
chown -R cyberpanel:cyberpanel /usr/local/CyberCP/yourPlugin
|
|
chmod -R 755 /usr/local/CyberCP/yourPlugin</code></pre>
|
|
</li>
|
|
<li><strong>Create Symlink</strong>
|
|
<pre><code>ln -sf /usr/local/CyberCP/yourPlugin /home/cyberpanel/plugins/yourPlugin</code></pre>
|
|
</li>
|
|
<li><strong>Update Django Settings</strong>
|
|
<p>Add your plugin to <code>INSTALLED_APPS</code> in <code>/usr/local/CyberCP/cyberpanel/settings.py</code>:</p>
|
|
<pre><code>INSTALLED_APPS = [
|
|
# ... existing apps ...
|
|
'yourPlugin',
|
|
]</code></pre>
|
|
</li>
|
|
<li><strong>Update URL Configuration</strong>
|
|
<p>Add your plugin URLs in <code>/usr/local/CyberCP/cyberpanel/urls.py</code>:</p>
|
|
<pre><code>urlpatterns = [
|
|
# ... existing patterns ...
|
|
path("yourPlugin/", include("yourPlugin.urls")),
|
|
]</code></pre>
|
|
</li>
|
|
<li><strong>Run Migrations</strong>
|
|
<pre><code>cd /usr/local/CyberCP
|
|
python3 manage.py makemigrations yourPlugin
|
|
python3 manage.py migrate yourPlugin</code></pre>
|
|
</li>
|
|
<li><strong>Collect Static Files</strong>
|
|
<pre><code>python3 manage.py collectstatic --noinput</code></pre>
|
|
</li>
|
|
<li><strong>Restart Services</strong>
|
|
<pre><code>systemctl restart lscpd
|
|
systemctl restart cyberpanel</code></pre>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div id="uninstall-plugins">
|
|
<h2>How to Uninstall Plugins</h2>
|
|
|
|
<h3>Method 1: Using the Installation Script</h3>
|
|
<pre><code># Run with uninstall flag
|
|
./install.sh --uninstall</code></pre>
|
|
|
|
<h3>Method 2: Manual Uninstallation</h3>
|
|
<ol>
|
|
<li><strong>Remove Plugin Files</strong>
|
|
<pre><code>rm -rf /usr/local/CyberCP/yourPlugin
|
|
rm -f /home/cyberpanel/plugins/yourPlugin</code></pre>
|
|
</li>
|
|
<li><strong>Remove from Django Settings</strong>
|
|
<pre><code>sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/settings.py</code></pre>
|
|
</li>
|
|
<li><strong>Remove from URLs</strong>
|
|
<pre><code>sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/urls.py</code></pre>
|
|
</li>
|
|
<li><strong>Restart Services</strong>
|
|
<pre><code>systemctl restart lscpd
|
|
systemctl restart cyberpanel</code></pre>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div id="meta-xml">
|
|
<h2>How to Add meta.xml</h2>
|
|
<p>Create a <code>meta.xml</code> file in your plugin root directory:</p>
|
|
<pre><code><?xml version="1.0" encoding="UTF-8"?>
|
|
<plugin>
|
|
<name>Your Plugin Name</name>
|
|
<type>Utility</type>
|
|
<description>Your plugin description</description>
|
|
<version>1.0.0</version>
|
|
<author>Your Name</author>
|
|
<website>https://your-website.com</website>
|
|
<license>MIT</license>
|
|
<dependencies>
|
|
<python>3.6+</python>
|
|
<django>2.2+</django>
|
|
</dependencies>
|
|
<permissions>
|
|
<admin>true</admin>
|
|
<user>false</user>
|
|
</permissions>
|
|
<settings>
|
|
<enable_toggle>true</enable_toggle>
|
|
<test_button>true</test_button>
|
|
<popup_messages>true</popup_messages>
|
|
<inline_integration>true</inline_integration>
|
|
</settings>
|
|
</plugin></code></pre>
|
|
|
|
<h3>Required Fields:</h3>
|
|
<ul>
|
|
<li><code>name</code>: Plugin display name</li>
|
|
<li><code>type</code>: Plugin category (Utility, Security, Performance, etc.)</li>
|
|
<li><code>description</code>: Plugin description</li>
|
|
<li><code>version</code>: Plugin version</li>
|
|
</ul>
|
|
|
|
<h3>Optional Fields:</h3>
|
|
<ul>
|
|
<li><code>author</code>: Plugin author</li>
|
|
<li><code>website</code>: Plugin website</li>
|
|
<li><code>license</code>: License type</li>
|
|
<li><code>dependencies</code>: Required dependencies</li>
|
|
<li><code>permissions</code>: Access permissions</li>
|
|
<li><code>settings</code>: Plugin-specific settings</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="add-buttons">
|
|
<h2>How to Add Buttons for Pages</h2>
|
|
|
|
<h3>1. In Your Template</h3>
|
|
<pre><code><!-- Primary Action Button -->
|
|
<button class="btn-test" id="your-button">
|
|
<i class="fas fa-icon"></i>
|
|
Button Text
|
|
</button>
|
|
|
|
<!-- Secondary Button -->
|
|
<a href="{% url 'yourPlugin:your_view' %}" class="btn-secondary">
|
|
<i class="fas fa-icon"></i>
|
|
Button Text
|
|
</a>
|
|
|
|
<!-- Danger Button -->
|
|
<button class="btn-danger" id="danger-button">
|
|
<i class="fas fa-trash"></i>
|
|
Delete
|
|
</button></code></pre>
|
|
|
|
<h3>2. CSS Styles</h3>
|
|
<pre><code>.btn-test {
|
|
background: linear-gradient(135deg, #5856d6, #4a90e2);
|
|
color: white;
|
|
border: none;
|
|
padding: 12px 24px;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.btn-test:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 20px rgba(88,86,214,0.3);
|
|
}
|
|
|
|
.btn-test:disabled {
|
|
opacity: 0.6;
|
|
cursor: not-allowed;
|
|
transform: none;
|
|
}</code></pre>
|
|
|
|
<h3>3. JavaScript Event Handling</h3>
|
|
<pre><code>document.getElementById('your-button').addEventListener('click', function() {
|
|
// Your button logic here
|
|
fetch('/yourPlugin/your-endpoint/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCSRFToken()
|
|
},
|
|
body: JSON.stringify({data: 'value'})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 1) {
|
|
showNotification('success', 'Success', data.message);
|
|
} else {
|
|
showNotification('error', 'Error', data.error_message);
|
|
}
|
|
});
|
|
});</code></pre>
|
|
</div>
|
|
|
|
<div id="add-toggles">
|
|
<h2>How to Add Toggles</h2>
|
|
|
|
<h3>1. HTML Structure</h3>
|
|
<pre><code><div class="control-group">
|
|
<label for="plugin-toggle" class="toggle-label">
|
|
Enable Feature
|
|
</label>
|
|
<label class="toggle-switch">
|
|
<input type="checkbox" id="plugin-toggle" {% if feature_enabled %}checked{% endif %}>
|
|
<span class="slider"></span>
|
|
</label>
|
|
</div></code></pre>
|
|
|
|
<h3>2. CSS Styles</h3>
|
|
<pre><code>.toggle-switch {
|
|
position: relative;
|
|
display: inline-block;
|
|
width: 60px;
|
|
height: 34px;
|
|
}
|
|
|
|
.toggle-switch input {
|
|
opacity: 0;
|
|
width: 0;
|
|
height: 0;
|
|
}
|
|
|
|
.slider {
|
|
position: absolute;
|
|
cursor: pointer;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: #ccc;
|
|
transition: .4s;
|
|
border-radius: 34px;
|
|
}
|
|
|
|
.slider:before {
|
|
position: absolute;
|
|
content: "";
|
|
height: 26px;
|
|
width: 26px;
|
|
left: 4px;
|
|
bottom: 4px;
|
|
background-color: white;
|
|
transition: .4s;
|
|
border-radius: 50%;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
|
}
|
|
|
|
input:checked + .slider {
|
|
background-color: #5856d6;
|
|
}
|
|
|
|
input:checked + .slider:before {
|
|
transform: translateX(26px);
|
|
}</code></pre>
|
|
|
|
<h3>3. JavaScript Handling</h3>
|
|
<pre><code>document.getElementById('plugin-toggle').addEventListener('change', function() {
|
|
fetch('/yourPlugin/toggle/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCSRFToken()
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 1) {
|
|
showNotification('success', 'Toggle Updated', data.message);
|
|
} else {
|
|
showNotification('error', 'Error', data.error_message);
|
|
// Revert toggle state
|
|
this.checked = !this.checked;
|
|
}
|
|
});
|
|
});</code></pre>
|
|
</div>
|
|
|
|
<div id="install-uninstall-buttons">
|
|
<h2>How to Add Install/Uninstall Buttons</h2>
|
|
|
|
<h3>1. In Your Plugin Template</h3>
|
|
<pre><code><div class="plugin-actions">
|
|
<button class="btn-install" id="install-plugin">
|
|
<i class="fas fa-download"></i>
|
|
Install Plugin
|
|
</button>
|
|
|
|
<button class="btn-uninstall" id="uninstall-plugin">
|
|
<i class="fas fa-trash"></i>
|
|
Uninstall Plugin
|
|
</button>
|
|
</div></code></pre>
|
|
|
|
<h3>2. CSS Styles</h3>
|
|
<pre><code>.plugin-actions {
|
|
display: flex;
|
|
gap: 10px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.btn-install {
|
|
background: #10b981;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-uninstall {
|
|
background: #ef4444;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-install:hover {
|
|
background: #059669;
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.btn-uninstall:hover {
|
|
background: #dc2626;
|
|
transform: translateY(-2px);
|
|
}</code></pre>
|
|
|
|
<h3>3. JavaScript Implementation</h3>
|
|
<pre><code>// Install button
|
|
document.getElementById('install-plugin').addEventListener('click', function() {
|
|
if (confirm('Are you sure you want to install this plugin?')) {
|
|
this.disabled = true;
|
|
this.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Installing...';
|
|
|
|
fetch('/yourPlugin/install/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCSRFToken()
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 1) {
|
|
showNotification('success', 'Installation Complete', data.message);
|
|
location.reload();
|
|
} else {
|
|
showNotification('error', 'Installation Failed', data.error_message);
|
|
}
|
|
})
|
|
.finally(() => {
|
|
this.disabled = false;
|
|
this.innerHTML = '<i class="fas fa-download"></i> Install Plugin';
|
|
});
|
|
}
|
|
});
|
|
|
|
// Uninstall button
|
|
document.getElementById('uninstall-plugin').addEventListener('click', function() {
|
|
if (confirm('Are you sure you want to uninstall this plugin? This action cannot be undone.')) {
|
|
this.disabled = true;
|
|
this.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Uninstalling...';
|
|
|
|
fetch('/yourPlugin/uninstall/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCSRFToken()
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 1) {
|
|
showNotification('success', 'Uninstallation Complete', data.message);
|
|
setTimeout(() => location.reload(), 2000);
|
|
} else {
|
|
showNotification('error', 'Uninstallation Failed', data.error_message);
|
|
}
|
|
})
|
|
.finally(() => {
|
|
this.disabled = false;
|
|
this.innerHTML = '<i class="fas fa-trash"></i> Uninstall Plugin';
|
|
});
|
|
}
|
|
});</code></pre>
|
|
</div>
|
|
|
|
<div id="enable-disable-buttons">
|
|
<h2>How to Add Enable/Disable Plugin Buttons</h2>
|
|
|
|
<h3>1. Model for Plugin State</h3>
|
|
<pre><code># models.py
|
|
from django.db import models
|
|
from django.contrib.auth.models import User
|
|
|
|
class PluginSettings(models.Model):
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
plugin_enabled = models.BooleanField(default=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class Meta:
|
|
unique_together = ['user']</code></pre>
|
|
|
|
<h3>2. View for Toggle</h3>
|
|
<pre><code># views.py
|
|
from django.http import JsonResponse
|
|
from django.views.decorators.http import require_http_methods
|
|
from .models import PluginSettings
|
|
|
|
@require_http_methods(["POST"])
|
|
def toggle_plugin(request):
|
|
try:
|
|
settings, created = PluginSettings.objects.get_or_create(
|
|
user=request.user,
|
|
defaults={'plugin_enabled': True}
|
|
)
|
|
|
|
settings.plugin_enabled = not settings.plugin_enabled
|
|
settings.save()
|
|
|
|
return JsonResponse({
|
|
'status': 1,
|
|
'enabled': settings.plugin_enabled,
|
|
'message': f'Plugin {"enabled" if settings.plugin_enabled else "disabled"} successfully'
|
|
})
|
|
except Exception as e:
|
|
return JsonResponse({'status': 0, 'error_message': str(e)})</code></pre>
|
|
|
|
<h3>3. Template Implementation</h3>
|
|
<pre><code><div class="plugin-controls">
|
|
<label for="plugin-toggle" class="toggle-label">
|
|
Enable Plugin
|
|
</label>
|
|
<label class="toggle-switch">
|
|
<input type="checkbox" id="plugin-toggle" {% if plugin_enabled %}checked{% endif %}>
|
|
<span class="slider"></span>
|
|
</label>
|
|
</div></code></pre>
|
|
|
|
<h3>4. JavaScript Handling</h3>
|
|
<pre><code>document.getElementById('plugin-toggle').addEventListener('change', function() {
|
|
fetch('/yourPlugin/toggle/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCSRFToken()
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 1) {
|
|
showNotification('success', 'Plugin Toggle', data.message);
|
|
// Update UI elements based on enabled state
|
|
updatePluginUI(data.enabled);
|
|
} else {
|
|
showNotification('error', 'Error', data.error_message);
|
|
this.checked = !this.checked; // Revert toggle
|
|
}
|
|
});
|
|
});
|
|
|
|
function updatePluginUI(enabled) {
|
|
const buttons = document.querySelectorAll('.plugin-button');
|
|
buttons.forEach(button => {
|
|
button.disabled = !enabled;
|
|
});
|
|
|
|
const statusIndicator = document.querySelector('.status-indicator');
|
|
if (statusIndicator) {
|
|
statusIndicator.textContent = enabled ? 'Enabled' : 'Disabled';
|
|
statusIndicator.className = `status-indicator ${enabled ? 'enabled' : 'disabled'}`;
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
|
|
<div id="avoid-sidebar-breaking">
|
|
<h2>How to Avoid Breaking the CyberPanel Sidebar</h2>
|
|
|
|
<h3>1. Use CyberPanel's Base Template</h3>
|
|
<p>Always extend the base template:</p>
|
|
<pre><code>{% extends "baseTemplate/index.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% trans "Your Plugin - CyberPanel" %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- Your plugin content here -->
|
|
{% endblock %}</code></pre>
|
|
|
|
<h3>2. Don't Modify the Sidebar HTML</h3>
|
|
<p>Never directly modify the sidebar HTML. Instead, use CyberPanel's built-in navigation system.</p>
|
|
|
|
<h3>3. Use Proper CSS Scoping</h3>
|
|
<pre><code>/* Good: Scoped to your plugin */
|
|
.your-plugin-wrapper {
|
|
/* Your styles here */
|
|
}
|
|
|
|
/* Bad: Global styles that might affect sidebar */
|
|
.sidebar {
|
|
/* Don't do this */
|
|
}</code></pre>
|
|
|
|
<h3>4. Use CyberPanel's CSS Variables</h3>
|
|
<pre><code>.your-plugin-element {
|
|
background: var(--bg-primary, white);
|
|
color: var(--text-primary, #2f3640);
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}</code></pre>
|
|
|
|
<h3>5. Test Responsive Design</h3>
|
|
<p>Ensure your plugin works on all screen sizes without breaking the sidebar:</p>
|
|
<pre><code>@media (max-width: 768px) {
|
|
.your-plugin-wrapper {
|
|
padding: 15px;
|
|
}
|
|
|
|
/* Don't modify sidebar behavior */
|
|
}</code></pre>
|
|
</div>
|
|
|
|
<div id="inline-loading">
|
|
<h2>How to Make Plugins Load Inline</h2>
|
|
|
|
<h3>1. Use CyberPanel's httpProc</h3>
|
|
<pre><code># views.py
|
|
from plogical.httpProc import httpProc
|
|
|
|
def your_view(request):
|
|
context = {
|
|
'data': 'your_data',
|
|
'plugin_enabled': True
|
|
}
|
|
|
|
proc = httpProc(request, 'yourPlugin/your_template.html', context, 'admin')
|
|
return proc.render()</code></pre>
|
|
|
|
<h3>2. Template Structure</h3>
|
|
<pre><code>{% extends "baseTemplate/index.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% trans "Your Plugin - CyberPanel" %}{% endblock %}
|
|
|
|
{% block header_scripts %}
|
|
<style>
|
|
/* Your plugin-specific styles */
|
|
.your-plugin-wrapper {
|
|
background: transparent;
|
|
padding: 20px;
|
|
}
|
|
|
|
.your-plugin-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="your-plugin-wrapper">
|
|
<div class="your-plugin-container">
|
|
<!-- Your plugin content here -->
|
|
</div>
|
|
</div>
|
|
{% endblock %}</code></pre>
|
|
|
|
<h3>3. URL Configuration</h3>
|
|
<pre><code># urls.py
|
|
from django.urls import path
|
|
from . import views
|
|
|
|
app_name = 'yourPlugin'
|
|
|
|
urlpatterns = [
|
|
path('', views.your_view, name='your_view'),
|
|
path('settings/', views.settings_view, name='settings'),
|
|
# ... other URLs
|
|
]</code></pre>
|
|
|
|
<h3>4. Main URLs Integration</h3>
|
|
<pre><code># In /usr/local/CyberCP/cyberpanel/urls.py
|
|
urlpatterns = [
|
|
# ... existing patterns ...
|
|
path("yourPlugin/", include("yourPlugin.urls")),
|
|
]</code></pre>
|
|
</div>
|
|
|
|
<div id="plugin-structure">
|
|
<h2>Plugin Structure Overview</h2>
|
|
<pre><code>yourPlugin/
|
|
├── __init__.py
|
|
├── admin.py
|
|
├── apps.py
|
|
├── models.py
|
|
├── views.py
|
|
├── urls.py
|
|
├── signals.py
|
|
├── meta.xml
|
|
├── install.sh
|
|
├── templates/
|
|
│ └── yourPlugin/
|
|
│ ├── plugin_home.html
|
|
│ ├── plugin_settings.html
|
|
│ └── plugin_logs.html
|
|
├── static/
|
|
│ └── yourPlugin/
|
|
│ ├── css/
|
|
│ │ └── yourPlugin.css
|
|
│ └── js/
|
|
│ └── yourPlugin.js
|
|
└── migrations/
|
|
└── __init__.py</code></pre>
|
|
</div>
|
|
|
|
<div id="best-practices">
|
|
<h2>Best Practices</h2>
|
|
|
|
<h3>1. Security</h3>
|
|
<ul>
|
|
<li>Always validate user input</li>
|
|
<li>Use CSRF protection</li>
|
|
<li>Sanitize data before displaying</li>
|
|
<li>Use proper authentication decorators</li>
|
|
</ul>
|
|
|
|
<h3>2. Performance</h3>
|
|
<ul>
|
|
<li>Use database indexes for frequently queried fields</li>
|
|
<li>Implement caching where appropriate</li>
|
|
<li>Optimize database queries</li>
|
|
<li>Minimize JavaScript and CSS</li>
|
|
</ul>
|
|
|
|
<h3>3. User Experience</h3>
|
|
<ul>
|
|
<li>Provide clear feedback for all actions</li>
|
|
<li>Use loading states for long operations</li>
|
|
<li>Implement proper error handling</li>
|
|
<li>Make the interface responsive</li>
|
|
</ul>
|
|
|
|
<h3>4. Code Quality</h3>
|
|
<ul>
|
|
<li>Follow Django best practices</li>
|
|
<li>Use meaningful variable names</li>
|
|
<li>Add proper documentation</li>
|
|
<li>Write unit tests</li>
|
|
</ul>
|
|
|
|
<h3>5. Integration</h3>
|
|
<ul>
|
|
<li>Use CyberPanel's existing components</li>
|
|
<li>Follow the established design patterns</li>
|
|
<li>Maintain consistency with the UI</li>
|
|
<li>Test thoroughly before release</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="troubleshooting">
|
|
<h2>Troubleshooting</h2>
|
|
|
|
<h3>Common Issues</h3>
|
|
|
|
<h4>1. Plugin not showing in installed plugins</h4>
|
|
<ul>
|
|
<li>Check if meta.xml exists and is valid</li>
|
|
<li>Verify the plugin is in INSTALLED_APPS</li>
|
|
<li>Ensure proper file permissions</li>
|
|
</ul>
|
|
|
|
<h4>2. Template not found errors</h4>
|
|
<ul>
|
|
<li>Check template path in views.py</li>
|
|
<li>Verify template files exist</li>
|
|
<li>Ensure proper directory structure</li>
|
|
</ul>
|
|
|
|
<h4>3. Static files not loading</h4>
|
|
<ul>
|
|
<li>Run <code>python3 manage.py collectstatic</code></li>
|
|
<li>Check STATIC_URL configuration</li>
|
|
<li>Verify file permissions</li>
|
|
</ul>
|
|
|
|
<h4>4. Database migration errors</h4>
|
|
<ul>
|
|
<li>Check model definitions</li>
|
|
<li>Run <code>python3 manage.py makemigrations</code></li>
|
|
<li>Verify database connectivity</li>
|
|
</ul>
|
|
|
|
<h4>5. Permission denied errors</h4>
|
|
<ul>
|
|
<li>Check file ownership (cyberpanel:cyberpanel)</li>
|
|
<li>Verify file permissions (755 for directories, 644 for files)</li>
|
|
<li>Ensure proper SELinux context if applicable</li>
|
|
</ul>
|
|
|
|
<h3>Debug Steps</h3>
|
|
|
|
<h4>1. Check CyberPanel logs</h4>
|
|
<pre><code>tail -f /home/cyberpanel/logs/cyberpanel.log</code></pre>
|
|
|
|
<h4>2. Check Django logs</h4>
|
|
<pre><code>tail -f /home/cyberpanel/logs/django.log</code></pre>
|
|
|
|
<h4>3. Verify plugin installation</h4>
|
|
<pre><code>ls -la /home/cyberpanel/plugins/
|
|
ls -la /usr/local/CyberCP/yourPlugin/</code></pre>
|
|
|
|
<h4>4. Test database connectivity</h4>
|
|
<pre><code>cd /usr/local/CyberCP
|
|
python3 manage.py shell</code></pre>
|
|
|
|
<h4>5. Check service status</h4>
|
|
<pre><code>systemctl status lscpd
|
|
systemctl status cyberpanel</code></pre>
|
|
</div>
|
|
|
|
<blockquote>
|
|
<strong>Conclusion:</strong> This guide provides comprehensive instructions for developing CyberPanel plugins. Follow the best practices and troubleshooting steps to ensure your plugins integrate seamlessly with CyberPanel while maintaining security and performance standards.
|
|
</blockquote>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- OS Compatibility Guide -->
|
|
<div class="docs-section" id="os-compatibility">
|
|
<div class="docs-content">
|
|
<h1 class="section-title">Operating System Compatibility</h1>
|
|
|
|
<div class="feature-list">
|
|
<div class="feature-item">
|
|
<h4>🌐 Multi-OS Support</h4>
|
|
<p>Comprehensive support for all CyberPanel-supported operating systems.</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>🔍 Automatic Detection</h4>
|
|
<p>Intelligent OS detection and configuration for seamless installation.</p>
|
|
</div>
|
|
<div class="feature-item">
|
|
<h4>🧪 Compatibility Testing</h4>
|
|
<p>Built-in compatibility testing to verify system requirements.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Supported Operating Systems</h2>
|
|
|
|
<div class="compatibility-grid">
|
|
<div class="os-card">
|
|
<h3>Ubuntu</h3>
|
|
<ul>
|
|
<li>✅ Ubuntu 22.04 (Full Support)</li>
|
|
<li>✅ Ubuntu 20.04 (Full Support)</li>
|
|
<li>✅ Debian 11+ (Compatible)</li>
|
|
</ul>
|
|
<p><strong>Package Manager:</strong> apt-get</p>
|
|
<p><strong>Web Server:</strong> apache2</p>
|
|
</div>
|
|
|
|
<div class="os-card">
|
|
<h3>RHEL-based</h3>
|
|
<ul>
|
|
<li>✅ AlmaLinux 8, 9, 10</li>
|
|
<li>✅ RockyLinux 8, 9</li>
|
|
<li>✅ RHEL 8, 9</li>
|
|
<li>✅ CentOS 9</li>
|
|
</ul>
|
|
<p><strong>Package Manager:</strong> dnf/yum</p>
|
|
<p><strong>Web Server:</strong> httpd</p>
|
|
</div>
|
|
|
|
<div class="os-card">
|
|
<h3>CloudLinux</h3>
|
|
<ul>
|
|
<li>✅ CloudLinux 8</li>
|
|
<li>✅ CloudLinux 7 (Limited)</li>
|
|
</ul>
|
|
<p><strong>Package Manager:</strong> yum</p>
|
|
<p><strong>Web Server:</strong> httpd</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Python Compatibility</h2>
|
|
<p>The plugin requires Python 3.6+ and automatically detects the correct Python executable:</p>
|
|
|
|
<div class="code-block">
|
|
<pre><code># Detection order:
|
|
1. python3.12
|
|
2. python3.11
|
|
3. python3.10
|
|
4. python3.9
|
|
5. python3.8
|
|
6. python3.7
|
|
7. python3.6
|
|
8. python3
|
|
9. python (fallback)</code></pre>
|
|
</div>
|
|
|
|
<h2>Installation Compatibility</h2>
|
|
<p>The installation script automatically detects your operating system and configures the plugin accordingly:</p>
|
|
|
|
<div class="code-block">
|
|
<pre><code># Automatic detection includes:
|
|
- OS name and version
|
|
- Python executable path
|
|
- Package manager (apt-get, dnf, yum)
|
|
- Service manager (systemctl, service)
|
|
- Web server (apache2, httpd)
|
|
- User and group permissions</code></pre>
|
|
</div>
|
|
|
|
<h2>Compatibility Testing</h2>
|
|
<p>Run the built-in compatibility test to verify your system:</p>
|
|
|
|
<div class="code-block">
|
|
<pre><code># Navigate to plugin directory
|
|
cd /usr/local/CyberCP/testPlugin
|
|
|
|
# Run compatibility test
|
|
python3 test_os_compatibility.py
|
|
|
|
# Or make it executable and run
|
|
chmod +x test_os_compatibility.py
|
|
./test_os_compatibility.py</code></pre>
|
|
</div>
|
|
|
|
<h2>Test Results</h2>
|
|
<p>The compatibility test checks:</p>
|
|
<ul>
|
|
<li>✅ OS detection and version</li>
|
|
<li>✅ Python installation and version</li>
|
|
<li>✅ Package manager availability</li>
|
|
<li>✅ Service manager functionality</li>
|
|
<li>✅ Web server configuration</li>
|
|
<li>✅ File permissions and ownership</li>
|
|
<li>✅ Network connectivity</li>
|
|
<li>✅ CyberPanel integration</li>
|
|
</ul>
|
|
|
|
<h2>OS-Specific Configurations</h2>
|
|
|
|
<h3>Ubuntu/Debian Systems</h3>
|
|
<div class="code-block">
|
|
<pre><code># Package Manager: apt-get
|
|
# Python: python3
|
|
# Pip: pip3
|
|
# Service Manager: systemctl
|
|
# Web Server: apache2
|
|
# User/Group: cyberpanel:cyberpanel
|
|
|
|
# Installation commands
|
|
sudo apt-get update
|
|
sudo apt-get install -y python3 python3-pip python3-venv git curl
|
|
sudo apt-get install -y build-essential python3-dev</code></pre>
|
|
</div>
|
|
|
|
<h3>RHEL-based Systems</h3>
|
|
<div class="code-block">
|
|
<pre><code># Package Manager: dnf (RHEL 8+) / yum (RHEL 7)
|
|
# Python: python3
|
|
# Pip: pip3
|
|
# Service Manager: systemctl
|
|
# Web Server: httpd
|
|
# User/Group: cyberpanel:cyberpanel
|
|
|
|
# Installation commands (RHEL 8+)
|
|
sudo dnf install -y python3 python3-pip python3-devel git curl
|
|
sudo dnf install -y gcc gcc-c++ make
|
|
|
|
# Installation commands (RHEL 7)
|
|
sudo yum install -y python3 python3-pip python3-devel git curl
|
|
sudo yum install -y gcc gcc-c++ make</code></pre>
|
|
</div>
|
|
|
|
<h3>CloudLinux</h3>
|
|
<div class="code-block">
|
|
<pre><code># Package Manager: yum
|
|
# Python: python3
|
|
# Pip: pip3
|
|
# Service Manager: systemctl
|
|
# Web Server: httpd
|
|
# User/Group: cyberpanel:cyberpanel
|
|
|
|
# Installation commands
|
|
sudo yum install -y python3 python3-pip python3-devel git curl
|
|
sudo yum install -y gcc gcc-c++ make
|
|
|
|
# CageFS configuration
|
|
cagefsctl --enable cyberpanel
|
|
cagefsctl --update</code></pre>
|
|
</div>
|
|
|
|
<h2>Security Compatibility</h2>
|
|
|
|
<h3>SELinux (RHEL-based systems)</h3>
|
|
<div class="code-block">
|
|
<pre><code># Check SELinux status
|
|
sestatus
|
|
|
|
# Set proper context for plugin files
|
|
setsebool -P httpd_can_network_connect 1
|
|
chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/</code></pre>
|
|
</div>
|
|
|
|
<h3>AppArmor (Ubuntu/Debian)</h3>
|
|
<div class="code-block">
|
|
<pre><code># Check AppArmor status
|
|
aa-status
|
|
|
|
# Allow Apache to access plugin files
|
|
aa-complain apache2</code></pre>
|
|
</div>
|
|
|
|
<h3>Firewall Configuration</h3>
|
|
<div class="code-block">
|
|
<pre><code># Ubuntu/Debian (ufw)
|
|
sudo ufw allow 8090/tcp
|
|
sudo ufw allow 80/tcp
|
|
sudo ufw allow 443/tcp
|
|
|
|
# RHEL-based (firewalld)
|
|
sudo firewall-cmd --permanent --add-port=8090/tcp
|
|
sudo firewall-cmd --permanent --add-port=80/tcp
|
|
sudo firewall-cmd --permanent --add-port=443/tcp
|
|
sudo firewall-cmd --reload</code></pre>
|
|
</div>
|
|
|
|
<h2>Troubleshooting</h2>
|
|
|
|
<h3>Common Issues</h3>
|
|
<div class="troubleshooting-section">
|
|
<h4>Python not found</h4>
|
|
<div class="code-block">
|
|
<pre><code># Ubuntu/Debian
|
|
sudo apt-get update
|
|
sudo apt-get install -y python3 python3-pip
|
|
|
|
# RHEL-based
|
|
sudo dnf install -y python3 python3-pip
|
|
# or
|
|
sudo yum install -y python3 python3-pip</code></pre>
|
|
</div>
|
|
|
|
<h4>Permission denied</h4>
|
|
<div class="code-block">
|
|
<pre><code>sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins
|
|
sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin</code></pre>
|
|
</div>
|
|
|
|
<h4>Service not starting</h4>
|
|
<div class="code-block">
|
|
<pre><code>sudo systemctl daemon-reload
|
|
sudo systemctl restart lscpd
|
|
sudo systemctl restart apache2 # Ubuntu/Debian
|
|
sudo systemctl restart httpd # RHEL-based</code></pre>
|
|
</div>
|
|
</div>
|
|
|
|
<h2>Debug Commands</h2>
|
|
<div class="code-block">
|
|
<pre><code># Check OS information
|
|
cat /etc/os-release
|
|
uname -a
|
|
|
|
# Check Python installation
|
|
python3 --version
|
|
which python3
|
|
which pip3
|
|
|
|
# Check services
|
|
systemctl status lscpd
|
|
systemctl status apache2 # Ubuntu/Debian
|
|
systemctl status httpd # RHEL-based
|
|
|
|
# Check file permissions
|
|
ls -la /home/cyberpanel/plugins/
|
|
ls -la /usr/local/CyberCP/testPlugin/
|
|
|
|
# Check CyberPanel logs
|
|
tail -f /home/cyberpanel/logs/cyberpanel.log
|
|
tail -f /home/cyberpanel/logs/django.log</code></pre>
|
|
</div>
|
|
|
|
<blockquote>
|
|
<strong>Note:</strong> The plugin is designed to work seamlessly across all supported operating systems. If you encounter any compatibility issues, please run the compatibility test and check the troubleshooting section above.
|
|
</blockquote>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const navButtons = document.querySelectorAll('.nav-button[data-section]');
|
|
const sections = document.querySelectorAll('.docs-section');
|
|
|
|
navButtons.forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
|
|
// Remove active class from all buttons and sections
|
|
navButtons.forEach(btn => btn.classList.remove('active'));
|
|
sections.forEach(section => section.classList.remove('active'));
|
|
|
|
// Add active class to clicked button
|
|
this.classList.add('active');
|
|
|
|
// Show corresponding section
|
|
const targetSection = document.getElementById(this.dataset.section);
|
|
if (targetSection) {
|
|
targetSection.classList.add('active');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Smooth scrolling for anchor links
|
|
const anchorLinks = document.querySelectorAll('a[href^="#"]');
|
|
anchorLinks.forEach(link => {
|
|
link.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const targetId = this.getAttribute('href').substring(1);
|
|
const targetElement = document.getElementById(targetId);
|
|
if (targetElement) {
|
|
targetElement.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start'
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Initialize with quick-guide active
|
|
const quickGuideButton = document.querySelector('[data-section="quick-guide"]');
|
|
if (quickGuideButton) {
|
|
quickGuideButton.classList.add('active');
|
|
}
|
|
const quickGuideSection = document.getElementById('quick-guide');
|
|
if (quickGuideSection) {
|
|
quickGuideSection.classList.add('active');
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|