mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-03-21 19:41:30 +01:00
- Replace {% with {%% in code examples to prevent template parsing errors
- Fixes 'block tag with name title appears more than once' error
- Code examples now display correctly without being parsed as actual template blocks
660 lines
23 KiB
HTML
660 lines
23 KiB
HTML
{% extends "baseTemplate/index.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% trans "Plugin Development Help - CyberPanel" %}{% endblock %}
|
|
|
|
{% block header_scripts %}
|
|
<style>
|
|
.help-wrapper {
|
|
background: transparent;
|
|
padding: 20px;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.help-header {
|
|
background: var(--bg-primary, white);
|
|
border-radius: 12px;
|
|
padding: 30px;
|
|
margin-bottom: 25px;
|
|
box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.08));
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}
|
|
|
|
.help-header h1 {
|
|
font-size: 32px;
|
|
font-weight: 700;
|
|
color: var(--text-primary, #2f3640);
|
|
margin: 0 0 10px 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 15px;
|
|
}
|
|
|
|
.help-header .icon {
|
|
width: 56px;
|
|
height: 56px;
|
|
background: #5856d6;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: white;
|
|
font-size: 28px;
|
|
box-shadow: 0 4px 12px rgba(88,86,214,0.3);
|
|
}
|
|
|
|
.help-header p {
|
|
font-size: 16px;
|
|
color: var(--text-secondary, #64748b);
|
|
margin: 0;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.help-content {
|
|
background: var(--bg-primary, white);
|
|
border-radius: 12px;
|
|
padding: 40px;
|
|
box-shadow: var(--shadow-md, 0 2px 8px rgba(0,0,0,0.08));
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}
|
|
|
|
.help-content h2 {
|
|
font-size: 24px;
|
|
font-weight: 700;
|
|
color: var(--text-primary, #2f3640);
|
|
margin: 30px 0 15px 0;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #5856d6;
|
|
}
|
|
|
|
.help-content h3 {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #2f3640);
|
|
margin: 25px 0 12px 0;
|
|
}
|
|
|
|
.help-content h4 {
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #2f3640);
|
|
margin: 20px 0 10px 0;
|
|
}
|
|
|
|
.help-content p {
|
|
font-size: 15px;
|
|
color: var(--text-secondary, #64748b);
|
|
line-height: 1.8;
|
|
margin: 12px 0;
|
|
}
|
|
|
|
.help-content ul, .help-content ol {
|
|
margin: 15px 0;
|
|
padding-left: 30px;
|
|
}
|
|
|
|
.help-content li {
|
|
font-size: 15px;
|
|
color: var(--text-secondary, #64748b);
|
|
line-height: 1.8;
|
|
margin: 8px 0;
|
|
}
|
|
|
|
.help-content code {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 14px;
|
|
color: #5856d6;
|
|
}
|
|
|
|
.help-content pre {
|
|
background: #1e1e1e;
|
|
color: #d4d4d4;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
overflow-x: auto;
|
|
margin: 20px 0;
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 14px;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.help-content pre code {
|
|
background: transparent;
|
|
color: inherit;
|
|
padding: 0;
|
|
}
|
|
|
|
.help-content blockquote {
|
|
border-left: 4px solid #5856d6;
|
|
padding-left: 20px;
|
|
margin: 20px 0;
|
|
font-style: italic;
|
|
color: var(--text-secondary, #64748b);
|
|
}
|
|
|
|
.help-content table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.help-content table th,
|
|
.help-content table td {
|
|
padding: 12px;
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
text-align: left;
|
|
}
|
|
|
|
.help-content table th {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
font-weight: 600;
|
|
color: var(--text-primary, #2f3640);
|
|
}
|
|
|
|
.help-content table td {
|
|
color: var(--text-secondary, #64748b);
|
|
}
|
|
|
|
.help-content .alert {
|
|
padding: 15px 20px;
|
|
border-radius: 8px;
|
|
margin: 20px 0;
|
|
border-left: 4px solid;
|
|
}
|
|
|
|
.help-content .alert-info {
|
|
background: #e0f2fe;
|
|
border-color: #0ea5e9;
|
|
color: #0c4a6e;
|
|
}
|
|
|
|
.help-content .alert-warning {
|
|
background: #fef3c7;
|
|
border-color: #f59e0b;
|
|
color: #92400e;
|
|
}
|
|
|
|
.help-content .alert-success {
|
|
background: #d1fae5;
|
|
border-color: #10b981;
|
|
color: #065f46;
|
|
}
|
|
|
|
.help-content .alert-danger {
|
|
background: #fee2e2;
|
|
border-color: #ef4444;
|
|
color: #991b1b;
|
|
}
|
|
|
|
.toc {
|
|
background: var(--bg-secondary, #f8f9ff);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 30px 0;
|
|
border: 1px solid var(--border-primary, #e8e9ff);
|
|
}
|
|
|
|
.toc h3 {
|
|
margin-top: 0;
|
|
color: var(--text-primary, #2f3640);
|
|
}
|
|
|
|
.toc ul {
|
|
list-style: none;
|
|
padding-left: 0;
|
|
}
|
|
|
|
.toc li {
|
|
margin: 8px 0;
|
|
}
|
|
|
|
.toc a {
|
|
color: #5856d6;
|
|
text-decoration: none;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.toc a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.code-block {
|
|
position: relative;
|
|
}
|
|
|
|
.code-block::before {
|
|
content: attr(data-language);
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 15px;
|
|
background: rgba(255,255,255,0.1);
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
color: #d4d4d4;
|
|
}
|
|
|
|
.badge {
|
|
display: inline-block;
|
|
padding: 4px 10px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.badge-required {
|
|
background: #fee2e2;
|
|
color: #991b1b;
|
|
}
|
|
|
|
.badge-optional {
|
|
background: #d1fae5;
|
|
color: #065f46;
|
|
}
|
|
|
|
.back-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: #5856d6;
|
|
text-decoration: none;
|
|
font-weight: 600;
|
|
margin-bottom: 20px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.back-link:hover {
|
|
color: #4a90e2;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.help-wrapper {
|
|
padding: 15px;
|
|
}
|
|
|
|
.help-content {
|
|
padding: 25px;
|
|
}
|
|
|
|
.help-header h1 {
|
|
font-size: 24px;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.help-content pre {
|
|
font-size: 12px;
|
|
padding: 15px;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="help-wrapper">
|
|
<a href="/plugins/installed" class="back-link">
|
|
<i class="fas fa-arrow-left"></i>
|
|
{% trans "Back to Installed Plugins" %}
|
|
</a>
|
|
|
|
<div class="help-header">
|
|
<h1>
|
|
<div class="icon">
|
|
<i class="fas fa-book"></i>
|
|
</div>
|
|
{% trans "Plugin Development Guide" %}
|
|
</h1>
|
|
<p>{% trans "Comprehensive guide to creating plugins for CyberPanel. Learn how to build, package, and distribute your own plugins." %}</p>
|
|
</div>
|
|
|
|
<div class="help-content">
|
|
<div class="toc">
|
|
<h3>{% trans "Table of Contents" %}</h3>
|
|
<ul>
|
|
<li><a href="#introduction">{% trans "Introduction" %}</a></li>
|
|
<li><a href="#prerequisites">{% trans "Prerequisites" %}</a></li>
|
|
<li><a href="#architecture">{% trans "Plugin Architecture Overview" %}</a></li>
|
|
<li><a href="#first-plugin">{% trans "Creating Your First Plugin" %}</a></li>
|
|
<li><a href="#structure">{% trans "Plugin Structure & Files" %}</a></li>
|
|
<li><a href="#components">{% trans "Core Components" %}</a></li>
|
|
<li><a href="#advanced">{% trans "Advanced Features" %}</a></li>
|
|
<li><a href="#best-practices">{% trans "Best Practices" %}</a></li>
|
|
<li><a href="#security">{% trans "Security Guidelines" %}</a></li>
|
|
<li><a href="#testing">{% trans "Testing & Debugging" %}</a></li>
|
|
<li><a href="#packaging">{% trans "Packaging & Distribution" %}</a></li>
|
|
<li><a href="#troubleshooting">{% trans "Troubleshooting" %}</a></li>
|
|
<li><a href="#examples">{% trans "Examples & References" %}</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h2 id="introduction">{% trans "Introduction" %}</h2>
|
|
<p>{% trans "CyberPanel's plugin system allows developers to extend the control panel's functionality with custom features. Plugins integrate seamlessly with CyberPanel's Django-based architecture, providing access to the full power of the platform while maintaining security and consistency." %}</p>
|
|
|
|
<h3>{% trans "What Can Plugins Do?" %}</h3>
|
|
<ul>
|
|
<li>{% trans "Add new administrative features" %}</li>
|
|
<li>{% trans "Integrate with external services (APIs, webhooks, etc.)" %}</li>
|
|
<li>{% trans "Customize the user interface" %}</li>
|
|
<li>{% trans "Extend database functionality" %}</li>
|
|
<li>{% trans "Add automation and monitoring capabilities" %}</li>
|
|
<li>{% trans "Create custom reporting tools" %}</li>
|
|
<li>{% trans "Integrate security features" %}</li>
|
|
</ul>
|
|
|
|
<h2 id="prerequisites">{% trans "Prerequisites" %}</h2>
|
|
<h3>{% trans "Required Knowledge" %}</h3>
|
|
<ul>
|
|
<li><strong>Python 3.6+</strong>: {% trans "Basic to intermediate Python knowledge" %}</li>
|
|
<li><strong>Django Framework</strong>: {% trans "Understanding of Django views, URLs, templates, and models" %}</li>
|
|
<li><strong>HTML/CSS/JavaScript</strong>: {% trans "For creating user interfaces" %}</li>
|
|
<li><strong>Linux/Unix</strong>: {% trans "Basic command-line familiarity" %}</li>
|
|
<li><strong>XML</strong>: {% trans "Understanding of XML structure for meta.xml" %}</li>
|
|
</ul>
|
|
|
|
<h2 id="architecture">{% trans "Plugin Architecture Overview" %}</h2>
|
|
<h3>{% trans "How Plugins Work" %}</h3>
|
|
<ol>
|
|
<li><strong>{% trans "Plugin Source Location" %}</strong>: <code>/home/cyberpanel/plugins/</code>
|
|
<ul>
|
|
<li>{% trans "Plugins are stored here before installation" %}</li>
|
|
<li>{% trans "Can be uploaded as ZIP files or placed directly" %}</li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>{% trans "Installed Location" %}</strong>: <code>/usr/local/CyberCP/</code>
|
|
<ul>
|
|
<li>{% trans "After installation, plugins are copied here" %}</li>
|
|
<li>{% trans "This is where CyberPanel loads plugins from" %}</li>
|
|
</ul>
|
|
</li>
|
|
</ol>
|
|
|
|
<h2 id="first-plugin">{% trans "Creating Your First Plugin" %}</h2>
|
|
<h3>{% trans "Step 1: Create Plugin Directory Structure" %}</h3>
|
|
<pre><code># Navigate to plugins directory
|
|
cd /home/cyberpanel/plugins
|
|
|
|
# Create your plugin directory
|
|
mkdir myFirstPlugin
|
|
cd myFirstPlugin
|
|
|
|
# Create required subdirectories
|
|
mkdir -p templates/myFirstPlugin
|
|
mkdir -p static/myFirstPlugin/css
|
|
mkdir -p static/myFirstPlugin/js
|
|
mkdir -p migrations</code></pre>
|
|
|
|
<h3>{% trans "Step 2: Create meta.xml (REQUIRED)" %}</h3>
|
|
<pre><code><?xml version="1.0" encoding="UTF-8"?>
|
|
<cyberpanelPluginConfig>
|
|
<name>My First Plugin</name>
|
|
<type>Utility</type>
|
|
<description>A simple example plugin</description>
|
|
<version>1.0.0</version>
|
|
<url>/plugins/myFirstPlugin/</url>
|
|
<settings_url>/plugins/myFirstPlugin/settings/</settings_url>
|
|
</cyberpanelPluginConfig></code></pre>
|
|
|
|
<h3>{% trans "Step 3: Create urls.py" %}</h3>
|
|
<pre><code>from django.urls import path
|
|
from . import views
|
|
|
|
app_name = 'myFirstPlugin'
|
|
|
|
urlpatterns = [
|
|
path('', views.main_view, name='main'),
|
|
path('settings/', views.settings_view, name='settings'),
|
|
]</code></pre>
|
|
|
|
<h3>{% trans "Step 4: Create views.py" %}</h3>
|
|
<pre><code>from django.shortcuts import render, redirect
|
|
from functools import wraps
|
|
|
|
def cyberpanel_login_required(view_func):
|
|
"""Custom decorator for CyberPanel session authentication"""
|
|
@wraps(view_func)
|
|
def _wrapped_view(request, *args, **kwargs):
|
|
try:
|
|
userID = request.session['userID']
|
|
return view_func(request, *args, **kwargs)
|
|
except KeyError:
|
|
from loginSystem.views import loadLoginPage
|
|
return redirect(loadLoginPage)
|
|
return _wrapped_view
|
|
|
|
@cyberpanel_login_required
|
|
def main_view(request):
|
|
context = {
|
|
'plugin_name': 'My First Plugin',
|
|
'version': '1.0.0'
|
|
}
|
|
return render(request, 'myFirstPlugin/main.html', context)</code></pre>
|
|
|
|
<h3>{% trans "Step 5: Create Templates" %}</h3>
|
|
<p>{% trans "Templates must extend baseTemplate/index.html:" %}</p>
|
|
<pre><code><!-- Example template code (replace {% with HTML entities) -->
|
|
{%% extends "baseTemplate/index.html" %%}
|
|
{%% load static %%}
|
|
{%% load i18n %%}
|
|
|
|
{%% block title %%}
|
|
My First Plugin - {%% trans "CyberPanel" %%}
|
|
{%% endblock %%}
|
|
|
|
{%% block content %%}
|
|
<div class="container">
|
|
<h1>{{ plugin_name }}</h1>
|
|
<p>Version {{ version }}</p>
|
|
</div>
|
|
{%% endblock %%}</code></pre>
|
|
|
|
<div class="alert alert-info">
|
|
<strong>{% trans "Important" %}:</strong> {% trans "Always use the @cyberpanel_login_required decorator for all views to ensure users are authenticated." %}
|
|
</div>
|
|
|
|
<h2 id="structure">{% trans "Plugin Structure & Files" %}</h2>
|
|
<h3>{% trans "Required Files" %}</h3>
|
|
<ul>
|
|
<li><code>__init__.py</code> - <span class="badge badge-required">{% trans "Required" %}</span> - {% trans "Python package marker" %}</li>
|
|
<li><code>meta.xml</code> - <span class="badge badge-required">{% trans "Required" %}</span> - {% trans "Plugin metadata" %}</li>
|
|
<li><code>urls.py</code> - <span class="badge badge-required">{% trans "Required" %}</span> - {% trans "URL routing" %}</li>
|
|
<li><code>views.py</code> - <span class="badge badge-required">{% trans "Required" %}</span> - {% trans "View functions" %}</li>
|
|
</ul>
|
|
|
|
<h3>{% trans "Optional Files" %}</h3>
|
|
<ul>
|
|
<li><code>models.py</code> - <span class="badge badge-optional">{% trans "Optional" %}</span> - {% trans "Database models" %}</li>
|
|
<li><code>forms.py</code> - <span class="badge badge-optional">{% trans "Optional" %}</span> - {% trans "Django forms" %}</li>
|
|
<li><code>utils.py</code> - <span class="badge badge-optional">{% trans "Optional" %}</span> - {% trans "Utility functions" %}</li>
|
|
<li><code>templates/</code> - <span class="badge badge-optional">{% trans "Optional" %}</span> - {% trans "HTML templates" %}</li>
|
|
<li><code>static/</code> - <span class="badge badge-optional">{% trans "Optional" %}</span> - {% trans "CSS, JS, images" %}</li>
|
|
</ul>
|
|
|
|
<h2 id="components">{% trans "Core Components" %}</h2>
|
|
<h3>{% trans "1. Authentication & Security" %}</h3>
|
|
<p>{% trans "Always use the cyberpanel_login_required decorator:" %}</p>
|
|
<pre><code>@cyberpanel_login_required
|
|
def my_view(request):
|
|
# Your view code
|
|
pass</code></pre>
|
|
|
|
<h3>{% trans "2. URL Routing" %}</h3>
|
|
<pre><code>from django.urls import path
|
|
from . import views
|
|
|
|
app_name = 'myPlugin'
|
|
|
|
urlpatterns = [
|
|
path('', views.main_view, name='main'),
|
|
path('item/<int:item_id>/', views.item_detail, name='item_detail'),
|
|
]</code></pre>
|
|
|
|
<h3>{% trans "3. Templates" %}</h3>
|
|
<p>{% trans "Always extend baseTemplate/index.html:" %}</p>
|
|
<pre><code>{% extends "baseTemplate/index.html" %}
|
|
{% load static %}
|
|
{% load i18n %}</code></pre>
|
|
|
|
<h2 id="advanced">{% trans "Advanced Features" %}</h2>
|
|
<h3>{% trans "Database Models" %}</h3>
|
|
<pre><code>from django.db import models
|
|
|
|
class MyModel(models.Model):
|
|
name = models.CharField(max_length=255)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
class Meta:
|
|
db_table = 'my_plugin_mymodel'</code></pre>
|
|
|
|
<h3>{% trans "Forms" %}</h3>
|
|
<pre><code>from django import forms
|
|
|
|
class MyForm(forms.Form):
|
|
name = forms.CharField(max_length=255, required=True)
|
|
email = forms.EmailField(required=True)</code></pre>
|
|
|
|
<h3>{% trans "API Endpoints" %}</h3>
|
|
<pre><code>from django.http import JsonResponse
|
|
|
|
@cyberpanel_login_required
|
|
def api_endpoint(request):
|
|
data = {'status': 'success'}
|
|
return JsonResponse(data)</code></pre>
|
|
|
|
<h2 id="best-practices">{% trans "Best Practices" %}</h2>
|
|
<ul>
|
|
<li>{% trans "Keep files under 500 lines - split into modules if needed" %}</li>
|
|
<li>{% trans "Use descriptive names for functions and variables" %}</li>
|
|
<li>{% trans "Follow PEP 8 Python style guide" %}</li>
|
|
<li>{% trans "Add comments for complex logic" %}</li>
|
|
<li>{% trans "Always validate user input" %}</li>
|
|
<li>{% trans "Use Django ORM instead of raw SQL" %}</li>
|
|
<li>{% trans "Test your plugin thoroughly before distribution" %}</li>
|
|
</ul>
|
|
|
|
<h2 id="security">{% trans "Security Guidelines" %}</h2>
|
|
<div class="alert alert-warning">
|
|
<strong>{% trans "Security is Critical" %}:</strong> {% trans "Always validate input, use parameterized queries, sanitize output, and check user permissions." %}
|
|
</div>
|
|
<ul>
|
|
<li>{% trans "Always validate and sanitize user input" %}</li>
|
|
<li>{% trans "Use Django ORM or parameterized queries" %}</li>
|
|
<li>{% trans "Escape HTML in templates (Django does this by default)" %}</li>
|
|
<li>{% trans "Validate file uploads (type, size, content)" %}</li>
|
|
<li>{% trans "Use HTTPS for sensitive operations" %}</li>
|
|
<li>{% trans "Implement rate limiting for API endpoints" %}</li>
|
|
</ul>
|
|
|
|
<h2 id="testing">{% trans "Testing & Debugging" %}</h2>
|
|
<h3>{% trans "Common Issues" %}</h3>
|
|
<ul>
|
|
<li><strong>{% trans "Template Not Found" %}</strong>: {% trans "Check template path and name" %}</li>
|
|
<li><strong>{% trans "URL Not Found" %}</strong>: {% trans "Verify URL patterns and app_name" %}</li>
|
|
<li><strong>{% trans "Import Errors" %}</strong>: {% trans "Check Python syntax and import paths" %}</li>
|
|
<li><strong>{% trans "Static Files Not Loading" %}</strong>: {% trans "Run collectstatic command" %}</li>
|
|
</ul>
|
|
|
|
<h3>{% trans "Debugging Commands" %}</h3>
|
|
<pre><code># Check Python syntax
|
|
python3 -m py_compile views.py
|
|
|
|
# Check XML validity
|
|
xmllint --noout meta.xml
|
|
|
|
# View logs
|
|
tail -f /usr/local/lscp/logs/error.log</code></pre>
|
|
|
|
<h2 id="packaging">{% trans "Packaging & Distribution" %}</h2>
|
|
<h3>{% trans "Create Plugin Package" %}</h3>
|
|
<pre><code>cd /home/cyberpanel/plugins/myPlugin
|
|
zip -r myPlugin-v1.0.0.zip . \
|
|
-x "*.pyc" \
|
|
-x "__pycache__/*" \
|
|
-x "*.log"</code></pre>
|
|
|
|
<h2 id="troubleshooting">{% trans "Troubleshooting" %}</h2>
|
|
<h3>{% trans "Installation Issues" %}</h3>
|
|
<ul>
|
|
<li>{% trans "Check meta.xml format and validity" %}</li>
|
|
<li>{% trans "Verify plugin directory exists" %}</li>
|
|
<li>{% trans "Check file permissions" %}</li>
|
|
<li>{% trans "Review CyberPanel logs" %}</li>
|
|
</ul>
|
|
|
|
<h3>{% trans "Runtime Issues" %}</h3>
|
|
<ul>
|
|
<li>{% trans "Verify URL routing" %}</li>
|
|
<li>{% trans "Check authentication decorator" %}</li>
|
|
<li>{% trans "Review template paths" %}</li>
|
|
<li>{% trans "Check for JavaScript errors" %}</li>
|
|
</ul>
|
|
|
|
<h2 id="examples">{% trans "Examples & References" %}</h2>
|
|
<h3>{% trans "Reference Plugins" %}</h3>
|
|
<ul>
|
|
<li><strong>examplePlugin</strong>: {% trans "Basic plugin structure" %}
|
|
<ul>
|
|
<li>{% trans "Location" %}: <code>/usr/local/CyberCP/examplePlugin/</code></li>
|
|
<li>{% trans "URL" %}: <code>/plugins/examplePlugin/</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>testPlugin</strong>: {% trans "Comprehensive example" %}
|
|
<ul>
|
|
<li>{% trans "Location" %}: <code>/usr/local/CyberCP/testPlugin/</code></li>
|
|
<li>{% trans "URL" %}: <code>/plugins/testPlugin/</code></li>
|
|
<li>{% trans "Author" %}: <strong>usmannasir</strong></li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>discordWebhooks</strong>: {% trans "Discord webhook integration plugin" %}
|
|
<ul>
|
|
<li>{% trans "Location" %}: <code>/usr/local/CyberCP/discordWebhooks/</code></li>
|
|
<li>{% trans "URL" %}: <code>/plugins/discordWebhooks/</code></li>
|
|
<li>{% trans "Author" %}: <strong>Master3395</strong></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<h3>{% trans "Useful Resources" %}</h3>
|
|
<ul>
|
|
<li><a href="https://cyberpanel.net/KnowledgeBase/" target="_blank">{% trans "CyberPanel Documentation" %}</a></li>
|
|
<li><a href="https://docs.djangoproject.com/" target="_blank">{% trans "Django Documentation" %}</a></li>
|
|
<li><a href="https://github.com/master3395/cyberpanel/tree/v2.5.5-dev" target="_blank">{% trans "CyberPanel GitHub Repository" %}</a></li>
|
|
<li><a href="https://github.com/master3395/cyberpanel/tree/v2.5.5-dev/docs/PLUGIN_DEVELOPMENT_GUIDE.md" target="_blank">{% trans "Full Plugin Development Guide (Markdown)" %}</a></li>
|
|
</ul>
|
|
|
|
<div class="alert alert-success">
|
|
<strong>{% trans "Ready to Start?" %}</strong> {% trans "Begin with a simple plugin and gradually add more features as you become familiar with the system. Check the examplePlugin and testPlugin directories for complete working examples." %}
|
|
</div>
|
|
|
|
<div style="margin-top: 40px; padding-top: 20px; border-top: 2px solid var(--border-primary, #e8e9ff);">
|
|
<p style="text-align: center; color: var(--text-secondary, #64748b);">
|
|
<strong>{% trans "Author" %}:</strong> master3395 |
|
|
<strong>{% trans "Version" %}:</strong> 2.0.0 |
|
|
<strong>{% trans "Last Updated" %}:</strong> 2026-01-04
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Smooth scrolling for anchor links
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
const target = document.querySelector(this.getAttribute('href'));
|
|
if (target) {
|
|
target.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start'
|
|
});
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|