- FTPUsers: use domain__domain__in (FK to Websites) not domain__in
- Session: use session.get('userID'), return JSON when missing
- ACL: use currentACL.get('admin',0) to avoid KeyError
- /proc: resilient parsing for net/dev, diskstats, stat
- Log errors via CyberCPLogFileWriter; generic user-facing messages
- Prevents intermittent 500s that zero out insights (Users, Sites, etc.)
- Calculate total installed plugins count
- Calculate total active/enabled plugins count
- Display statistics in page header with icons
- Shows 'Installed: X' and 'Active: Y' counts
- Statistics only shown when plugins are installed
- Improves visibility of plugin status at a glance
- Fix except block indentation to match try block
- Add error handling for enrichment in stale cache fallback
- Ensures proper exception handling structure
- Wrap mailUtilities.checkHome in try-except
- Add try-except around _enrich_store_plugins calls
- If enrichment fails, return plugins without enrichment instead of 500 error
- Add error handling for _is_plugin_enabled calls
- Prevents HTTP 500 errors when plugin store loading fails
- Fixes issue where installing discordWebhooks caused plugin store to fail
- Remove redundant local import of pluginInstaller inside install_from_store function
- pluginInstaller is already imported at module level (line 20)
- The local import was creating a variable shadowing issue
- When the cleanup code path wasn't executed, pluginInstaller was referenced before assignment
- Fixes installation from store failing with variable reference error
- Only check /usr/local/CyberCP/ for installed status, not /home/cyberpanel/plugins/
- Require both plugin directory AND meta.xml to exist for installed status
- Plugins in source directory are not considered installed
- Fixes issue where Discord Webhooks, Fail2ban, Premium Plugin Example, and Test Plugin showed as installed when they weren't
Previously, the check used: os.path.exists(installed_path) or os.path.exists(source_path)
This incorrectly marked plugins as installed if they existed in the source directory.
Now uses: os.path.exists(installed_path) and os.path.exists(installed_meta)
This correctly only marks plugins as installed if they're actually in /usr/local/CyberCP/ with meta.xml
- Make toggleView more flexible - only require the specific view element needed
- Store view can now work even when gridView/tableView don't exist (no plugins installed)
- Fix initialization to directly show store view without calling toggleView recursively
- Find store button by text content instead of array index for reliability
- Prevents 'View elements not found' errors when loading Plugin Store with no installed plugins
- Hide Grid and Table view buttons when plugins list is empty
- Only show Plugin Store button when no plugins are installed
- Improves UX by preventing clicks on non-functional buttons
- Combined with null checks, ensures no JavaScript errors occur
- Add null checks for gridView, tableView, and storeView elements
- Prevent 'Cannot read properties of null' errors when elements don't exist
- Add null checks for viewBtns array access
- Add function existence checks before calling setupStoreSearch, loadPluginStore, displayStorePlugins
- Improve initialization code with better error handling
- Fixes Plugin Store loading errors when no plugins are installed
- Filter pluginList to only include plugins where installed == True
- Uninstalled plugins will only appear in Plugin Store, not Installed Plugins
- This fixes the issue where uninstalled plugins were still showing locally
- Plugins in /home/cyberpanel/plugins/ but not in /usr/local/CyberCP/ are now hidden from Installed Plugins
- Track INSTALLED_APPS section state while iterating
- Only remove plugin if found within INSTALLED_APPS section
- Prevents removing plugin references from comments or other sections
- Use more precise string matching to avoid partial matches
- removeFromSettings: Match plugin name in quotes within INSTALLED_APPS context
- removeFromURLs: Match plugin name in path() and include() patterns
- Prevents false positives (e.g., 'pluginName2' matching 'pluginName')
This ensures uninstall only removes the exact plugin, not similar names.
- Verify plugin directory is actually removed after removeFiles()
- If directory still exists, retry with ProcessUtilities.normalExecutioner()
- Return error if directory still exists after all attempts
- Prevents silent failures where uninstall appears successful but plugin remains
Fixes: Plugins showing as installed after 'successful' uninstall
- Check if running as root (os.geteuid() == 0)
- If root: fix permissions directly without sudo
- If not root: use ProcessUtilities.normalExecutioner() which handles
privileged commands properly (no password prompt needed)
- Remove sudo dependency that was causing password prompts
Fixes: sudo password prompt errors when uninstalling plugins
- Try direct removal first (fastest)
- If that fails, use sudo chown/chmod to fix permissions, then remove
- Final fallback: use sudo rm -rf
- Better error handling and logging at each step
Fixes: Permission denied errors when uninstalling plugins with root-owned files
(examplePlugin, paypalPremiumPlugin, pm2Manager)
Remove commented-out emailMarketing URL reference from template.
Django may still try to parse commented {% url %} tags, causing
'Reverse for emailMarketing not found' error.
emailMarketing was removed from INSTALLED_APPS but websiteFunctions
was still trying to import it, causing ModuleNotFoundError.
Fixes: ModuleNotFoundError: No module named 'emailMarketing'
- Comment out emailMarketing menu item in baseTemplate/index.html
- Skip emailMarketing in pluginHolder/views.py when listing plugins
- Prevents HTTP 500 error when template tries to reverse 'emailMarketing' URL
Fixes: HTTP 500 on /plugins/installed after emailMarketing removal
- Use pluginInstaller.removeFiles() which handles permissions properly
- Add fallback to rm -rf if pluginInstaller method fails
- Better error handling and logging
- Applied to both install_plugin and install_from_store functions
Fixes: Incomplete plugin directory cleanup failures due to permission issues
emailMarketing was in INSTALLED_APPS but URL route was missing,
causing 'Reverse for emailMarketing not found' error when template
tries to use {% url 'emailMarketing' %}
emailMarketing was removed from INSTALLED_APPS but the plugin directory
still exists, causing Django to fail with:
'Model class emailMarketing.models.EmailMarketing doesn't declare an explicit
app_label and isn't in an application in INSTALLED_APPS'
This fixes the HTTP 500 error on /plugins/installed
Plugins should be installed via Plugin Store, not auto-registered in core.
Plugin registrations (INSTALLED_APPS and URL routes) are added dynamically
during plugin installation via pluginInstaller, not hardcoded in core.
Removed from INSTALLED_APPS:
- fail2ban
- discordAuth (already removed by user)
- googleTagManager
- discordWebhooks (already removed by user)
Removed from urls.py:
- All plugin URL routes (fail2ban, googleTagManager, discordAuth)
These plugins must be installed via Plugin Store, which will automatically
add them to INSTALLED_APPS and urls.py during installation.
Plugins should be installed via Plugin Store, not auto-registered in core.
Plugin registrations (INSTALLED_APPS and URL routes) are added dynamically
during plugin installation, not hardcoded in the core repository.
Reverted:
- Removed fail2ban, discordWebhooks, googleTagManager from INSTALLED_APPS
- Removed plugin URL routes from urls.py
- discordAuth was already removed by user
Kept:
- Automatic lscpd restart after plugin installation (pluginHolder/views.py)
- File ownership/permissions fixes
- Implement server fingerprinting for license binding
- Add code integrity verification with SHA256 hashes
- Implement domain binding for license validation
- Add time-based re-validation with 1-hour caching
- Create secure_verification_required decorator with multiple security layers
- Update both Patreon and PayPal premium plugins with security enhancements
- Add PayPal verification endpoint (verify-paypal-payment.php)
- Update Patreon endpoint to support server fingerprint and domain binding
- Added NEW badge for plugins updated within last 3 months (90 days)
- Added Stale badge for plugins not updated in last 2 years (730 days)
- Removed Author, Status, and Active columns from Plugin Store view
- Fixed intermittent old table display with cache-busting v7
- Added column count validation to ensure correct 8-column structure
- Added tooltips for NEW and Stale badges with descriptive messages
- Cleared plugin store cache to prevent stale data display
- Updated cache-busting version to v7 to force browser refresh
- Add GET /docker/containers for HTML page; GET /docker/listContainers redirects there
- POST /docker/listContainers returns 405 (page uses getContainerList for data)
- Remove duplicate listContainers Angular controller; fix pagination (getContainerList)
- Extend getContainerList API: totalCount, totalPages, currentPage, itemsPerPage
- Add ACTIVITY BOARD-style pagination: Prev/Next, Go to page, Showing X–Y of Z
- Update menu/templates/JS redirects to /docker/containers
- Sync dockerManager.js across app static, STATIC_ROOT, public/static
- Cache-Control on HTML response; cache-bust script ?v=4
Fixes raw JSON instead of UI when loading /docker/listContainers (cache/proxy
serving stored JSON for GET). Use /docker/containers for the page.
- Added code to detect and remove any duplicate view-toggle divs
- Keeps only the one with id='plugins-view-toggle'
- This handles cases where browser cache or template cache shows duplicates
- Added id='plugins-view-toggle' to view-toggle div to prevent duplicates
- Updated toggleView() to only select buttons from the main view-toggle
- This should prevent any duplicate button issues
- Moved view toggle (Grid View, Table View, Plugin Store, Plugin Development Guide) to top of plugins section
- Removed duplicate view toggle that appeared at bottom
- Now only one set of view toggle buttons appears at the top
- Removed duplicate view toggle section that appeared when plugins exist
- Kept single view toggle that's always visible (after plugins section)
- Fixes issue where Grid View, Table View, Plugin Store buttons appeared twice