152 lines
5.8 KiB
Python
152 lines
5.8 KiB
Python
"""
|
|
Admin Panel Database Models
|
|
"""
|
|
from datetime import datetime
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
import bcrypt
|
|
|
|
db = SQLAlchemy()
|
|
|
|
class AdminUser(db.Model):
|
|
"""Admin users table"""
|
|
__tablename__ = 'admin_users'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
username = db.Column(db.String(50), unique=True, nullable=False)
|
|
email = db.Column(db.String(120), unique=True, nullable=False)
|
|
password_hash = db.Column(db.String(255), nullable=False)
|
|
full_name = db.Column(db.String(100))
|
|
role = db.Column(db.String(20), default='admin') # admin, super_admin
|
|
is_active = db.Column(db.Boolean, default=True)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
last_login = db.Column(db.DateTime)
|
|
|
|
def set_password(self, password):
|
|
"""Hash and set password"""
|
|
self.password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
|
|
|
def check_password(self, password):
|
|
"""Verify password"""
|
|
return bcrypt.checkpw(password.encode('utf-8'), self.password_hash.encode('utf-8'))
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'username': self.username,
|
|
'email': self.email,
|
|
'full_name': self.full_name,
|
|
'role': self.role,
|
|
'is_active': self.is_active,
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
'last_login': self.last_login.isoformat() if self.last_login else None,
|
|
}
|
|
|
|
|
|
class SubscriptionPlan(db.Model):
|
|
"""Subscription plans table"""
|
|
__tablename__ = 'subscription_plans'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(50), unique=True, nullable=False)
|
|
slug = db.Column(db.String(50), unique=True, nullable=False)
|
|
description = db.Column(db.Text)
|
|
price_monthly = db.Column(db.Numeric(10, 2), default=0)
|
|
price_yearly = db.Column(db.Numeric(10, 2), default=0)
|
|
|
|
# Limits
|
|
max_domains = db.Column(db.Integer, default=1)
|
|
max_containers = db.Column(db.Integer, default=1)
|
|
max_storage_gb = db.Column(db.Integer, default=10)
|
|
max_bandwidth_gb = db.Column(db.Integer, default=100)
|
|
|
|
# Features (JSON)
|
|
features = db.Column(db.JSON, default=list)
|
|
|
|
is_active = db.Column(db.Boolean, default=True)
|
|
is_visible = db.Column(db.Boolean, default=True)
|
|
sort_order = db.Column(db.Integer, default=0)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'name': self.name,
|
|
'slug': self.slug,
|
|
'description': self.description,
|
|
'price_monthly': float(self.price_monthly) if self.price_monthly else 0,
|
|
'price_yearly': float(self.price_yearly) if self.price_yearly else 0,
|
|
'max_domains': self.max_domains,
|
|
'max_containers': self.max_containers,
|
|
'max_storage_gb': self.max_storage_gb,
|
|
'max_bandwidth_gb': self.max_bandwidth_gb,
|
|
'features': self.features or [],
|
|
'is_active': self.is_active,
|
|
'is_visible': self.is_visible,
|
|
'sort_order': self.sort_order,
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
|
|
}
|
|
|
|
|
|
class CloudflareAccount(db.Model):
|
|
"""Company Cloudflare accounts"""
|
|
__tablename__ = 'cloudflare_accounts'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(100), nullable=False)
|
|
email = db.Column(db.String(120), nullable=False)
|
|
api_token = db.Column(db.Text, nullable=False) # Encrypted
|
|
max_domains = db.Column(db.Integer, default=100)
|
|
current_domains = db.Column(db.Integer, default=0)
|
|
notes = db.Column(db.Text)
|
|
is_active = db.Column(db.Boolean, default=True)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
def to_dict(self, include_token=False):
|
|
data = {
|
|
'id': self.id,
|
|
'name': self.name,
|
|
'email': self.email,
|
|
'max_domains': self.max_domains,
|
|
'current_domains': self.current_domains,
|
|
'notes': self.notes,
|
|
'is_active': self.is_active,
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
|
|
}
|
|
if include_token:
|
|
data['api_token'] = self.api_token
|
|
return data
|
|
|
|
|
|
class AuditLog(db.Model):
|
|
"""Audit logs for admin actions"""
|
|
__tablename__ = 'audit_logs'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
admin_id = db.Column(db.Integer, db.ForeignKey('admin_users.id'))
|
|
action = db.Column(db.String(100), nullable=False)
|
|
resource_type = db.Column(db.String(50)) # customer, plan, cf_account
|
|
resource_id = db.Column(db.Integer)
|
|
details = db.Column(db.JSON)
|
|
ip_address = db.Column(db.String(45))
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
admin = db.relationship('AdminUser', backref='audit_logs')
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'admin_id': self.admin_id,
|
|
'admin_username': self.admin.username if self.admin else None,
|
|
'action': self.action,
|
|
'resource_type': self.resource_type,
|
|
'resource_id': self.resource_id,
|
|
'details': self.details,
|
|
'ip_address': self.ip_address,
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
}
|
|
|