fix(entcms): 重写所有数据库操作使用 async with context manager

_get_db() 返回的是 async context manager,不是 sor 对象。
所有函数都错误地直接调用 sor.R/C/U/D,导致 AttributeError。

修正为正确模式:
  db = DBPools()
  async with db.sqlorContext(DBNAME) as sor:
      await sor.R('table', ns)

影响函数:
- cms_content CRUD (4个)
- cms_categories CRUD (4个) + get_category_options
- cms_leads CRUD (4个) + submit_lead
- cms_sections CRUD (4个) + get_visible_sections
- cms_site_config CRUD (4个) + get_site_config
- get_published_content, get_latest_news, get_content_detail
- submit_content_for_approval
This commit is contained in:
yumoqing 2026-06-03 17:24:55 +08:00
parent 2a49ed80d1
commit 7abdc336b7

View File

@ -5,6 +5,7 @@ entcms - 企业CMS系统模块
import json import json
from ahserver.serverenv import ServerEnv from ahserver.serverenv import ServerEnv
from appPublic.uniqueID import getID from appPublic.uniqueID import getID
from sqlor.dbpools import DBPools
MODULE_NAME = "entcms" MODULE_NAME = "entcms"
MODULE_VERSION = "1.0.0" MODULE_VERSION = "1.0.0"
@ -12,16 +13,11 @@ MODULE_VERSION = "1.0.0"
DBNAME = "entcms" DBNAME = "entcms"
def _get_db():
"""获取数据库上下文"""
from sqlor.dbpools import DBPools
return DBPools().sqlorContext(DBNAME)
# ===== CMS Content CRUD ===== # ===== CMS Content CRUD =====
async def cms_content_list(ns=None): async def cms_content_list(ns=None):
"""查询内容列表""" """查询内容列表"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = ns or {} ns = ns or {}
ns.setdefault('sort', 'sort_order asc, created_at desc') ns.setdefault('sort', 'sort_order asc, created_at desc')
rows = await sor.R('cms_content', ns) rows = await sor.R('cms_content', ns)
@ -31,7 +27,8 @@ async def cms_content_list(ns=None):
async def cms_content_create(data): async def cms_content_create(data):
"""创建内容""" """创建内容"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
data['id'] = getID() data['id'] = getID()
await sor.C('cms_content', data) await sor.C('cms_content', data)
return data return data
@ -39,14 +36,16 @@ async def cms_content_create(data):
async def cms_content_update(data): async def cms_content_update(data):
"""更新内容""" """更新内容"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.U('cms_content', data) await sor.U('cms_content', data)
return data return data
async def cms_content_delete(data): async def cms_content_delete(data):
"""删除内容""" """删除内容"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.D('cms_content', data) await sor.D('cms_content', data)
return data return data
@ -54,7 +53,8 @@ async def cms_content_delete(data):
# ===== CMS Categories CRUD ===== # ===== CMS Categories CRUD =====
async def cms_categories_list(ns=None): async def cms_categories_list(ns=None):
"""查询分类列表""" """查询分类列表"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = ns or {} ns = ns or {}
ns.setdefault('sort', 'sort_order asc') ns.setdefault('sort', 'sort_order asc')
rows = await sor.R('cms_categories', ns) rows = await sor.R('cms_categories', ns)
@ -62,27 +62,31 @@ async def cms_categories_list(ns=None):
async def cms_categories_create(data): async def cms_categories_create(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
data['id'] = getID() data['id'] = getID()
await sor.C('cms_categories', data) await sor.C('cms_categories', data)
return data return data
async def cms_categories_update(data): async def cms_categories_update(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.U('cms_categories', data) await sor.U('cms_categories', data)
return data return data
async def cms_categories_delete(data): async def cms_categories_delete(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.D('cms_categories', data) await sor.D('cms_categories', data)
return data return data
async def get_category_options(content_type=None): async def get_category_options(content_type=None):
"""获取分类下拉选项""" """获取分类下拉选项"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = {'sort': 'sort_order asc'} ns = {'sort': 'sort_order asc'}
if content_type: if content_type:
ns['content_type'] = content_type ns['content_type'] = content_type
@ -93,7 +97,8 @@ async def get_category_options(content_type=None):
# ===== CMS Leads CRUD ===== # ===== CMS Leads CRUD =====
async def cms_leads_list(ns=None): async def cms_leads_list(ns=None):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = ns or {} ns = ns or {}
ns.setdefault('sort', 'created_at desc') ns.setdefault('sort', 'created_at desc')
rows = await sor.R('cms_leads', ns) rows = await sor.R('cms_leads', ns)
@ -101,27 +106,31 @@ async def cms_leads_list(ns=None):
async def cms_leads_create(data): async def cms_leads_create(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
data['id'] = getID() data['id'] = getID()
await sor.C('cms_leads', data) await sor.C('cms_leads', data)
return data return data
async def cms_leads_update(data): async def cms_leads_update(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.U('cms_leads', data) await sor.U('cms_leads', data)
return data return data
async def cms_leads_delete(data): async def cms_leads_delete(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.D('cms_leads', data) await sor.D('cms_leads', data)
return data return data
async def submit_lead(data): async def submit_lead(data):
"""公开接口 - 网站访客提交线索""" """公开接口 - 网站访客提交线索"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
data['id'] = getID() data['id'] = getID()
data.setdefault('status', 'new') data.setdefault('status', 'new')
data.setdefault('source', 'website') data.setdefault('source', 'website')
@ -131,31 +140,36 @@ async def submit_lead(data):
# ===== CMS Sections CRUD ===== # ===== CMS Sections CRUD =====
async def cms_sections_list(ns=None): async def cms_sections_list(ns=None):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = ns or {} ns = ns or {}
ns.setdefault('sort', 'sort_order asc') ns.setdefault('sort', 'sort_order asc')
rows = await sor.R('cms_sections', ns) rows = await sor.R('cms_sections', ns)
return {'rows': rows, 'total': len(rows)} return {'rows': rows, 'total': len(rows)}
async def cms_sections_create(data): async def cms_sections_create(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
data['id'] = getID() data['id'] = getID()
await sor.C('cms_sections', data) await sor.C('cms_sections', data)
return data return data
async def cms_sections_update(data): async def cms_sections_update(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.U('cms_sections', data) await sor.U('cms_sections', data)
return data return data
async def cms_sections_delete(data): async def cms_sections_delete(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.D('cms_sections', data) await sor.D('cms_sections', data)
return data return data
async def get_visible_sections(): async def get_visible_sections():
"""获取所有可见栏目(公开接口)""" """获取所有可见栏目(公开接口)"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = {'is_visible': '1', 'sort': 'sort_order asc'} ns = {'is_visible': '1', 'sort': 'sort_order asc'}
rows = await sor.R('cms_sections', ns) rows = await sor.R('cms_sections', ns)
import json as _json import json as _json
@ -169,7 +183,8 @@ async def get_visible_sections():
# ===== CMS Site Config CRUD ===== # ===== CMS Site Config CRUD =====
async def cms_site_config_list(ns=None): async def cms_site_config_list(ns=None):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = ns or {} ns = ns or {}
ns.setdefault('sort', 'config_group asc, sort_order asc') ns.setdefault('sort', 'config_group asc, sort_order asc')
rows = await sor.R('cms_site_config', ns) rows = await sor.R('cms_site_config', ns)
@ -177,27 +192,31 @@ async def cms_site_config_list(ns=None):
async def cms_site_config_create(data): async def cms_site_config_create(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
data['id'] = getID() data['id'] = getID()
await sor.C('cms_site_config', data) await sor.C('cms_site_config', data)
return data return data
async def cms_site_config_update(data): async def cms_site_config_update(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.U('cms_site_config', data) await sor.U('cms_site_config', data)
return data return data
async def cms_site_config_delete(data): async def cms_site_config_delete(data):
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
await sor.D('cms_site_config', data) await sor.D('cms_site_config', data)
return data return data
async def get_site_config(group=None): async def get_site_config(group=None):
"""获取站点配置(公开接口)""" """获取站点配置(公开接口)"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = {'sort': 'sort_order asc'} ns = {'sort': 'sort_order asc'}
if group: if group:
ns['config_group'] = group ns['config_group'] = group
@ -214,7 +233,8 @@ async def get_site_config(group=None):
# ===== Public Content APIs ===== # ===== Public Content APIs =====
async def get_published_content(content_type=None, limit=10): async def get_published_content(content_type=None, limit=10):
"""获取已发布内容(公开接口)""" """获取已发布内容(公开接口)"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = {'status': 'published', 'sort': 'sort_order asc, published_at desc'} ns = {'status': 'published', 'sort': 'sort_order asc, published_at desc'}
if content_type: if content_type:
ns['content_type'] = content_type ns['content_type'] = content_type
@ -226,7 +246,8 @@ async def get_published_content(content_type=None, limit=10):
async def get_latest_news(limit=2): async def get_latest_news(limit=2):
"""获取最新新闻(公开接口)""" """获取最新新闻(公开接口)"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = {'status': 'published', 'content_type': 'news', 'sort': 'published_at desc'} ns = {'status': 'published', 'content_type': 'news', 'sort': 'published_at desc'}
rows = await sor.R('cms_content', ns) rows = await sor.R('cms_content', ns)
return rows[:limit] return rows[:limit]
@ -234,7 +255,8 @@ async def get_latest_news(limit=2):
async def get_content_detail(content_id): async def get_content_detail(content_id):
"""获取内容详情(公开接口)""" """获取内容详情(公开接口)"""
sor = _get_db() db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
ns = {'id': content_id, 'status': 'published'} ns = {'id': content_id, 'status': 'published'}
rows = await sor.R('cms_content', ns) rows = await sor.R('cms_content', ns)
return rows[0] if rows else None return rows[0] if rows else None
@ -243,8 +265,9 @@ async def get_content_detail(content_id):
# ===== Submit for approval ===== # ===== Submit for approval =====
async def submit_content_for_approval(content_id, title, applicant_id): async def submit_content_for_approval(content_id, title, applicant_id):
"""提交内容审批调用dingdingflow""" """提交内容审批调用dingdingflow"""
db = DBPools()
async with db.sqlorContext(DBNAME) as sor:
# 更新内容状态为pending # 更新内容状态为pending
sor = _get_db()
await sor.U('cms_content', {'id': content_id, 'status': 'pending'}) await sor.U('cms_content', {'id': content_id, 'status': 'pending'})
# 调用dingdingflow的submit_approval # 调用dingdingflow的submit_approval
try: try: