Files
cms-SiteForge/app/reusables.py
T

54 lines
2.9 KiB
Python
Raw Normal View History

"""Site-scoped reusable editor component library with versioned snapshots."""
import json
from fastapi import APIRouter,Body,HTTPException,Request
from . import db,enterprise,blueprints
from .core import uid
router=APIRouter(prefix='/api/sites',tags=['Reusable Components'])
def setup():
with db.connect() as c:
c.executescript('''CREATE TABLE IF NOT EXISTS reusable_components(
id TEXT PRIMARY KEY,site_id TEXT NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
name TEXT NOT NULL,version INTEGER NOT NULL DEFAULT 1,block_json TEXT NOT NULL,
updated_at TEXT NOT NULL);
CREATE INDEX IF NOT EXISTS idx_reuse_site ON reusable_components(site_id);
''')
@router.get('/{site_id}/components')
def all_components(request:Request,site_id:str):
enterprise.require(request,site_id,'viewer')
return [{**r,'block':json.loads(r.pop('block_json'))} for r in db.rows(
'SELECT * FROM reusable_components WHERE site_id=? ORDER BY updated_at DESC',(site_id,))]
@router.post('/{site_id}/components')
def save_component(request:Request,site_id:str,payload:dict=Body(...)):
enterprise.require(request,site_id,'editor')
name=str(payload.get('name','')).strip()[:100]
if not name:raise HTTPException(400,'组件名称不能为空')
try:block=blueprints.validate_blocks([payload.get('block')])[0]
except (ValueError,TypeError) as exc:raise HTTPException(400,str(exc))
cid=uid()
db.insert('INSERT INTO reusable_components VALUES (?,?,?,?,?,?)',
(cid,site_id,name,1,json.dumps(block,ensure_ascii=False),db.now()))
return {'id':cid,'name':name,'version':1,'block':block}
@router.put('/{site_id}/components/{component_id}')
def update_component(request:Request,site_id:str,component_id:str,payload:dict=Body(...)):
enterprise.require(request,site_id,'editor')
current=db.one('SELECT * FROM reusable_components WHERE site_id=? AND id=?',(site_id,component_id))
if not current:raise HTTPException(404)
if payload.get('expected_version')!=current['version']:raise HTTPException(409,'组件已被修改,请重新加载')
try:block=blueprints.validate_blocks([payload.get('block')])[0]
except (ValueError,TypeError) as exc:raise HTTPException(400,str(exc))
db.execute('UPDATE reusable_components SET name=?,block_json=?,version=?,updated_at=? WHERE id=? AND site_id=?',
(str(payload.get('name') or current['name'])[:100],json.dumps(block,ensure_ascii=False),current['version']+1,db.now(),component_id,site_id))
return {'id':component_id,'version':current['version']+1}
@router.delete('/{site_id}/components/{component_id}')
def delete_component(request:Request,site_id:str,component_id:str):
enterprise.require(request,site_id,'editor')
if not db.execute('DELETE FROM reusable_components WHERE site_id=? AND id=?',(site_id,component_id)):
raise HTTPException(404)
return {'deleted':True}