chore: baseline V8.10.0-dev.1 with v8_workflows type-mapping fix and trade-pro spec
- SiteForge Enterprise V8.10.0-dev.1 upstream source (210 tests) - Fix: v8_workflows._mapped_input now reads both 类型/分类 columns so WXR imports keep post/product types instead of collapsing to page - Docs: trade-pro theme port spec (R3) and implementation plan Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
"""Local SQLite data store for SiteForge MVP. One database, hard site_id isolation."""
|
||||
import os
|
||||
import sqlite3
|
||||
import json
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
DATA = Path(os.getenv('SITEFORGE_DATA_DIR', str(ROOT / 'storage'))).resolve()
|
||||
DB_FILE = Path(os.getenv('SITEFORGE_DB_FILE',str(DATA / 'siteforge.sqlite3'))).resolve()
|
||||
DATABASE_URL = os.getenv('SITEFORGE_DATABASE_URL','')
|
||||
POSTGRES = DATABASE_URL.startswith(('postgresql://','postgres://'))
|
||||
|
||||
def now():
|
||||
return datetime.now(timezone.utc).isoformat(timespec='seconds')
|
||||
|
||||
def connect():
|
||||
if POSTGRES:
|
||||
from . import pg_compat
|
||||
return pg_compat.connect(DATABASE_URL)
|
||||
DATA.mkdir(parents=True, exist_ok=True)
|
||||
c = sqlite3.connect(DB_FILE)
|
||||
c.row_factory = sqlite3.Row
|
||||
c.execute('PRAGMA foreign_keys = ON')
|
||||
c.execute('PRAGMA busy_timeout=5000')
|
||||
return c
|
||||
|
||||
def init():
|
||||
with connect() as c:
|
||||
c.executescript('''
|
||||
PRAGMA journal_mode=WAL;
|
||||
CREATE TABLE IF NOT EXISTS sites (
|
||||
id TEXT PRIMARY KEY, name TEXT NOT NULL, domain TEXT NOT NULL DEFAULT '',
|
||||
tagline TEXT NOT NULL DEFAULT '', theme TEXT NOT NULL DEFAULT 'corporate',
|
||||
accent TEXT NOT NULL DEFAULT '#2563eb', logo TEXT NOT NULL DEFAULT '',
|
||||
mode TEXT NOT NULL DEFAULT 'new',
|
||||
settings_json TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL, updated_at TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS entries (
|
||||
id TEXT PRIMARY KEY, site_id TEXT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
type TEXT NOT NULL, title TEXT NOT NULL, route TEXT NOT NULL, slug TEXT NOT NULL,
|
||||
summary TEXT NOT NULL DEFAULT '', body TEXT NOT NULL DEFAULT '',
|
||||
cover TEXT NOT NULL DEFAULT '', seo_title TEXT NOT NULL DEFAULT '',
|
||||
seo_description TEXT NOT NULL DEFAULT '', canonical TEXT NOT NULL DEFAULT '',
|
||||
robots TEXT NOT NULL DEFAULT 'index,follow',
|
||||
meta_json TEXT NOT NULL DEFAULT '{}', status TEXT NOT NULL DEFAULT 'published',
|
||||
source TEXT NOT NULL DEFAULT 'manual', created_at TEXT NOT NULL, updated_at TEXT NOT NULL,
|
||||
UNIQUE(site_id, route)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_entries_site ON entries(site_id, type, status);
|
||||
CREATE TABLE IF NOT EXISTS redirects (
|
||||
id TEXT PRIMARY KEY, site_id TEXT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
old_path TEXT NOT NULL, new_path TEXT NOT NULL, status_code INTEGER NOT NULL DEFAULT 301,
|
||||
UNIQUE(site_id, old_path)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS builds (
|
||||
id TEXT PRIMARY KEY, site_id TEXT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
created_at TEXT NOT NULL, status TEXT NOT NULL, total_pages INTEGER NOT NULL DEFAULT 0,
|
||||
report_json TEXT NOT NULL DEFAULT '{}', zip_path TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_builds_site ON builds(site_id, created_at);
|
||||
CREATE TABLE IF NOT EXISTS presets (
|
||||
id TEXT PRIMARY KEY,name TEXT NOT NULL,theme TEXT NOT NULL,
|
||||
settings_json TEXT NOT NULL,home_blocks_json TEXT NOT NULL,created_at TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS content_schemas (
|
||||
site_id TEXT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
content_type TEXT NOT NULL, fields_json TEXT NOT NULL DEFAULT '[]',
|
||||
PRIMARY KEY(site_id,content_type)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS imports (
|
||||
id TEXT PRIMARY KEY, site_id TEXT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
created_at TEXT NOT NULL, source TEXT NOT NULL,
|
||||
result_json TEXT NOT NULL DEFAULT '{}'
|
||||
);
|
||||
''')
|
||||
if not POSTGRES:
|
||||
from . import schema_registry
|
||||
schema_registry.ensure(c)
|
||||
|
||||
def rows(sql, params=()):
|
||||
with connect() as c:
|
||||
return [dict(r) for r in c.execute(sql, params).fetchall()]
|
||||
|
||||
def one(sql, params=()):
|
||||
with connect() as c:
|
||||
r=c.execute(sql, params).fetchone()
|
||||
return dict(r) if r else None
|
||||
|
||||
def execute(sql, params=()):
|
||||
with connect() as c:
|
||||
cur = c.execute(sql, params)
|
||||
return cur.rowcount
|
||||
|
||||
def insert(sql, params=()):
|
||||
with connect() as c:
|
||||
c.execute(sql, params)
|
||||
|
||||
if __name__ == '__main__':
|
||||
init()
|
||||
Reference in New Issue
Block a user