This commit is contained in:
yumoqing 2025-01-03 16:24:32 +08:00
parent 3a2efc25f1
commit 0c16deab08
12 changed files with 533 additions and 3 deletions

View File

@ -6,12 +6,14 @@ from appPublic.registerfunction import RegisterFunction
from appPublic.rc4 import password, unpassword from appPublic.rc4 import password, unpassword
from appPublic.jsonConfig import getConfig from appPublic.jsonConfig import getConfig
from appPublic.log import debug, exception 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.auth_api import AuthAPI, user_login
from ahserver.serverenv import ServerEnv from ahserver.serverenv import ServerEnv, get_serverenv, set_serverenv
import jwt import jwt
ownerid = None
defualt_password_key = "!@#$%^&*(*&^%$QWERTYUIqwertyui234567" defualt_password_key = "!@#$%^&*(*&^%$QWERTYUIqwertyui234567"
defualt_secret_key="test1234!@#$2222354" defualt_secret_key="test1234!@#$2222354"
def generate_token(ak): def generate_token(ak):
@ -53,6 +55,17 @@ async def get_user_roles(userid):
roles.append(r.name) roles.append(r.name)
return roles 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): def mypassword(passwd):
config = getConfig() config = getConfig()
key = config.password_key or default_password_key key = config.password_key or default_password_key
@ -63,6 +76,38 @@ def myunpassword(passwd):
key = config.password_key or default_password_key key = config.password_key or default_password_key
return unpassword(passwd) 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(): def load_rbac():
AuthAPI.checkUserPermission = objcheckperm AuthAPI.checkUserPermission = objcheckperm
env = ServerEnv() env = ServerEnv()
@ -70,6 +115,8 @@ def load_rbac():
env.unpassword = myunpassword env.unpassword = myunpassword
env.get_user_roles = get_user_roles env.get_user_roles = get_user_roles
env.check_user_password = checkUserPassword env.check_user_password = checkUserPassword
env.register_user = register_user
env.get_owner_orgid = get_owner_orgid
async def get_dbname(): async def get_dbname():
rf = RegisterFunction() rf = RegisterFunction()
@ -98,7 +145,7 @@ async def getAuthenticationUserid(sor, request):
auther = BasicAuth('x') auther = BasicAuth('x')
m = auther.decode(auth) m = auther.decode(auth)
username = m.login username = m.login
password = password(m.password) password = mypassword(m.password)
sql = "select * from users where username=${username}$ and password=${password}$" sql = "select * from users where username=${username}$ and password=${password}$"
recs = await sor.sqlExe(sql, {'username':username,'password':password}) recs = await sor.sqlExe(sql, {'username':username,'password':password})
if len(recs) < 1: if len(recs) < 1:

View File

@ -50,8 +50,12 @@ av_folders = [
'/bricks', '/bricks',
'/imgs', '/imgs',
'/login.ui', '/login.ui',
'/gen_code.dspy',
'/code_login.dspy',
'/up_login.dspy', '/up_login.dspy',
'/wechat_login.ui',
'/public', '/public',
'/debug/index.dspy',
'/rbac/userpassword_login.ui', '/rbac/userpassword_login.ui',
'/rbac/userpassword_login.dspy', '/rbac/userpassword_login.dspy',
'/tmp' '/tmp'

23
www/user/logout.dspy Normal file
View File

@ -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')
}
}
]
}

View File

@ -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')}}"
}
}
]
}
]
}

View File

@ -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')

75
www/user/user.ui Normal file
View File

@ -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 %}

45
www/user/user_menu.ui Normal file
View File

@ -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')}}"
}
]
}
}

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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":[]
}

View File

@ -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
}
}

View File

@ -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"
}
}