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.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:

View File

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

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