Initial YakPanel commit
This commit is contained in:
@@ -21,7 +21,7 @@ class Settings(BaseSettings):
|
||||
www_logs: str = "/www/wwwlogs"
|
||||
vhost_path: str = "/www/server/panel/vhost"
|
||||
|
||||
# Database (use absolute path for SQLite)
|
||||
# Database (relative SQLite paths are resolved to backend/data/, not process CWD)
|
||||
database_url: str = "sqlite+aiosqlite:///./data/default.db"
|
||||
|
||||
# Redis
|
||||
|
||||
@@ -1,20 +1,36 @@
|
||||
"""YakPanel - Database configuration"""
|
||||
import os
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
|
||||
from pathlib import Path
|
||||
|
||||
from sqlalchemy.engine.url import URL, make_url
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
from app.core.config import get_settings
|
||||
|
||||
|
||||
settings = get_settings()
|
||||
def _resolve_database_url(raw_url: str) -> str:
|
||||
"""Anchor relative SQLite paths to the backend directory (not process CWD)."""
|
||||
url = make_url(raw_url)
|
||||
if not url.drivername.startswith("sqlite"):
|
||||
return raw_url
|
||||
db_path = url.database
|
||||
if db_path is None or db_path.startswith(":"):
|
||||
return raw_url
|
||||
path = Path(db_path)
|
||||
backend_dir = Path(__file__).resolve().parent.parent
|
||||
if not path.is_absolute():
|
||||
path = (backend_dir / path).resolve()
|
||||
else:
|
||||
path = path.resolve()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
return str(URL.create(drivername=url.drivername, database=str(path)))
|
||||
|
||||
# Ensure data directory exists for SQLite
|
||||
if "sqlite" in settings.database_url:
|
||||
backend_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
data_dir = os.path.join(backend_dir, "data")
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
settings = get_settings()
|
||||
DATABASE_URL = _resolve_database_url(settings.database_url)
|
||||
|
||||
engine = create_async_engine(
|
||||
settings.database_url,
|
||||
DATABASE_URL,
|
||||
echo=settings.debug,
|
||||
)
|
||||
|
||||
@@ -29,6 +45,7 @@ AsyncSessionLocal = async_sessionmaker(
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
"""SQLAlchemy declarative base"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@@ -48,13 +65,22 @@ async def get_db():
|
||||
def _run_migrations(conn):
|
||||
"""Add new columns to existing tables (SQLite)."""
|
||||
import sqlalchemy
|
||||
|
||||
try:
|
||||
r = conn.execute(sqlalchemy.text("PRAGMA table_info(sites)"))
|
||||
cols = [row[1] for row in r.fetchall()]
|
||||
if "php_version" not in cols:
|
||||
conn.execute(sqlalchemy.text("ALTER TABLE sites ADD COLUMN php_version VARCHAR(16) DEFAULT '74'"))
|
||||
conn.execute(
|
||||
sqlalchemy.text(
|
||||
"ALTER TABLE sites ADD COLUMN php_version VARCHAR(16) DEFAULT '74'"
|
||||
)
|
||||
)
|
||||
if "force_https" not in cols:
|
||||
conn.execute(sqlalchemy.text("ALTER TABLE sites ADD COLUMN force_https INTEGER DEFAULT 0"))
|
||||
conn.execute(
|
||||
sqlalchemy.text(
|
||||
"ALTER TABLE sites ADD COLUMN force_https INTEGER DEFAULT 0"
|
||||
)
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
# Create backup_plans if not exists (create_all handles new installs)
|
||||
@@ -91,6 +117,7 @@ def _run_migrations(conn):
|
||||
async def init_db():
|
||||
"""Initialize database tables"""
|
||||
import app.models # noqa: F401 - register all models with Base.metadata
|
||||
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
if "sqlite" in str(engine.url):
|
||||
|
||||
Reference in New Issue
Block a user