diff --git a/rbac/check_perm.py b/rbac/check_perm.py index 9b6c6c7..a915760 100644 --- a/rbac/check_perm.py +++ b/rbac/check_perm.py @@ -6,12 +6,14 @@ from appPublic.registerfunction import RegisterFunction from appPublic.rc4 import password, unpassword from appPublic.jsonConfig import getConfig from appPublic.log import debug, exception +from appPublic.dictObject import DictObject +from appPublic.uniqueID import getID from ahserver.auth_api import AuthAPI, user_login -from ahserver.serverenv import ServerEnv +from ahserver.serverenv import ServerEnv, get_serverenv, set_serverenv import jwt +ownerid = None defualt_password_key = "!@#$%^&*(*&^%$QWERTYUIqwertyui234567" - defualt_secret_key="test1234!@#$2222354" def generate_token(ak): @@ -53,6 +55,17 @@ async def get_user_roles(userid): roles.append(r.name) return roles +async def get_owner_orgid(sor): + global ownerid + if ownerid: + return ownerid + + sql = "select * from orgtypes where orgtypeid = 'owner'" + recs = await sor.sqlExe(sql, {}) + if len(recs) > 0: + ownerid = recs[0].orgid + return ownerid + def mypassword(passwd): config = getConfig() key = config.password_key or default_password_key @@ -63,6 +76,38 @@ def myunpassword(passwd): key = config.password_key or default_password_key return unpassword(passwd) +async def create_org(sor, ns): + await sor.C('organization', ns) + otns = { + 'id':getID(), + 'orgid':ns.id, + 'orgtypeid':'customer' + } + await sor.C('orgtypes', otns) + +async def create_user(sor, ns): + await sor.C('users', ns) + sql = "select * from role where orgtypeid = 'customer' and name in ('admin', 'customer')" + recs = await sor.sqlExe(sql, {}) + for r in recs: + await sor.C('userrole', { + 'id':getID(), + 'userid':ns.id, + 'roleid':r.id + }) + +async def register_user(sor, ns): + if ns.password != ns.cfm_password: + debug('password not match') + return False + id = getID() + ns.id = id + ns.orgid = id + ns1 = DictObject(id=id, orgname=ns.username) + await create_org(sor, ns1) + await create_user(sor, ns) + return id + def load_rbac(): AuthAPI.checkUserPermission = objcheckperm env = ServerEnv() @@ -70,6 +115,8 @@ def load_rbac(): env.unpassword = myunpassword env.get_user_roles = get_user_roles env.check_user_password = checkUserPassword + env.register_user = register_user + env.get_owner_orgid = get_owner_orgid async def get_dbname(): rf = RegisterFunction() @@ -98,7 +145,7 @@ async def getAuthenticationUserid(sor, request): auther = BasicAuth('x') m = auther.decode(auth) username = m.login - password = password(m.password) + password = mypassword(m.password) sql = "select * from users where username=${username}$ and password=${password}$" recs = await sor.sqlExe(sql, {'username':username,'password':password}) if len(recs) < 1: diff --git a/script/init.py b/script/init.py index 69fe7d7..17c2340 100644 --- a/script/init.py +++ b/script/init.py @@ -50,8 +50,12 @@ av_folders = [ '/bricks', '/imgs', '/login.ui', + '/gen_code.dspy', + '/code_login.dspy', '/up_login.dspy', + '/wechat_login.ui', '/public', + '/debug/index.dspy', '/rbac/userpassword_login.ui', '/rbac/userpassword_login.dspy', '/tmp' diff --git a/www/user/logout.dspy b/www/user/logout.dspy new file mode 100644 index 0000000..baf169d --- /dev/null +++ b/www/user/logout.dspy @@ -0,0 +1,23 @@ +await forget_user() +return { + "widgettype":"Message", + "options":{ + "title":"Message", + "message":"logout success", + "auto_open":true, + "anthor":"cc", + "timeout":3 + }, + "binds":[ + { + "wid":"self", + "event":"dismissed", + "actiontype":"urlwidget", + "target":"window", + "options":{ + "url":entire_url('/index.ui') + } + } + ] +} + diff --git a/www/user/reset_password/index.ui b/www/user/reset_password/index.ui new file mode 100644 index 0000000..8cec34a --- /dev/null +++ b/www/user/reset_password/index.ui @@ -0,0 +1,49 @@ +{ + "widgettype":"PopupWindow", + "options":{ + "cwidth":22, + "height":"75%", + "archor":"cc", + "auto_open":true + }, + "subwidgets":[ + { + "widgettype":"Form", + "options":{ + "title":"Reset Password", + "description":"reset yourself password", + "fields":[ + { + "name": "password", + "type": "str", + "length": 255, + "uitype": "password", + "datatype": "str", + "required":true, + "label": "\u5bc6\u7801" + }, + { + "name": "cfm_password", + "type": "str", + "length": 255, + "uitype": "password", + "datatype": "str", + "required":true, + "label": "\u5bc6\u7801" + } + ] + }, + "binds":[ + { + "wid":"self", + "event":"submit", + "actiontype":"urlwidget", + "target":"self", + "options":{ + "url":"{{entire_url('reset_password.dspy')}}" + } + } + ] + } + ] +} diff --git a/www/user/reset_password/reset_password.dspy b/www/user/reset_password/reset_password.dspy new file mode 100644 index 0000000..1ce256e --- /dev/null +++ b/www/user/reset_password/reset_password.dspy @@ -0,0 +1,16 @@ +if params_kw.password != params_kw.cfm_password: + return UiError(title='Error', message='Password not match') + +userid = await get_user() +if userid is None: + return UiError(title='Error', message='You need login first') + +ns = { + 'id':userid, + 'password':params_kw.password +} +db = DBPools() +async with db.sqlorContext('sage') as sor: + await sor.U('users', ns) + return UiMessage(title='Success', message='Password reset success') +return UiError(title='Error', message='Reset password failed') diff --git a/www/user/user.ui b/www/user/user.ui new file mode 100644 index 0000000..62902d2 --- /dev/null +++ b/www/user/user.ui @@ -0,0 +1,75 @@ +{% if get_user() %} +{ + "widgettype":"HBox", + "options":{ + "css":"clickable", + "popup":{ + "options":{ + "auto_dismiss":true + }, + "popup_desc":{ + "widgettype":"urlwidget", + "options":{ + "url":"{{entire_url('user_menu.ui')}}" + } + }, + "popup_event":"click" + } + }, + "subwidgets":[ + { + "widgettype":"Icon", + "options":{ + "url":"{{entire_url('/imgs/people.png')}}", + "rate":1.5 + } + }, + { + "widgettype":"Text", + "options":{ + "wrap":false, + "text":"{{get_username()}}" + } + } + ] +} +{% else %} +{ + "widgettype":"IconBar", + "options":{ + "css":"filler", + "tools":[ + { + "name":"login", + "tip":"user login", + "icon":"{{entire_url('/imgs/login.png')}}" + }, + { + "name":"register", + "tip":"user register", + "icon":"{{entire_url('/imgs/register.png')}}" + } + ] + }, + "binds":[ + { + "wid":"self", + "event":"login", + "actiontype":"urlwidget", + "target":"self", + "options":{ + "url":"{{entire_url('login.ui')}}" + } + }, + { + "wid":"self", + "event":"register", + "actiontype":"urlwidget", + "target":"self", + "options":{ + "url":"{{entire_url('register.ui')}}" + } + } + ] +} +{% endif %} diff --git a/www/user/user_menu.ui b/www/user/user_menu.ui new file mode 100644 index 0000000..ec6706f --- /dev/null +++ b/www/user/user_menu.ui @@ -0,0 +1,45 @@ +{ + "widgettype":"Menu", + "options":{ + "target":"page_center", + "items":[ +{% if 'customer' in get_user_roles(get_user()) %} + { + "name":"recharge", + "label":"充值", + "url":"{{entire_url('/accounting/recharge.ui')}}" + }, + { + "name":"myacc", + "label":"我的账户", + "url":"{{entire_url('myaccout')}}" + }, + { + "name":"mybill", + "label":"我的账单", + "url":"{{entire_url('mybill')}}" + }, + { + "name":"myorder", + "label":"我的订单", + "url":"{{entire_url('myorder')}}" + }, + { + "name":"myresource", + "label":"我的资源", + "url":"{{entire_url('myresource')}}" + }, +{% endif %} + { + "name":"resetpwd", + "label":"重置密码", + "url":"{{entire_url('reset_password')}}" + }, + { + "name":"logout", + "label":"签退", + "url":"{{entire_url('logout.dspy')}}" + } + ] + } +} diff --git a/www/user/userapikey/add_userapikey.dspy b/www/user/userapikey/add_userapikey.dspy new file mode 100644 index 0000000..143f5a2 --- /dev/null +++ b/www/user/userapikey/add_userapikey.dspy @@ -0,0 +1,25 @@ + +ns = params_kw.copy() +id = params_kw.id +if not id or len(id) > 32: + id = uuid() +ns['id'] = id +db = DBPools() +async with db.sqlorContext('sage') as sor: + r = await sor.C('userapikey', ns.copy()) + return { + "widgettype":"Message", + "options":{ + "user_data":ns, + "title":"Add Success", + "message":"ok" + } + } + +return { + "widgettype":"Error", + "options":{ + "title":"Add Error", + "message":"failed" + } +} \ No newline at end of file diff --git a/www/user/userapikey/delete_userapikey.dspy b/www/user/userapikey/delete_userapikey.dspy new file mode 100644 index 0000000..ec1039b --- /dev/null +++ b/www/user/userapikey/delete_userapikey.dspy @@ -0,0 +1,24 @@ + +ns = { + 'id':params_kw['id'], +} +db = DBPools() +async with db.sqlorContext('sage') as sor: + r = await sor.D('userapikey', ns) + print('delete success'); + return { + "widgettype":"Message", + "options":{ + "title":"Delete Success", + "message":"ok" + } + } + +print('Delete failed'); +return { + "widgettype":"Error", + "options":{ + "title":"Delete Error", + "message":"failed" + } +} \ No newline at end of file diff --git a/www/user/userapikey/get_userapikey.dspy b/www/user/userapikey/get_userapikey.dspy new file mode 100644 index 0000000..085fa59 --- /dev/null +++ b/www/user/userapikey/get_userapikey.dspy @@ -0,0 +1,74 @@ + +ns = params_kw.copy() +print(f'get_userapikey.dspy:{ns=}') +if not ns.get('page'): + ns['page'] = 1 +if not ns.get('sort'): + + ns['sort'] = 'id' + +filterjson = params_kw.get('data_filter') +userid = await get_user() +ns['userid'] = userid +if not filterjson: + fields = [ f['name'] for f in [ + { + "name": "id", + "title": "id", + "type": "str", + "length": 32 + }, + { + "name": "providerid", + "title": "\u4f9b\u5e94\u5546id", + "type": "str", + "length": 200 + }, + { + "name": "customerid", + "title": "\u7528\u6237id", + "type": "str", + "length": 32, + "default": "0" + }, + { + "name": "apikey", + "title": "api\u5bc6\u94a5", + "type": "str", + "length": 4000, + "default": "0" + }, + { + "name": "secretkey", + "title": "\u9644\u5c5e\u5bc6\u94a5", + "type": "str", + "length": 4000 + }, + { + "name": "rfname", + "title": "\u51fd\u6570\u540d", + "type": "str", + "length": 400 + } +] ] + filterjson = default_filterjson(fields, ns) +sql = '''select a.*, b.providerid_text, c.customerid_text +from (select y.* from users x, userapikey y where x.id=${userid}$ and x.orgid = y.customerid) a left join (select id as providerid, + orgname as providerid_text from organization where 1 = 1) b on a.providerid = b.providerid left join (select id as customerid, + orgname as customerid_text from organization where 1 = 1) c on a.customerid = c.customerid''' + +if filterjson: + dbf = DBFilter(filterjson) + conds = dbf.gen(ns) + if conds: + ns.update(dbf.consts) + sql += ' and ' + conds +info(f'{ns=},{sql=}') +db = DBPools() +async with db.sqlorContext('sage') as sor: + r = await sor.sqlPaging(sql, ns) + return r +return { + "total":0, + "rows":[] +} diff --git a/www/user/userapikey/index.ui b/www/user/userapikey/index.ui new file mode 100644 index 0000000..fa784c8 --- /dev/null +++ b/www/user/userapikey/index.ui @@ -0,0 +1,126 @@ + +{ + "widgettype":"Tabular", + "options":{ + + + "editable":{ + "new_data_url":"{{entire_url('add_userapikey.dspy')}}", + "delete_data_url":"{{entire_url('delete_userapikey.dspy')}}", + "update_data_url":"{{entire_url('update_userapikey.dspy')}}" + }, + + "data_url":"{{entire_url('./get_userapikey.dspy')}}", + "data_method":"GET", + "data_params":{{json.dumps(params_kw, indent=4)}}, + "row_options":{ + + + + + "browserfields":{ + "excloud": [], + "cwidth": {} +}, + + + "editexclouded":[ + "id" +], + + "fields":[ + { + "name": "id", + "title": "id", + "type": "str", + "length": 32, + "cwidth": 18, + "uitype": "str", + "datatype": "str", + "label": "id" + }, + { + "name": "providerid", + "title": "\u4f9b\u5e94\u5546id", + "type": "str", + "length": 200, + "label": "\u4f9b\u5e94\u5546id", + "cwidth":16, + "uitype": "code", + "cwidth":18, + "valueField": "providerid", + "textField": "providerid_text", + "params": { + "dbname": "sage", + "table": "organization", + "tblvalue": "id", + "tbltext": "orgname", + "valueField": "providerid", + "textField": "providerid_text" + }, + "dataurl": "\/get_code.dspy" + }, + { + "name": "customerid", + "title": "\u7528\u6237id", + "type": "str", + "length": 32, + "cwidth":18, + "default": "0", + "label": "\u7528\u6237id", + "cwidth":16, + "uitype": "code", + "valueField": "customerid", + "textField": "customerid_text", + "params": { + "dbname": "sage", + "table": "organization", + "tblvalue": "id", + "tbltext": "orgname", + "valueField": "customerid", + "textField": "customerid_text" + }, + "dataurl": "\/get_code.dspy" + }, + { + "name": "apikey", + "title": "api\u5bc6\u94a5", + "type": "str", + "length": 4000, + "default": "0", + "cwidth": 18, + "uitype": "text", + "rows": 4, + "datatype": "str", + "label": "api\u5bc6\u94a5" + }, + { + "name": "secretkey", + "title": "\u9644\u5c5e\u5bc6\u94a5", + "type": "str", + "length": 4000, + "cwidth": 18, + "uitype": "text", + "rows": 4, + "datatype": "str", + "label": "\u9644\u5c5e\u5bc6\u94a5" + }, + { + "name": "rfname", + "title": "\u51fd\u6570\u540d", + "type": "str", + "length": 400, + "cwidth": 18, + "uitype": "text", + "rows": 4, + "datatype": "str", + "label": "\u51fd\u6570\u540d" + } +] + }, + + "page_rows":160, + "cache_limit":5 + } + +} diff --git a/www/user/userapikey/update_userapikey.dspy b/www/user/userapikey/update_userapikey.dspy new file mode 100644 index 0000000..b31458e --- /dev/null +++ b/www/user/userapikey/update_userapikey.dspy @@ -0,0 +1,22 @@ + +ns = params_kw.copy() +db = DBPools() +async with db.sqlorContext('sage') as sor: + r = await sor.U('userapikey', ns) + print('update success'); + return { + "widgettype":"Message", + "options":{ + "title":"Update Success", + "message":"ok" + } + } + +print('update failed'); +return { + "widgettype":"Error", + "options":{ + "title":"Update Error", + "message":"failed" + } +} \ No newline at end of file