diff --git a/json/build.sh b/json/build.sh new file mode 100755 index 0000000..948b4ba --- /dev/null +++ b/json/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash + +xls2ui -m ../models -o ../wwwroot appbase *.json diff --git a/json/jsonhttpapi.json b/json/jsonhttpapi.json new file mode 100644 index 0000000..3aa4400 --- /dev/null +++ b/json/jsonhttpapi.json @@ -0,0 +1,40 @@ +{ + "tblname":"jsonhttpapi", + "params":{ + "title":"应用api", + "description":"应用api管理,配置与外部系统的api应用接口,需要api返回json格式数据", + "sortby":"name", + "logined_userorgid":"ownerid", + "toolbar":{ + "tools":[ + { + "name":"test", + "icon":"test.png", + "selected_row": true, + "label":"接口测试" + } + ] + }, + "browserfields":{ + "exclouded":["id", "ownerid"], + "alters":{} + }, + "binds":[ + { + "wid":"self", + "event":"row_selected", + "actiontype":"script", + "target":"self", + "script":"console.log('test', params);" + }, + { + "wid":"self", + "event":"test", + "actiontype":"script", + "target":"self", + "script":"console.log('swith event', params);" + } + ], + "editexclouded":["id", "ownerid"] + } +} diff --git a/json/upapp.json b/json/upapp.json new file mode 100644 index 0000000..6df732c --- /dev/null +++ b/json/upapp.json @@ -0,0 +1,13 @@ +{ + "tblname":"upapp", + "params":{ + "title":"上位系统", + "description":"上位系统", + "sortby":"name", + "browserfields":{ + "exclouded":["id"], + "alters":{} + }, + "editexclouded":["id"] + } +} diff --git a/json/upapp1.json b/json/upapp1.json new file mode 100644 index 0000000..a4b9083 --- /dev/null +++ b/json/upapp1.json @@ -0,0 +1,20 @@ +{ + "tblname":"upapp", + "alias":"upapp1", + "params":{ + "title":"上位系统", + "sortby":"name", + "noedit":true, + "browserfields":{ + "exclouded":["id"], + "alters":{} + }, + "subtables":[ + { + "field":"upappid", + "subtable":"upappkey", + "title":"应用密码" + } + ] + } +} diff --git a/json/upappkey.json b/json/upappkey.json new file mode 100644 index 0000000..1397974 --- /dev/null +++ b/json/upappkey.json @@ -0,0 +1,14 @@ +{ + "tblname":"upappkey", + "params":{ + "title":"上位系统密码", + "description":"上位系统密码", + "sortby":"name", + "confidential_fields":["akikey", "userpwd" ], + "browserfields":{ + "exclouded":["id"], + "alters":{} + }, + "editexclouded":["id"] + } +} diff --git a/uapi/__init__.py b/uapi/__init__.py new file mode 100644 index 0000000..58f3ace --- /dev/null +++ b/uapi/__init__.py @@ -0,0 +1 @@ +from .version import __version__ diff --git a/uapi/appapi.py b/uapi/appapi.py new file mode 100644 index 0000000..e764ea3 --- /dev/null +++ b/uapi/appapi.py @@ -0,0 +1,131 @@ +from functools import partial +from sqlor.dbpools import DBPools +from appPublic.httpclient import JsonHttpAPI +from ahserver.globalEnv import password_decode +from aiohttp import web + +class AppAPI(JsonHttpAPI): + def __init__(self, appid, env={}): + self.appid = appid + super().__init__(env=env) + self.auth_api = None + self.auth_ret = None + + async def get_authapi(self, sor): + sql = "select * from jsonhttpapi where name = 'auth' and appid=${appid}$" + recs = await sor.sqlExe(sql, {'appid': self.appid}) + if len(recs): + return recs[0] + return None + + async def get_apiinfo(self, orgids, apiname): + db = DBPools() + dbname = get_serverenv('get_module_dbname')('uapi') + async with db.sqlorContext(dbname) as sor: + sql = """select c.baseurl, +c.name as appname, +b.*, +a.apikey, +a.secretkey +from upappkey a, jsonhttpapi b, upapp c +where + a.upappid=b.appid + and a.upappid = c.id + and b.appid = ${appid}$ + and b.name = ${apiname}$ + and a.ownerid = ${orgid}$ +""" + for orgid in orgids: + ns = { + "orgid": orgid, + "apiname": appname, + "appid": self.appid + } + recs = await sor.sqlExe(sql, ns) + if len(recs) > 0: + rec = recs[0] + rec.apikey = password_decode(rec.apikey) + if rec.secretkey: + rec.secretkey = password_decode(rec.secretkey) + if rec.need_auth and self.auth_api is None: + self.auth_api = await self.get_authapi(sor) + if rec.need_auth and self.auth_api is None: + raise Exception(f'{rec.appname} app has not auth api but need') + rec.auth_api = self.auth_api + rec.apikey_orgid = orgid + return recs[0] + return None + + def request(self, apiname, ns): + orgs = ns.get('orgs') + api = await self.get_apiinfo(orgs, apiname) + if api is None: + raise Exception(f'{self.appid} app has not {apiname} api') + ns1 = self.env.copy() + ns1['apikey'] = api.apikey + ns1['secretkey'] = api.secretkey + ns1.update(ns) + if api.need_auth: + if self.auth_ret is None: + auth_url = api.baseurl + self.auth_api.path + self.auth_ret = await self.call(auth_url, + method=self.auth_api.httpmethod, + ns=ns1, + headerstmpl=self.auth_api.headers, + paramstmpl=self.auth_api.params, + datatmpl=self.auth_api.data, + resptmpl=self.auth_api.response) + if self.auth_ret is None: + raise Exception(f'{self.appid} app auth error') + ns1.update(self.auth_ret) + stream_func = None + if api.stream: + await self.stream_begin() + stream_func = partial(self.stream_func, api, ns1) + url = api.baseurl + api.path + ret = await self.call(url, method=api.httpmethod, ns=ns1, + stream_func = stream_func, + headerstmpl=api.headers, + paramstmpl=api.params, + datatmpl=api.data, + resptmpl=api.response) + if api.stream: + return await self.stream_end() + return ret + + async def stream_begin(self): + pass + + async def stream_end(self): + return None + + async def stream_func(self, api, ns, chunk): + if api.chunk_match: + chunk = chunk[len(api.chunk_match):] + d = chunk + if api.streamresponse: + d = json.loads(chunk) + ns1 = ns.copy() + ns1.update(d) + d = self.te.renders(api.streamresponse, ns1) + return d + + +class AiohttpAppAPI(AppAPI): + async def request(self, request, apiname, ns): + self.request = request + return await super().request(apiname, ns) + + async def stream_begin(self): + self.resp = web.StreamResponse() + await self.resp.prepare(request) + + async def stream_end(self): + return self.resp + + async def stream_func(self, api, ns, chunk): + d = super().stream_func(api, ns, chuck) + b = d.encode('utf-8') + await self.resp.write(bin) + await self.resp.drain() + diff --git a/uapi/init.py b/uapi/init.py new file mode 100644 index 0000000..9ac8346 --- /dev/null +++ b/uapi/init.py @@ -0,0 +1,8 @@ +from ahserver.serverenv import get_serverenv +from .appapi import AppAPI, AiohttpAppAPI + +def load_uapi(): + g = ServerEnv() + g.AiohttpAppAPI = AiohttpAppAPI + g.AppAPI = AppAPI + diff --git a/uapi/version.py b/uapi/version.py new file mode 100644 index 0000000..b8023d8 --- /dev/null +++ b/uapi/version.py @@ -0,0 +1 @@ +__version__ = '0.0.1'