245 lines
9.9 KiB
Python
245 lines
9.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""script_engine.init -- module initialization and business function registration."""
|
|
from ahserver.serverenv import ServerEnv
|
|
from sqlor.dbpools import DBPools
|
|
from appPublic.uniqueID import getID
|
|
from appPublic.timeUtils import curDateString
|
|
from script_engine.engine import validate_script as _validate_content, execute_script_content as _execute_content, VALID_SCRIPT_TYPES
|
|
|
|
_SCRIPT_FIELDS = ('id', 'script_name', 'script_type', 'content', 'description', 'status', 'created_at', 'updated_at')
|
|
|
|
|
|
def _dbname():
|
|
return ServerEnv().get_module_dbname('script_engine')
|
|
|
|
|
|
def _ok(data=None, message='ok'):
|
|
return {'code': 0, 'message': message, 'field': '', 'detail': '', 'data': data}
|
|
|
|
|
|
def _err(code, message, field='', detail=''):
|
|
return {'code': code, 'message': message, 'field': field, 'detail': detail}
|
|
|
|
|
|
def _clean_str(value, default=''):
|
|
if value is None:
|
|
return default
|
|
s = str(value).strip()
|
|
return s if s else default
|
|
|
|
|
|
def _row_to_dict(row):
|
|
out = {}
|
|
for f in _SCRIPT_FIELDS:
|
|
out[f] = getattr(row, f, None)
|
|
return out
|
|
|
|
|
|
def _validate_input(script_name, script_type, content):
|
|
if not script_name:
|
|
return False, 'script_name', 'script name must not be empty'
|
|
if len(script_name) > 100:
|
|
return False, 'script_name', 'script name length must not exceed 100'
|
|
if script_type not in VALID_SCRIPT_TYPES:
|
|
return False, 'script_type', 'unsupported script type: %s' % script_type
|
|
if not content or not content.strip():
|
|
return False, 'content', 'script content must not be empty'
|
|
if len(content) > 65535:
|
|
return False, 'content', 'script content length must not exceed 65535'
|
|
ok, err = _validate_content(content, script_type)
|
|
if not ok:
|
|
return False, 'content', err
|
|
return True, '', ''
|
|
|
|
|
|
async def create_script(request, params_kw):
|
|
try:
|
|
params = params_kw or {}
|
|
script_name = _clean_str(params.get('script_name'))
|
|
script_type = _clean_str(params.get('script_type'), '0')
|
|
content = _clean_str(params.get('content'))
|
|
description = _clean_str(params.get('description'))
|
|
status = _clean_str(params.get('status'), '1')
|
|
ok, field, msg = _validate_input(script_name, script_type, content)
|
|
if not ok:
|
|
return _err(400, msg, field, 'create_script: input validation failed')
|
|
dbname = _dbname()
|
|
db = DBPools()
|
|
now = curDateString()
|
|
new_id = getID()
|
|
ns = {'id': new_id, 'script_name': script_name, 'script_type': script_type, 'content': content, 'description': description, 'status': status, 'created_at': now, 'updated_at': now}
|
|
async with db.sqlorContext(dbname) as sor:
|
|
await sor.C('script', ns)
|
|
return _ok({'id': new_id}, 'created')
|
|
except Exception as e:
|
|
from traceback import format_exc
|
|
return _err(500, 'create failed: %s' % str(e), '', format_exc())
|
|
|
|
|
|
async def update_script(request, params_kw):
|
|
try:
|
|
params = params_kw or {}
|
|
script_id = _clean_str(params.get('id'))
|
|
if not script_id:
|
|
return _err(400, 'script id is required', 'id', 'update_script: id required')
|
|
script_name = _clean_str(params.get('script_name'))
|
|
script_type = _clean_str(params.get('script_type'), '0')
|
|
content = _clean_str(params.get('content'))
|
|
description = _clean_str(params.get('description'))
|
|
status = _clean_str(params.get('status'), '1')
|
|
ok, field, msg = _validate_input(script_name, script_type, content)
|
|
if not ok:
|
|
return _err(400, msg, field, 'update_script: input validation failed')
|
|
dbname = _dbname()
|
|
db = DBPools()
|
|
async with db.sqlorContext(dbname) as sor:
|
|
rows = await sor.R('script', {'id': script_id})
|
|
if not rows:
|
|
return _err(404, 'script not found', 'id', 'update_script: record missing')
|
|
upd = {'id': script_id, 'script_name': script_name, 'script_type': script_type, 'content': content, 'description': description, 'status': status, 'updated_at': curDateString()}
|
|
await sor.U('script', upd)
|
|
return _ok({'id': script_id}, 'updated')
|
|
except Exception as e:
|
|
from traceback import format_exc
|
|
return _err(500, 'update failed: %s' % str(e), '', format_exc())
|
|
|
|
|
|
async def delete_script(request, params_kw):
|
|
try:
|
|
params = params_kw or {}
|
|
script_id = _clean_str(params.get('id'))
|
|
if not script_id:
|
|
return _err(400, 'script id is required', 'id', 'delete_script: id required')
|
|
dbname = _dbname()
|
|
db = DBPools()
|
|
async with db.sqlorContext(dbname) as sor:
|
|
rows = await sor.R('script', {'id': script_id})
|
|
if not rows:
|
|
return _err(404, 'script not found', 'id', 'delete_script: record missing')
|
|
await sor.D('script', {'id': script_id})
|
|
return _ok({'id': script_id}, 'deleted')
|
|
except Exception as e:
|
|
from traceback import format_exc
|
|
return _err(500, 'delete failed: %s' % str(e), '', format_exc())
|
|
|
|
|
|
async def get_script(request, params_kw):
|
|
try:
|
|
params = params_kw or {}
|
|
script_id = _clean_str(params.get('id'))
|
|
if not script_id:
|
|
return _err(400, 'script id is required', 'id', 'get_script: id required')
|
|
dbname = _dbname()
|
|
db = DBPools()
|
|
async with db.sqlorContext(dbname) as sor:
|
|
rows = await sor.R('script', {'id': script_id})
|
|
if not rows:
|
|
return _err(404, 'script not found', 'id', 'get_script: record missing')
|
|
rec = _row_to_dict(rows[0])
|
|
return _ok(rec, 'ok')
|
|
except Exception as e:
|
|
from traceback import format_exc
|
|
return _err(500, 'query failed: %s' % str(e), '', format_exc())
|
|
|
|
|
|
async def list_scripts(request, params_kw):
|
|
try:
|
|
params = params_kw or {}
|
|
page = int(params.get('page', 1) or 1)
|
|
rows = int(params.get('rows', 20) or 20)
|
|
if page < 1:
|
|
page = 1
|
|
if rows < 1 or rows > 200:
|
|
rows = 20
|
|
keyword = _clean_str(params.get('script_name'))
|
|
script_type = _clean_str(params.get('script_type'))
|
|
status = _clean_str(params.get('status'))
|
|
conds = []
|
|
ns = {'page': page, 'rows': rows, 'sort': 'created_at desc'}
|
|
if keyword:
|
|
conds.append('script_name like ${keyword}$')
|
|
ns['keyword'] = '%%%s%%' % keyword
|
|
if script_type:
|
|
conds.append('script_type = ${script_type}$')
|
|
ns['script_type'] = script_type
|
|
if status:
|
|
conds.append('status = ${status}$')
|
|
ns['status'] = status
|
|
where = (' where ' + ' and '.join(conds)) if conds else ''
|
|
sql = 'select id, script_name, script_type, description, status, created_at, updated_at from script%s' % where
|
|
dbname = _dbname()
|
|
db = DBPools()
|
|
async with db.sqlorContext(dbname) as sor:
|
|
result = await sor.sqlPaging(sql, ns)
|
|
total = result.get('total', 0)
|
|
rows_data = result.get('rows', []) or []
|
|
data = [_row_to_dict(r) for r in rows_data]
|
|
return _ok({'list': data, 'total': total}, 'ok')
|
|
except Exception as e:
|
|
from traceback import format_exc
|
|
return _err(500, 'list failed: %s' % str(e), '', format_exc())
|
|
|
|
|
|
async def execute_script(request, params_kw):
|
|
try:
|
|
params = params_kw or {}
|
|
script_id = _clean_str(params.get('id'))
|
|
content = None
|
|
script_type = '0'
|
|
if script_id:
|
|
dbname = _dbname()
|
|
db = DBPools()
|
|
async with db.sqlorContext(dbname) as sor:
|
|
rows = await sor.R('script', {'id': script_id})
|
|
if not rows:
|
|
return _err(404, 'script not found', 'id', 'execute_script: record missing')
|
|
content = rows[0].content
|
|
script_type = str(rows[0].script_type or '0')
|
|
else:
|
|
content = _clean_str(params.get('content'))
|
|
script_type = _clean_str(params.get('script_type'), '0')
|
|
if not content:
|
|
return _err(400, 'script content must not be empty', 'content', 'execute_script: no content')
|
|
ok, field, msg = _validate_input('t', script_type, content)
|
|
if not ok:
|
|
return _err(400, msg, field, 'execute_script: validation failed, not executed')
|
|
run_params = params.get('params') or {}
|
|
result = _execute_content(content, script_type, run_params)
|
|
return _ok(result, 'executed')
|
|
except NotImplementedError as e:
|
|
return _err(501, str(e), 'script_type', 'execute_script: type not supported')
|
|
except Exception as e:
|
|
from traceback import format_exc
|
|
return _err(500, 'execute failed: %s' % str(e), '', format_exc())
|
|
|
|
|
|
async def validate_script_api(request, params_kw):
|
|
try:
|
|
params = params_kw or {}
|
|
content = _clean_str(params.get('content'))
|
|
script_type = _clean_str(params.get('script_type'), '0')
|
|
if not content:
|
|
return _err(400, 'script content must not be empty', 'content', 'validate_script: no content')
|
|
ok, field, msg = _validate_input('t', script_type, content)
|
|
if not ok:
|
|
return _err(400, msg, field, 'validate_script: validation failed')
|
|
return _ok({'valid': True}, 'valid')
|
|
except Exception as e:
|
|
from traceback import format_exc
|
|
return _err(500, 'validate failed: %s' % str(e), '', format_exc())
|
|
|
|
|
|
def load_script_engine():
|
|
env = ServerEnv()
|
|
env.create_script = create_script
|
|
env.update_script = update_script
|
|
env.delete_script = delete_script
|
|
env.get_script = get_script
|
|
env.list_scripts = list_scripts
|
|
env.execute_script = execute_script
|
|
env.validate_script_api = validate_script_api
|
|
env.create_scripts = create_script
|
|
env.update_scripts = update_script
|
|
env.delete_scripts = delete_script
|
|
return env
|