diff --git a/baseTemplate/views.py b/baseTemplate/views.py index 1c7d05433..172e86731 100644 --- a/baseTemplate/views.py +++ b/baseTemplate/views.py @@ -129,6 +129,11 @@ def getAdminStatus(request): def getSystemStatus(request): + default_fallback = { + 'cpuUsage': 0, 'ramUsage': 0, 'diskUsage': 0, + 'cpuCores': 2, 'ramTotalMB': 4096, 'diskTotalGB': 100, + 'diskFreeGB': 100, 'uptime': 'N/A' + } try: val = request.session['userID'] currentACL = ACLManager.loadedACL(val) @@ -215,31 +220,13 @@ def getSystemStatus(request): except KeyError as e: logging.CyberCPLogFileWriter.writeToFile(f'[getSystemStatus] KeyError - No session userID: {str(e)}') - # Return default values on error - default_data = { - 'cpuUsage': 0, - 'ramUsage': 0, - 'diskUsage': 0, - 'cpuCores': 2, - 'ramTotalMB': 4096, - 'diskTotalGB': 100, - 'diskFreeGB': 100, - 'uptime': 'N/A' - } - return HttpResponse(json.dumps(default_data)) + return HttpResponse(json.dumps(default_fallback)) except Exception as e: - # Return default values on error - default_data = { - 'cpuUsage': 0, - 'ramUsage': 0, - 'diskUsage': 0, - 'cpuCores': 2, - 'ramTotalMB': 4096, - 'diskTotalGB': 100, - 'diskFreeGB': 100, - 'uptime': 'N/A' - } - return HttpResponse(json.dumps(default_data)) + logging.CyberCPLogFileWriter.writeToFile(f'[getSystemStatus] Exception: {str(e)}') + try: + return HttpResponse(json.dumps(default_fallback)) + except Exception: + return HttpResponse('{"cpuUsage":0,"ramUsage":0,"diskUsage":0,"cpuCores":2,"ramTotalMB":4096,"diskTotalGB":100,"diskFreeGB":100,"uptime":"N/A"}', content_type='application/json') def getLoadAverage(request): diff --git a/pluginHolder/templates/pluginHolder/help.html b/pluginHolder/templates/pluginHolder/help.html index 66bdcbdea..da5e53b13 100644 --- a/pluginHolder/templates/pluginHolder/help.html +++ b/pluginHolder/templates/pluginHolder/help.html @@ -323,6 +323,9 @@
<version>1.0.0</version>
{% trans "Never use formats like '1.0' or 'v1.0'. Always use the full semantic version: '1.0.0'" %}
+{% trans "The <type> field in meta.xml determines how your plugin is grouped in the Plugin Store. Use exactly one of these values (case-sensitive):" %}
+| {% trans "Category" %} | +{% trans "Purpose" %} | +
|---|---|
Utility | {% trans "General-purpose tools, helpers, and utilities" %} |
Security | {% trans "Security features: firewalls, fail2ban, SSL, etc." %} |
Backup | {% trans "Backup, snapshot, and restore functionality" %} |
Performance | {% trans "Caching, optimization, and performance tuning" %} |
Monitoring | {% trans "Monitoring, alerts, and health checks" %} |
Integration | {% trans "Third-party integrations: Discord, Slack, webhooks, APIs" %} |
Email | {% trans "Email marketing, SMTP, mail management" %} |
Development | {% trans "Developer tools: PM2, Node.js, deployment" %} |
Analytics | {% trans "Analytics, tracking, and reporting" %} |
{% trans "The Plugin Store and Installed Plugins views display freshness badges based on the last update date (modify_date from GitHub commit or meta.xml file mtime). These help users quickly see how actively maintained a plugin is:" %}
+| {% trans "Badge" %} | +{% trans "Condition" %} | +{% trans "Meaning" %} | +
|---|---|---|
| NEW | {% trans "Updated within last 90 days" %} | {% trans "Recently released or actively maintained" %} |
| Stable | {% trans "Updated within last 365 days" %} | {% trans "Updated within the past year" %} |
| Unstable | {% trans "1–2 years since last update" %} | {% trans "May need maintenance; consider forking or updating" %} |
| STALE | {% trans "Over 2 years since last update" %} | {% trans "Not updated recently; use with caution" %} |
{% trans "Badges are calculated automatically from the plugin's modify_date. For plugins in the Plugin Store, this comes from the GitHub repository's last commit. For installed plugins, it uses the meta.xml file modification time." %}
+ +{% trans "You can create premium (paid) plugins and implement your own verification system. This includes optional encryption between the plugin and your verification site to prevent unauthorized bypass." %}
+ +<paid>true</paid>
+<patreon_tier>Your Tier Name</patreon_tier>
+<patreon_url>https://www.patreon.com/your-page</patreon_url>
+ {% trans "Set <paid>true</paid> to display the Premium badge and subscription prompts in the Plugin Store." %}
+ +{% trans "Premium plugins typically verify access via a remote API. You can host this on your own site. Common verification methods:" %}
+{% trans "To protect against users modifying your plugin to bypass verification, you can encrypt the communication between the plugin and your verification API using AES-256-CBC. This ensures:" %}
+{% trans "Implementation outline:" %}
+{% trans "Both sides must use the same AES-256-CBC key. Keep the key secret and never commit it to public repositories. Store it in a protected config file outside the web root or in environment variables." %}
+ +{% trans "Always use the cyberpanel_login_required decorator:" %}
@@ -672,7 +762,7 @@ zip -r myPlugin-v1.0.0.zip . \{% trans "Author" %}: master3395 | {% trans "Version" %}: 2.0.0 | - {% trans "Last Updated" %}: 2026-01-04 + {% trans "Last Updated" %}: 2026-02-02
diff --git a/pluginHolder/templates/pluginHolder/plugins.html b/pluginHolder/templates/pluginHolder/plugins.html index 49d9c7dc4..389d4a685 100644 --- a/pluginHolder/templates/pluginHolder/plugins.html +++ b/pluginHolder/templates/pluginHolder/plugins.html @@ -200,6 +200,32 @@ border: 1px solid #c3e6cb; } + .freshness-badge-new, .freshness-badge-stable, .freshness-badge-stale { + display: inline-block; + padding: 3px 8px; + border-radius: 10px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + margin-top: 4px; + } + .freshness-badge-new { + background: #fef08a; + color: #854d0e; + } + .freshness-badge-stable { + background: #bbf7d0; + color: #166534; + } + .freshness-badge-stale { + background: #fecaca; + color: #991b1b; + } + .freshness-badge-unstable { + background: #e5e7eb; + color: #4b5563; + } + .plugin-pricing-badge.paid { background: #fff3cd; color: #856404; @@ -443,11 +469,62 @@ margin: 0 auto; } - /* View Toggle */ + /* View Toggle and Bulk Actions */ + .view-toggle-wrapper { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 16px; + margin-bottom: 20px; + } .view-toggle { display: flex; gap: 10px; - margin-bottom: 20px; + } + .bulk-actions-header { + display: flex !important; + visibility: visible !important; + opacity: 1 !important; + } + .bulk-actions-header .btn-bulk { + margin: 0; + flex-shrink: 0; + } + .btn-bulk { + padding: 8px 14px; + border-radius: 8px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + border: 1px solid transparent; + display: inline-flex; + align-items: center; + gap: 6px; + } + .btn-activate-all { + background: #28a745; + color: white; + border-color: #218838; + } + .btn-activate-all:hover:not(:disabled) { + background: #218838; + } + .btn-activate-all:disabled { + opacity: 0.6; + cursor: not-allowed; + } + .btn-deactivate-all { + background: #ffc107; + color: #212529; + border-color: #e0a800; + } + .btn-deactivate-all:hover:not(:disabled) { + background: #e0a800; + } + .btn-deactivate-all:disabled { + opacity: 0.6; + cursor: not-allowed; } .view-btn { @@ -1076,7 +1153,7 @@{% trans "List of installed plugins on your CyberPanel" %}