Add user notification preferences and related API endpoints

- Introduced a new model `UserNotificationPreferences` to store user-specific notification dismissal settings.
- Added context processor to include notification preferences in templates.
- Implemented API endpoints to dismiss backup and AI scanner notifications permanently.
- Updated front-end logic to handle notification dismissal via server-side checks and API calls.
- Enhanced documentation to include a new Custom CSS Guide for theme customization.
This commit is contained in:
Master3395
2025-09-15 02:01:11 +02:00
parent 792d91461a
commit 96226989b1
13 changed files with 1122 additions and 25 deletions

View File

@@ -107,6 +107,7 @@ TEMPLATES = [
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'baseTemplate.context_processors.version_context', 'baseTemplate.context_processors.version_context',
'baseTemplate.context_processors.cosmetic_context', 'baseTemplate.context_processors.cosmetic_context',
'baseTemplate.context_processors.notification_preferences_context',
], ],
}, },
}, },

View File

@@ -30,6 +30,7 @@ CyberPanel comes with comprehensive documentation and step-by-step guides:
- 🐳 **[Docker Command Execution](guides/Docker_Command_Execution_Guide.md)** - Execute commands in Docker containers - 🐳 **[Docker Command Execution](guides/Docker_Command_Execution_Guide.md)** - Execute commands in Docker containers
- 🤖 **[AI Scanner Setup](guides/AIScannerDocs.md)** - Configure AI-powered security scanning - 🤖 **[AI Scanner Setup](guides/AIScannerDocs.md)** - Configure AI-powered security scanning
- 📧 **[Mautic Installation](guides/MAUTIC_INSTALLATION_GUIDE.md)** - Email marketing platform setup - 📧 **[Mautic Installation](guides/MAUTIC_INSTALLATION_GUIDE.md)** - Email marketing platform setup
- 🎨 **[Custom CSS Guide](guides/CUSTOM_CSS_GUIDE.md)** - Create custom themes for CyberPanel 2.5.5-dev
--- ---
@@ -109,7 +110,6 @@ Install CyberPanel easily with the following command:
sh <(curl https://cyberpanel.net/install.sh || wget -O - https://cyberpanel.net/install.sh) sh <(curl https://cyberpanel.net/install.sh || wget -O - https://cyberpanel.net/install.sh)
``` ```
--- ---
## 📊 Upgrading CyberPanel ## 📊 Upgrading CyberPanel
@@ -125,6 +125,7 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr
## 🆕 Recent Updates & Fixes ## 🆕 Recent Updates & Fixes
### **Bandwidth Reset Issue Fixed** (January 2025) ### **Bandwidth Reset Issue Fixed** (January 2025)
- **Issue**: Monthly bandwidth usage was not resetting, causing cumulative values to grow indefinitely - **Issue**: Monthly bandwidth usage was not resetting, causing cumulative values to grow indefinitely
- **Solution**: Implemented automatic monthly bandwidth reset for all websites and child domains - **Solution**: Implemented automatic monthly bandwidth reset for all websites and child domains
- **Affected OS**: All supported operating systems (Ubuntu, AlmaLinux, RockyLinux, RHEL, CloudLinux, CentOS) - **Affected OS**: All supported operating systems (Ubuntu, AlmaLinux, RockyLinux, RHEL, CloudLinux, CentOS)
@@ -132,6 +133,7 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr
- **Documentation**: See [Bandwidth Reset Fix Guide](to-do/cyberpanel-bandwidth-reset-fix.md) - **Documentation**: See [Bandwidth Reset Fix Guide](to-do/cyberpanel-bandwidth-reset-fix.md)
### **New Operating System Support Added** (January 2025) ### **New Operating System Support Added** (January 2025)
- **Ubuntu 24.04.3**: Full compatibility with latest Ubuntu LTS - **Ubuntu 24.04.3**: Full compatibility with latest Ubuntu LTS
- **AlmaLinux 10**: Full compatibility with latest AlmaLinux release - **AlmaLinux 10**: Full compatibility with latest AlmaLinux release
- **Long-term Support**: Both supported until 2029-2030 - **Long-term Support**: Both supported until 2029-2030
@@ -157,15 +159,17 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr
- 🐳 [Docker Command Execution](guides/Docker_Command_Execution_Guide.md) - Execute commands in Docker containers - 🐳 [Docker Command Execution](guides/Docker_Command_Execution_Guide.md) - Execute commands in Docker containers
- 🤖 [AI Scanner Setup](guides/AIScannerDocs.md) - Configure AI-powered security scanning - 🤖 [AI Scanner Setup](guides/AIScannerDocs.md) - Configure AI-powered security scanning
- 📧 [Mautic Installation](guides/MAUTIC_INSTALLATION_GUIDE.md) - Email marketing platform setup - 📧 [Mautic Installation](guides/MAUTIC_INSTALLATION_GUIDE.md) - Email marketing platform setup
- 🎨 [Custom CSS Guide](guides/CUSTOM_CSS_GUIDE.md) - Create custom themes for CyberPanel 2.5.5+
- 📚 [All Guides Index](guides/INDEX.md) - Complete documentation hub - 📚 [All Guides Index](guides/INDEX.md) - Complete documentation hub
### 🔗 **Direct Guide Links** ### 🔗 **Direct Guide Links**
| Feature | Guide | Description | | Feature | Guide | Description |
| ----------- | ---------------------------------------------------------- | ------------------------------ | | ------------ | ---------------------------------------------------------- | ---------------------------------- |
| 🐳 Docker | [Command Execution](guides/Docker_Command_Execution_Guide.md) | Execute commands in containers | | 🐳 Docker | [Command Execution](guides/Docker_Command_Execution_Guide.md) | Execute commands in containers |
| 🤖 Security | [AI Scanner](guides/AIScannerDocs.md) | AI-powered security scanning | | 🤖 Security | [AI Scanner](guides/AIScannerDocs.md) | AI-powered security scanning |
| 📧 Email | [Mautic Setup](guides/MAUTIC_INSTALLATION_GUIDE.md) | Email marketing platform | | 📧 Email | [Mautic Setup](guides/MAUTIC_INSTALLATION_GUIDE.md) | Email marketing platform |
| 🎨 Design | [Custom CSS Guide](guides/CUSTOM_CSS_GUIDE.md) | Create custom themes for 2.5.5-dev |
| 📊 Bandwidth | [Reset Fix Guide](to-do/cyberpanel-bandwidth-reset-fix.md) | Fix bandwidth reset issues | | 📊 Bandwidth | [Reset Fix Guide](to-do/cyberpanel-bandwidth-reset-fix.md) | Fix bandwidth reset issues |
| 📚 All | [Complete Index](guides/INDEX.md) | Browse all available guides | | 📚 All | [Complete Index](guides/INDEX.md) | Browse all available guides |
@@ -176,12 +180,13 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr
### **Common Issues & Solutions** ### **Common Issues & Solutions**
#### **Bandwidth Not Resetting Monthly** #### **Bandwidth Not Resetting Monthly**
- **Issue**: Bandwidth usage shows cumulative values instead of monthly usage - **Issue**: Bandwidth usage shows cumulative values instead of monthly usage
- **Solution**: Run the bandwidth reset script: `/usr/local/CyberCP/scripts/reset_bandwidth.sh` - **Solution**: Run the bandwidth reset script: `/usr/local/CyberCP/scripts/reset_bandwidth.sh`
- **Prevention**: Ensure monthly cron job is running: `0 0 1 * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/postfixSenderPolicy/client.py monthlyCleanup` - **Prevention**: Ensure monthly cron job is running: `0 0 1 * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/postfixSenderPolicy/client.py monthlyCleanup`
#### **General Support** #### **General Support**
- Check logs: `/usr/local/lscp/logs/error.log` - Check logs: `/usr/local/lscp/logs/error.log`
- Verify cron jobs: `crontab -l` - Verify cron jobs: `crontab -l`
- Test manual reset: Use provided scripts in `/usr/local/CyberCP/scripts/` - Test manual reset: Use provided scripts in `/usr/local/CyberCP/scripts/`

View File

@@ -6,3 +6,6 @@ from django.apps import AppConfig
class BasetemplateConfig(AppConfig): class BasetemplateConfig(AppConfig):
name = 'baseTemplate' name = 'baseTemplate'
def ready(self):
import baseTemplate.signals

View File

@@ -24,3 +24,29 @@ def cosmetic_context(request):
return { return {
'cosmetic': cosmetic 'cosmetic': cosmetic
} }
def notification_preferences_context(request):
"""Add user notification preferences to all templates"""
try:
if 'userID' in request.session:
from .models import UserNotificationPreferences
from loginSystem.models import Administrator
user = Administrator.objects.get(pk=request.session['userID'])
try:
preferences = UserNotificationPreferences.objects.get(user=user)
return {
'backup_notification_dismissed': preferences.backup_notification_dismissed,
'ai_scanner_notification_dismissed': preferences.ai_scanner_notification_dismissed
}
except UserNotificationPreferences.DoesNotExist:
return {
'backup_notification_dismissed': False,
'ai_scanner_notification_dismissed': False
}
except:
pass
return {
'backup_notification_dismissed': False,
'ai_scanner_notification_dismissed': False
}

View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2024-01-01 00:00
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('baseTemplate', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='UserNotificationPreferences',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('backup_notification_dismissed', models.BooleanField(default=False, help_text='Whether user has dismissed the backup notification')),
('ai_scanner_notification_dismissed', models.BooleanField(default=False, help_text='Whether user has dismissed the AI scanner notification')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='notification_preferences', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'User Notification Preferences',
'verbose_name_plural': 'User Notification Preferences',
},
),
]

View File

@@ -2,6 +2,7 @@
from django.db import models from django.db import models
from django.contrib.auth.models import User
# Create your models here. # Create your models here.
@@ -12,3 +13,18 @@ class version(models.Model):
class CyberPanelCosmetic(models.Model): class CyberPanelCosmetic(models.Model):
MainDashboardCSS = models.TextField(default='') MainDashboardCSS = models.TextField(default='')
class UserNotificationPreferences(models.Model):
"""Model to store user notification dismissal preferences"""
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='notification_preferences')
backup_notification_dismissed = models.BooleanField(default=False, help_text="Whether user has dismissed the backup notification")
ai_scanner_notification_dismissed = models.BooleanField(default=False, help_text="Whether user has dismissed the AI scanner notification")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "User Notification Preferences"
verbose_name_plural = "User Notification Preferences"
def __str__(self):
return f"Notification Preferences for {self.user.username}"

23
baseTemplate/signals.py Normal file
View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import UserNotificationPreferences
@receiver(post_save, sender=User)
def create_user_notification_preferences(sender, instance, created, **kwargs):
"""Create default notification preferences when a new user is created"""
if created:
UserNotificationPreferences.objects.create(
user=instance,
backup_notification_dismissed=False,
ai_scanner_notification_dismissed=False
)
@receiver(post_save, sender=User)
def save_user_notification_preferences(sender, instance, **kwargs):
"""Save notification preferences when user is saved"""
if hasattr(instance, 'notification_preferences'):
instance.notification_preferences.save()

View File

@@ -1841,10 +1841,10 @@
// Backup notification banner logic // Backup notification banner logic
function checkBackupStatus() { function checkBackupStatus() {
// Check if user has dismissed the notification in this session // Check if user has dismissed the notification permanently (from server-side context)
if (sessionStorage.getItem('backupNotificationDismissed') === 'true') { {% if backup_notification_dismissed %}
return; return; // Notification already dismissed permanently
} {% endif %}
// Check if user has backup configured (you'll need to implement this API) // Check if user has backup configured (you'll need to implement this API)
// For now, we'll show it by default unless they have a backup plan // For now, we'll show it by default unless they have a backup plan
@@ -1871,16 +1871,34 @@
const body = document.body; const body = document.body;
banner.classList.remove('show'); banner.classList.remove('show');
body.classList.remove('notification-shown'); body.classList.remove('notification-shown');
// Remember dismissal for this session
sessionStorage.setItem('backupNotificationDismissed', 'true'); // Dismiss permanently via API
fetch('/base/dismiss_backup_notification', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
}
})
.then(response => response.json())
.then(data => {
if (data.status === 1) {
console.log('Backup notification dismissed permanently');
} else {
console.error('Failed to dismiss backup notification:', data.error);
}
})
.catch(error => {
console.error('Error dismissing backup notification:', error);
});
} }
// AI Scanner Notification Functions // AI Scanner Notification Functions
function checkAIScannerStatus() { function checkAIScannerStatus() {
// Check if user has dismissed the notification in this session // Check if user has dismissed the notification permanently (from server-side context)
if (sessionStorage.getItem('aiScannerNotificationDismissed') === 'true') { {% if ai_scanner_notification_dismissed %}
return; return; // Notification already dismissed permanently
} {% endif %}
// Check if we're not already on the AI Scanner page // Check if we're not already on the AI Scanner page
if (!window.location.href.includes('aiscanner')) { if (!window.location.href.includes('aiscanner')) {
@@ -1900,8 +1918,26 @@
const body = document.body; const body = document.body;
banner.classList.remove('show'); banner.classList.remove('show');
body.classList.remove('ai-scanner-shown'); body.classList.remove('ai-scanner-shown');
// Remember dismissal for this session
sessionStorage.setItem('aiScannerNotificationDismissed', 'true'); // Dismiss permanently via API
fetch('/base/dismiss_ai_scanner_notification', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
}
})
.then(response => response.json())
.then(data => {
if (data.status === 1) {
console.log('AI scanner notification dismissed permanently');
} else {
console.error('Failed to dismiss AI scanner notification:', data.error);
}
})
.catch(error => {
console.error('Error dismissing AI scanner notification:', error);
});
} }
// Check both notification statuses when page loads // Check both notification statuses when page loads

View File

@@ -24,4 +24,7 @@ urlpatterns = [
re_path(r'^getSSHUserActivity$', views.getSSHUserActivity, name='getSSHUserActivity'), re_path(r'^getSSHUserActivity$', views.getSSHUserActivity, name='getSSHUserActivity'),
re_path(r'^getTopProcesses$', views.getTopProcesses, name='getTopProcesses'), re_path(r'^getTopProcesses$', views.getTopProcesses, name='getTopProcesses'),
re_path(r'^analyzeSSHSecurity$', views.analyzeSSHSecurity, name='analyzeSSHSecurity'), re_path(r'^analyzeSSHSecurity$', views.analyzeSSHSecurity, name='analyzeSSHSecurity'),
re_path(r'^dismiss_backup_notification$', views.dismiss_backup_notification, name='dismiss_backup_notification'),
re_path(r'^dismiss_ai_scanner_notification$', views.dismiss_ai_scanner_notification, name='dismiss_ai_scanner_notification'),
re_path(r'^get_notification_preferences$', views.get_notification_preferences, name='get_notification_preferences'),
] ]

View File

@@ -6,7 +6,7 @@ from django.http import HttpResponse
from plogical.getSystemInformation import SystemInformation from plogical.getSystemInformation import SystemInformation
import json import json
from loginSystem.views import loadLoginPage from loginSystem.views import loadLoginPage
from .models import version from .models import version, UserNotificationPreferences
import requests import requests
import subprocess import subprocess
import shlex import shlex
@@ -1305,3 +1305,88 @@ def getTopProcesses(request):
except Exception as e: except Exception as e:
return HttpResponse(json.dumps({'error': str(e)}), content_type='application/json', status=500) return HttpResponse(json.dumps({'error': str(e)}), content_type='application/json', status=500)
@csrf_exempt
@require_POST
def dismiss_backup_notification(request):
"""API endpoint to permanently dismiss the backup notification for the current user"""
try:
user_id = request.session.get('userID')
if not user_id:
return HttpResponse(json.dumps({'status': 0, 'error': 'Not logged in'}), content_type='application/json', status=403)
# Get or create user notification preferences
user = Administrator.objects.get(pk=user_id)
preferences, created = UserNotificationPreferences.objects.get_or_create(
user=user,
defaults={
'backup_notification_dismissed': False,
'ai_scanner_notification_dismissed': False
}
)
# Mark backup notification as dismissed
preferences.backup_notification_dismissed = True
preferences.save()
return HttpResponse(json.dumps({'status': 1, 'message': 'Backup notification dismissed permanently'}), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'status': 0, 'error': str(e)}), content_type='application/json', status=500)
@csrf_exempt
@require_POST
def dismiss_ai_scanner_notification(request):
"""API endpoint to permanently dismiss the AI scanner notification for the current user"""
try:
user_id = request.session.get('userID')
if not user_id:
return HttpResponse(json.dumps({'status': 0, 'error': 'Not logged in'}), content_type='application/json', status=403)
# Get or create user notification preferences
user = Administrator.objects.get(pk=user_id)
preferences, created = UserNotificationPreferences.objects.get_or_create(
user=user,
defaults={
'backup_notification_dismissed': False,
'ai_scanner_notification_dismissed': False
}
)
# Mark AI scanner notification as dismissed
preferences.ai_scanner_notification_dismissed = True
preferences.save()
return HttpResponse(json.dumps({'status': 1, 'message': 'AI scanner notification dismissed permanently'}), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'status': 0, 'error': str(e)}), content_type='application/json', status=500)
@csrf_exempt
@require_GET
def get_notification_preferences(request):
"""API endpoint to get current user's notification preferences"""
try:
user_id = request.session.get('userID')
if not user_id:
return HttpResponse(json.dumps({'status': 0, 'error': 'Not logged in'}), content_type='application/json', status=403)
# Get user notification preferences
user = Administrator.objects.get(pk=user_id)
try:
preferences = UserNotificationPreferences.objects.get(user=user)
return HttpResponse(json.dumps({
'status': 1,
'backup_notification_dismissed': preferences.backup_notification_dismissed,
'ai_scanner_notification_dismissed': preferences.ai_scanner_notification_dismissed
}), content_type='application/json')
except UserNotificationPreferences.DoesNotExist:
# Return default values if preferences don't exist yet
return HttpResponse(json.dumps({
'status': 1,
'backup_notification_dismissed': False,
'ai_scanner_notification_dismissed': False
}), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'status': 0, 'error': str(e)}), content_type='application/json', status=500)

829
guides/CUSTOM_CSS_GUIDE.md Normal file
View File

@@ -0,0 +1,829 @@
# CyberPanel 2.5.5-dev Custom CSS Guide
A comprehensive guide for creating custom CSS that fully works with the new design system of CyberPanel 2.5.5-dev.
## Table of Contents
1. [Overview](#overview)
2. [Design System Architecture](#design-system-architecture)
3. [CSS Variables Reference](#css-variables-reference)
4. [Component Structure](#component-structure)
5. [Customization Examples](#customization-examples)
6. [Best Practices](#best-practices)
7. [Troubleshooting](#troubleshooting)
8. [Advanced Techniques](#advanced-techniques)
## Overview
CyberPanel 2.5.5-dev features a modern, CSS-variable-based design system that supports both light and dark themes. The system is built with:
- **CSS Custom Properties (Variables)** for consistent theming
- **Modern CSS Grid and Flexbox** layouts
- **Responsive design** principles
- **Dark mode support** with automatic theme switching
- **Component-based architecture** for easy customization
## Design System Architecture
### Core Structure
The design system is built around CSS custom properties defined in `:root` and `[data-theme="dark"]` selectors:
```css
:root {
/* Light Theme Variables */
--bg-primary: #f0f0ff;
--bg-secondary: white;
--text-primary: #2f3640;
--accent-color: #5856d6;
/* ... more variables */
}
[data-theme="dark"] {
/* Dark Theme Variables */
--bg-primary: #0f0f23;
--bg-secondary: #1a1a3e;
--text-primary: #e4e4e7;
--accent-color: #7c7ff3;
/* ... more variables */
}
```
### Key Components
1. **Header** (`#header`) - Top navigation bar
2. **Sidebar** (`#sidebar`) - Left navigation panel
3. **Main Content** (`#main-content`) - Page content area
4. **Cards** (`.content-card`) - Content containers
5. **Buttons** (`.btn`) - Interactive elements
6. **Forms** (`.form-*`) - Input elements
## CSS Variables Reference
### Color Variables
#### Background Colors
```css
--bg-primary /* Main background color */
--bg-secondary /* Card/container background */
--bg-sidebar /* Sidebar background */
--bg-sidebar-item /* Sidebar menu item background */
--bg-hover /* Hover state background */
```
#### Text Colors
```css
--text-primary /* Main text color */
--text-secondary /* Secondary text color */
--text-heading /* Heading text color */
```
#### Accent Colors
```css
--accent-color /* Primary accent color */
--accent-hover /* Accent hover state */
--danger-color /* Error/danger color */
--success-color /* Success color */
```
#### Border & Shadow
```css
--border-color /* Default border color */
--shadow-color /* Default shadow color */
```
### Special Variables
#### Gradients
```css
--warning-bg /* Warning banner gradient */
--ai-banner-bg /* AI scanner banner gradient */
```
#### Status Colors
```css
--success-bg /* Success background */
--success-border /* Success border */
--danger-bg /* Danger background */
--danger-border /* Danger border */
--warning-bg /* Warning background */
--info-bg /* Info background */
```
## Component Structure
### Header Component
```css
#header {
background: var(--bg-secondary);
height: 80px;
display: flex;
align-items: center;
padding: 0 30px;
box-shadow: 0 2px 12px var(--shadow-color);
position: fixed;
top: 0;
left: 260px;
right: 0;
z-index: 1000;
}
```
**Customization Example:**
```css
/* Change header height and add custom styling */
#header {
height: 100px;
background: linear-gradient(135deg, var(--accent-color), var(--accent-hover));
border-bottom: 3px solid var(--accent-color);
}
#header .logo-text .brand {
font-size: 32px;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
```
### Sidebar Component
```css
#sidebar {
width: 260px;
background: var(--bg-sidebar);
height: 100vh;
position: fixed;
left: 0;
top: 0;
overflow-y: auto;
z-index: 1001;
}
```
**Customization Example:**
```css
/* Make sidebar wider with custom styling */
#sidebar {
width: 300px;
background: linear-gradient(180deg, var(--bg-sidebar), var(--bg-secondary));
border-right: 2px solid var(--accent-color);
}
#sidebar .menu-item {
margin: 4px 20px;
border-radius: 12px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
#sidebar .menu-item:hover {
transform: translateX(5px);
box-shadow: 0 4px 12px var(--shadow-color);
}
```
### Content Cards
```css
.content-card {
background: var(--bg-secondary);
border-radius: 12px;
padding: 30px;
box-shadow: 0 2px 8px var(--shadow-color);
border: 1px solid var(--border-color);
margin-bottom: 25px;
}
```
**Customization Example:**
```css
/* Add glassmorphism effect to cards */
.content-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] .content-card {
background: rgba(26, 26, 62, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
}
```
## Customization Examples
### 1. Complete Theme Override
```css
/* Custom Purple Theme */
:root {
--bg-primary: #f8f4ff;
--bg-secondary: #ffffff;
--bg-sidebar: #f3f0ff;
--bg-hover: #e8e0ff;
--text-primary: #2d1b69;
--text-secondary: #6b46c1;
--accent-color: #8b5cf6;
--accent-hover: #7c3aed;
--border-color: #e0d7ff;
--shadow-color: rgba(139, 92, 246, 0.1);
}
[data-theme="dark"] {
--bg-primary: #1a0b2e;
--bg-secondary: #2d1b69;
--bg-sidebar: #1e0a3e;
--bg-hover: #3d2a7a;
--text-primary: #f3f0ff;
--text-secondary: #c4b5fd;
--accent-color: #a78bfa;
--accent-hover: #8b5cf6;
--border-color: #4c1d95;
--shadow-color: rgba(139, 92, 246, 0.3);
}
```
### 2. Custom Button Styles
```css
/* Custom button variants */
.btn-custom {
background: linear-gradient(135deg, var(--accent-color), var(--accent-hover));
border: none;
border-radius: 20px;
padding: 12px 24px;
color: white;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 4px 15px rgba(139, 92, 246, 0.3);
transition: all 0.3s ease;
}
.btn-custom:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(139, 92, 246, 0.4);
}
.btn-custom:active {
transform: translateY(0);
}
```
### 3. Custom Sidebar Menu Items
```css
/* Animated sidebar menu items */
#sidebar .menu-item {
position: relative;
overflow: hidden;
}
#sidebar .menu-item::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
#sidebar .menu-item:hover::before {
left: 100%;
}
#sidebar .menu-item .icon-wrapper {
position: relative;
z-index: 1;
}
```
### 4. Custom Form Styling
```css
/* Modern form inputs */
.form-control {
border: 2px solid var(--border-color);
border-radius: 12px;
padding: 12px 16px;
font-size: 14px;
transition: all 0.3s ease;
background: var(--bg-secondary);
}
.form-control:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.1);
transform: translateY(-1px);
}
.form-control::placeholder {
color: var(--text-secondary);
opacity: 0.7;
}
```
### 5. Custom Notifications
```css
/* Custom notification banners */
.notification-banner {
background: linear-gradient(135deg, var(--accent-color), var(--accent-hover));
border-radius: 16px;
padding: 20px;
margin: 20px;
box-shadow: 0 8px 32px rgba(139, 92, 246, 0.3);
position: relative;
overflow: hidden;
}
.notification-banner::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4);
animation: rainbow 3s linear infinite;
}
@keyframes rainbow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
```
## Best Practices
### 1. Use CSS Variables
Always use CSS variables instead of hardcoded values:
```css
/* ✅ Good */
.custom-element {
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
/* ❌ Bad */
.custom-element {
background: white;
color: #2f3640;
border: 1px solid #e8e9ff;
}
```
### 2. Support Both Themes
Always provide both light and dark theme support:
```css
.custom-element {
background: var(--bg-secondary);
color: var(--text-primary);
}
/* Dark theme specific adjustments */
[data-theme="dark"] .custom-element {
/* Additional dark theme styling if needed */
}
```
### 3. Use Semantic Class Names
```css
/* ✅ Good */
.primary-button { }
.content-container { }
.navigation-item { }
/* ❌ Bad */
.red-button { }
.big-box { }
.item1 { }
```
### 4. Maintain Responsive Design
```css
.custom-element {
padding: 20px;
font-size: 16px;
}
@media (max-width: 768px) {
.custom-element {
padding: 15px;
font-size: 14px;
}
}
```
### 5. Use Modern CSS Features
```css
.custom-element {
/* Use CSS Grid for layouts */
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
/* Use Flexbox for alignment */
align-items: center;
justify-content: space-between;
/* Use CSS custom properties for calculations */
--element-height: 60px;
height: var(--element-height);
/* Use modern selectors */
&:hover { }
&:focus-within { }
}
```
## Troubleshooting
### Common Issues
#### 1. Custom CSS Not Applying
**Problem:** Custom CSS doesn't appear to be working.
**Solution:**
- Check CSS specificity - use more specific selectors
- Ensure CSS is placed after the base styles
- Use `!important` sparingly and only when necessary
```css
/* Increase specificity */
#main-content .content-card .custom-element {
background: var(--bg-secondary);
}
```
#### 2. Dark Mode Not Working
**Problem:** Custom styles don't adapt to dark mode.
**Solution:**
- Always use CSS variables
- Test both light and dark themes
- Provide dark mode specific overrides when needed
```css
.custom-element {
background: var(--bg-secondary);
color: var(--text-primary);
}
[data-theme="dark"] .custom-element {
/* Dark mode specific adjustments */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
```
#### 3. Responsive Issues
**Problem:** Custom styles break on mobile devices.
**Solution:**
- Use relative units (rem, em, %)
- Test on different screen sizes
- Use CSS Grid and Flexbox for responsive layouts
```css
.custom-element {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
@media (max-width: 768px) {
.custom-element {
padding: 0.5rem;
}
}
```
## Advanced Techniques
### 1. CSS Animations
```css
/* Smooth page transitions */
.page-transition {
animation: fadeIn 0.3s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* Hover animations */
.interactive-element {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.interactive-element:hover {
transform: translateY(-2px) scale(1.02);
box-shadow: 0 8px 25px var(--shadow-color);
}
```
### 2. CSS Grid Layouts
```css
/* Advanced grid layouts */
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
padding: 20px;
}
.dashboard-card {
grid-column: span 1;
background: var(--bg-secondary);
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px var(--shadow-color);
}
.dashboard-card.featured {
grid-column: span 2;
}
@media (max-width: 768px) {
.dashboard-card.featured {
grid-column: span 1;
}
}
```
### 3. CSS Custom Properties with JavaScript
```css
/* Dynamic theming with CSS variables */
:root {
--custom-accent: #5856d6;
--custom-accent-hover: #4644c0;
}
.custom-theme {
--accent-color: var(--custom-accent);
--accent-hover: var(--custom-accent-hover);
}
```
### 4. Advanced Selectors
```css
/* Complex selectors for specific styling */
#sidebar .menu-item:not(.active):hover {
background: var(--bg-hover);
transform: translateX(5px);
}
.content-card > *:first-child {
margin-top: 0;
}
.content-card > *:last-child {
margin-bottom: 0;
}
/* Attribute selectors */
[data-status="success"] {
border-left: 4px solid var(--success-color);
}
[data-status="error"] {
border-left: 4px solid var(--danger-color);
}
```
### 5. CSS Functions and Calculations
```css
/* Using CSS functions */
.responsive-text {
font-size: clamp(14px, 2.5vw, 18px);
line-height: calc(1.5em + 0.5vw);
}
.dynamic-spacing {
padding: calc(1rem + 2vw);
margin: calc(0.5rem + 1vw);
}
/* CSS custom properties with calculations */
:root {
--base-size: 16px;
--scale-factor: 1.2;
--large-size: calc(var(--base-size) * var(--scale-factor));
}
```
## Implementation Guide
### Step 1: Access the Design Page
1. Log into CyberPanel
2. Navigate to **Design** in the sidebar
3. Scroll down to the **Custom CSS** section
### Step 2: Add Your Custom CSS
1. Paste your custom CSS into the textarea
2. Click **Save Changes**
3. Refresh the page to see your changes
### Step 3: Test Your Changes
1. Test in both light and dark modes
2. Test on different screen sizes
3. Verify all interactive elements work correctly
### Step 4: Iterate and Refine
1. Make adjustments as needed
2. Test thoroughly before finalizing
3. Document your customizations
## Example: Complete Custom Theme
Here's a complete example of a custom theme that you can use as a starting point:
```css
/* Custom CyberPanel Theme - Ocean Blue */
/* Light Theme */
:root {
--bg-primary: #f0f9ff;
--bg-secondary: #ffffff;
--bg-sidebar: #e0f2fe;
--bg-sidebar-item: #ffffff;
--bg-hover: #bae6fd;
--text-primary: #0c4a6e;
--text-secondary: #0369a1;
--text-heading: #0c4a6e;
--border-color: #bae6fd;
--shadow-color: rgba(6, 105, 161, 0.1);
--accent-color: #0284c7;
--accent-hover: #0369a1;
--danger-color: #dc2626;
--success-color: #059669;
--warning-bg: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
--ai-banner-bg: linear-gradient(135deg, #0284c7 0%, #0369a1 50%, #0c4a6e 100%);
}
/* Dark Theme */
[data-theme="dark"] {
--bg-primary: #0c4a6e;
--bg-secondary: #075985;
--bg-sidebar: #0c4a6e;
--bg-sidebar-item: #075985;
--bg-hover: #0369a1;
--text-primary: #e0f2fe;
--text-secondary: #bae6fd;
--text-heading: #f0f9ff;
--border-color: #0369a1;
--shadow-color: rgba(0, 0, 0, 0.3);
--accent-color: #38bdf8;
--accent-hover: #0ea5e9;
--danger-color: #f87171;
--success-color: #34d399;
--warning-bg: linear-gradient(135deg, #78350f 0%, #92400e 100%);
--ai-banner-bg: linear-gradient(135deg, #0c4a6e 0%, #075985 50%, #0369a1 100%);
}
/* Custom Header Styling */
#header {
background: linear-gradient(135deg, var(--accent-color), var(--accent-hover));
box-shadow: 0 4px 20px var(--shadow-color);
}
#header .logo-text .brand {
color: white;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Custom Sidebar Styling */
#sidebar {
background: linear-gradient(180deg, var(--bg-sidebar), var(--bg-secondary));
border-right: 3px solid var(--accent-color);
}
#sidebar .menu-item {
border-radius: 12px;
margin: 4px 20px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
#sidebar .menu-item:hover {
transform: translateX(8px);
box-shadow: 0 4px 15px var(--shadow-color);
}
#sidebar .menu-item.active {
background: linear-gradient(135deg, var(--accent-color), var(--accent-hover));
box-shadow: 0 4px 15px rgba(2, 132, 199, 0.3);
}
/* Custom Content Cards */
.content-card {
background: var(--bg-secondary);
border-radius: 16px;
box-shadow: 0 4px 20px var(--shadow-color);
border: 1px solid var(--border-color);
position: relative;
overflow: hidden;
}
.content-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, var(--accent-color), var(--accent-hover));
}
/* Custom Buttons */
.btn {
border-radius: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.btn-primary {
background: linear-gradient(135deg, var(--accent-color), var(--accent-hover));
box-shadow: 0 4px 15px rgba(2, 132, 199, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(2, 132, 199, 0.4);
}
/* Custom Form Elements */
.form-control {
border: 2px solid var(--border-color);
border-radius: 12px;
transition: all 0.3s ease;
}
.form-control:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 4px rgba(2, 132, 199, 0.1);
transform: translateY(-1px);
}
/* Custom Animations */
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.content-card {
animation: slideIn 0.5s ease-out;
}
/* Responsive Design */
@media (max-width: 768px) {
#sidebar {
width: 100%;
height: auto;
position: relative;
}
#header {
left: 0;
}
.content-card {
margin: 10px;
padding: 20px;
}
}
```
This guide provides everything you need to create beautiful, functional custom CSS for CyberPanel 2.5.5+. Remember to always test your changes thoroughly and use the CSS variables for consistency across themes.

View File

@@ -14,6 +14,9 @@ Welcome to the CyberPanel documentation hub! This folder contains all guides, tu
### 📧 Email & Marketing ### 📧 Email & Marketing
- **[Mautic Installation Guide](MAUTIC_INSTALLATION_GUIDE.md)** - Step-by-step guide for installing and configuring Mautic email marketing platform - **[Mautic Installation Guide](MAUTIC_INSTALLATION_GUIDE.md)** - Step-by-step guide for installing and configuring Mautic email marketing platform
### 🎨 Customization & Design
- **[Custom CSS Guide](CUSTOM_CSS_GUIDE.md)** - Complete guide for creating custom CSS that works with CyberPanel 2.5.5-dev design system
### 📖 General Documentation ### 📖 General Documentation
- **[README](../README.md)** - Main CyberPanel documentation with installation instructions and feature overview - **[README](../README.md)** - Main CyberPanel documentation with installation instructions and feature overview
- **[Contributing Guide](CONTRIBUTING.md)** - Guidelines for contributing to the CyberPanel project - **[Contributing Guide](CONTRIBUTING.md)** - Guidelines for contributing to the CyberPanel project
@@ -23,7 +26,8 @@ Welcome to the CyberPanel documentation hub! This folder contains all guides, tu
1. **New to CyberPanel?** Start with the [README](../README.md) for installation and basic setup 1. **New to CyberPanel?** Start with the [README](../README.md) for installation and basic setup
2. **Need Docker help?** Check the [Docker Command Execution Guide](Docker_Command_Execution_Guide.md) 2. **Need Docker help?** Check the [Docker Command Execution Guide](Docker_Command_Execution_Guide.md)
3. **Setting up email marketing?** Follow the [Mautic Installation Guide](MAUTIC_INSTALLATION_GUIDE.md) 3. **Setting up email marketing?** Follow the [Mautic Installation Guide](MAUTIC_INSTALLATION_GUIDE.md)
4. **Want to contribute?** Read the [Contributing Guide](CONTRIBUTING.md) 4. **Want to customize the interface?** Check the [Custom CSS Guide](CUSTOM_CSS_GUIDE.md)
5. **Want to contribute?** Read the [Contributing Guide](CONTRIBUTING.md)
## 🔍 Finding What You Need ## 🔍 Finding What You Need
@@ -31,6 +35,7 @@ Welcome to the CyberPanel documentation hub! This folder contains all guides, tu
- **Docker Features**: [Docker Command Execution Guide](Docker_Command_Execution_Guide.md) - **Docker Features**: [Docker Command Execution Guide](Docker_Command_Execution_Guide.md)
- **Security Features**: [AI Scanner Documentation](AIScannerDocs.md) - **Security Features**: [AI Scanner Documentation](AIScannerDocs.md)
- **Email Marketing**: [Mautic Installation Guide](MAUTIC_INSTALLATION_GUIDE.md) - **Email Marketing**: [Mautic Installation Guide](MAUTIC_INSTALLATION_GUIDE.md)
- **Customization & Design**: [Custom CSS Guide](CUSTOM_CSS_GUIDE.md)
- **Development**: [Contributing Guide](CONTRIBUTING.md) - **Development**: [Contributing Guide](CONTRIBUTING.md)
## 📝 Guide Categories ## 📝 Guide Categories
@@ -45,6 +50,11 @@ Welcome to the CyberPanel documentation hub! This folder contains all guides, tu
- Third-party applications - Third-party applications
- Custom configurations - Custom configurations
### 🎨 **Customization**
- Custom CSS theming
- Design system integration
- Interface personalization
### 📖 **Documentation** ### 📖 **Documentation**
- Installation guides - Installation guides
- Configuration tutorials - Configuration tutorials

28
run_migration.py Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Migration script for UserNotificationPreferences model
Run this script to apply the database migration for notification preferences
"""
import os
import sys
import django
# Add the project directory to Python path
sys.path.append('/usr/local/CyberCP')
# Set up Django environment
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CyberCP.settings')
django.setup()
from django.core.management import execute_from_command_line
if __name__ == '__main__':
print("Running migration for UserNotificationPreferences...")
try:
execute_from_command_line(['manage.py', 'migrate', 'baseTemplate'])
print("Migration completed successfully!")
except Exception as e:
print(f"Migration failed: {e}")
sys.exit(1)