Files
cms-SiteForge/app/console_v819.py
T

75 lines
3.2 KiB
Python
Raw Normal View History

"""Authorized, versioned navigation contract for the single SiteForge console.
The frontend is not an authorization authority: every business API keeps its
own server-side membership checks. This endpoint only returns allowed context.
"""
from fastapi import APIRouter, HTTPException, Request
from . import db, enterprise
from .version import VERSION
router = APIRouter(prefix='/api/console', tags=['Console'])
NAVIGATION = (
('dashboard', '工作台', '/siteforge/dashboard', None),
('sites', '网站管理', '/siteforge/factory', None),
('content', '内容管理', '/siteforge/content', 'viewer'),
('design', '网站设计', '/siteforge/editor', 'viewer'),
('migration', '数据与迁移', '/siteforge/migration', 'viewer'),
('release', '构建与发布', '/siteforge/releases', 'viewer'),
('system', '系统管理', '/siteforge/enterprise', 'owner'),
)
def available_sites(request: Request):
if request.state.is_superadmin:
return db.rows('SELECT id,name,domain FROM sites ORDER BY updated_at DESC,id')
return db.rows('''SELECT s.id,s.name,s.domain FROM sites s
JOIN team_memberships m ON m.site_id=s.id
JOIN team_users u ON u.id=m.user_id
WHERE m.user_id=? AND u.disabled=0
ORDER BY s.updated_at DESC,s.id''', (request.state.account_id,))
def capabilities(request: Request, site_id: str | None):
role = 'superadmin' if request.state.is_superadmin else 'none'
if site_id and not request.state.is_superadmin:
membership = db.one('SELECT role FROM team_memberships WHERE site_id=? AND user_id=?',
(site_id, request.state.account_id))
role = membership['role'] if membership else 'none'
level = enterprise.ACCESS.get(role, -1)
return dict(role=role, view=level>=0, edit=level>=enterprise.ACCESS['editor'],
review=level>=enterprise.ACCESS['reviewer'],
deploy=level>=enterprise.ACCESS['owner'],
manage_members=level>=enterprise.ACCESS['owner'],
create_site=bool(request.state.is_superadmin),
manage_users=bool(request.state.is_superadmin))
@router.get('/bootstrap')
def bootstrap(request: Request, site_id: str = ''):
"""Return user-scoped menus, never expose unassigned websites or credentials."""
sites = available_sites(request)
ids = {x['id'] for x in sites}
if site_id and site_id not in ids:
raise HTTPException(403, '没有访问该网站的权限')
selected = site_id or (sites[0]['id'] if sites else None)
rights = capabilities(request, selected)
sections = []
for key, title, path, required in NAVIGATION:
if required and not selected:
continue
if required and not rights['view']:
continue
if key == 'system' and not (rights['manage_members'] or rights['manage_users']):
continue
sections.append({'key': key, 'title': title, 'path': path, 'requires_site': bool(required)})
return {
'version': VERSION,
'user': request.state.actor,
'superadmin': bool(request.state.is_superadmin),
'sites': sites,
'selected_site_id': selected,
'capabilities': rights,
'navigation': sections,
}