Skip to content
Merged

Sync #28

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions demo/apps/apijson_demo/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@
el: '#app',
delimiters: ['{', '}'],
data: {
request_get : {{=request_get_json}},
request_head : {{=request_head_json}},
request_post : {{=request_post_json}},
request_put : {{=request_put_json}},
request_delete : {{=request_delete_json}},
request_get : {{<<request_get_json}},
request_head : {{<<request_head_json}},
request_post : {{<<request_post_json}},
request_put : {{<<request_put_json}},
request_delete : {{<<request_delete_json}},
request_data : "",
select_current : "",
can_post : true,
Expand Down
36 changes: 35 additions & 1 deletion demo/apps/apijson_demo/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,41 @@ def index():
"username$":"%user%"
}
}
}''',
},
{
"label":"Array query: simple @expr",
"value":'''{
"[]":{
"@count":4,
"@page":0,
"user":{
"@column":"id,username,nickname,email",
"@order":"id-",
"@role":"ADMIN",
"@expr":["username$","|","nickname$"],
"username$":"%b%",
"nickname$":"%c%"
}
}
}''',
},
{
"label":"Array query: complex @expr",
"value":'''{
"[]":{
"@count":4,
"@page":0,
"user":{
"@column":"id,username,nickname,email",
"@order":"id-",
"@role":"ADMIN",
"@expr":[["username$","&","email$"],"&",["!","nickname$"]],,
"username$":"%b%",
"nickname$":"%Admin%",
"email$":"%local%"
}
}
}''',
},
]
Expand Down Expand Up @@ -141,7 +176,6 @@ def index():
}''',
},
]

return {
"user_info":user_info,
"request_get_json":dumps(request_get),
Expand Down
151 changes: 100 additions & 51 deletions uliweb_apijson/apijson/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#coding=utf-8
from uliweb import expose, functions, models
from uliweb import expose, functions, models, UliwebError
from uliweb.orm import ModelNotFound
from sqlalchemy.sql import and_, or_, not_
from json import loads
import logging
import traceback
Expand Down Expand Up @@ -50,22 +51,22 @@ def get(self):
return json(self.rdict)

def _get_one(self,key):
modelname = key
model_name = key
params = self.request_data[key]
params_role = params.get("@role")

try:
model = getattr(models,modelname)
model_setting = settings.APIJSON_MODELS.get(modelname,{})
model = getattr(models,model_name)
model_setting = settings.APIJSON_MODELS.get(model_name,{})
except ModelNotFound as e:
log.error("try to find model '%s' but not found: '%s'"%(modelname,e))
return json({"code":400,"msg":"model '%s' not found"%(modelname)})
log.error("try to find model '%s' but not found: '%s'"%(model_name,e))
return json({"code":400,"msg":"model '%s' not found"%(model_name)})
model_column_set = None
q = model.all()

GET = model_setting.get("GET")
if not GET:
return json({"code":400,"msg":"'%s' not accessible"%(modelname)})
return json({"code":400,"msg":"'%s' not accessible"%(model_name)})

roles = GET.get("roles")
permission_check_ok = False
Expand All @@ -75,7 +76,7 @@ def _get_one(self,key):
else:
params_role = "UNKNOWN"
if params_role not in roles:
return json({"code":400,"msg":"'%s' not accessible by role '%s'"%(modelname,params_role)})
return json({"code":400,"msg":"'%s' not accessible by role '%s'"%(model_name,params_role)})
if params_role == "UNKNOWN":
permission_check_ok = True
elif functions.has_role(request.user,params_role):
Expand All @@ -88,7 +89,7 @@ def _get_one(self,key):
if params_role=="OWNER":
owner_filtered,q = self._filter_owner(model,model_setting,q)
if not owner_filtered:
return json({"code":400,"msg":"'%s' cannot filter with owner"%(modelname)})
return json({"code":400,"msg":"'%s' cannot filter with owner"%(model_name)})

params = self.request_data[key]
if isinstance(params,dict):
Expand All @@ -99,7 +100,7 @@ def _get_one(self,key):
elif hasattr(model,n):
q = q.filter(getattr(model.c,n)==params[n])
else:
return json({"code":400,"msg":"'%s' have no attribute '%s'"%(modelname,n)})
return json({"code":400,"msg":"'%s' have no attribute '%s'"%(model_name,n)})
o = q.one()
if o:
o = o.to_dict()
Expand All @@ -116,7 +117,7 @@ def _get_one(self,key):

def _get_array(self,key):
params = self.request_data[key]
modelname = None
model_name = None
model_param = None
model_column_set = None

Expand Down Expand Up @@ -147,14 +148,14 @@ def _get_array(self,key):
for n in params:
if n[0]!="@":
# TODO: support join in the future, now only support 1 model
modelname = n
model_name = n
break

if not modelname:
if not model_name:
return json({"code":400,"msg":"no model found in array query"})

#model settings
model_setting = settings.APIJSON_MODELS.get(modelname,{})
model_setting = settings.APIJSON_MODELS.get(model_name,{})
secret_fields = model_setting.get("secret_fields")

#model params
Expand All @@ -164,18 +165,18 @@ def _get_array(self,key):
if model_column:
model_column_set = set(model_column.split(","))
try:
model = getattr(models,modelname)
model = getattr(models,model_name)
except ModelNotFound as e:
log.error("try to find model '%s' but not found: '%s'"%(modelname,e))
return json({"code":400,"msg":"model '%s' not found"%(modelname)})
log.error("try to find model '%s' but not found: '%s'"%(model_name,e))
return json({"code":400,"msg":"model '%s' not found"%(model_name)})
#order
model_order = model_param.get("@order")

q = model.all()

GET = model_setting.get("GET")
if not GET:
return json({"code":400,"msg":"'%s' not accessible by apijson"%(modelname)})
return json({"code":400,"msg":"'%s' not accessible by apijson"%(model_name)})

roles = GET.get("roles")
params_role = model_param.get("@role")
Expand All @@ -186,7 +187,7 @@ def _get_array(self,key):
else:
params_role = "UNKNOWN"
if params_role not in roles:
return json({"code":400,"msg":"'%s' not accessible by role '%s'"%(modelname,params_role)})
return json({"code":400,"msg":"'%s' not accessible by role '%s'"%(model_name,params_role)})
if params_role == "UNKNOWN":
permission_check_ok = True
elif functions.has_role(request.user,params_role):
Expand All @@ -200,21 +201,18 @@ def _get_array(self,key):
if params_role == "OWNER":
owner_filtered,q = self._filter_owner(model,model_setting,q)
if not owner_filtered:
return json({"code":400,"msg":"'%s' cannot filter with owner"%(modelname)})
return json({"code":400,"msg":"'%s' cannot filter with owner"%(model_name)})

for n in model_param:
if n[0]!="@":
if n[-1]=="$":
name = n[:-1]
if hasattr(model,name):
q = q.filter(getattr(model.c,name).like(model_param[n]))
elif n[-1]=="}" and n[-2]=="{":
name = n[:-2]
if hasattr(model,name):
# TODO
pass
elif hasattr(model,n):
q = q.filter(getattr(model.c,n)==model_param[n])
model_expr = model_param.get("@expr")

if model_expr:
c = self._expr(model,model_param,model_expr)
q = q.filter(c)
else:
for n in model_param:
if n[0]!="@":
c = self._get_filter_condition(model,model_param,n)
q = q.filter(c)

if query_type in [1,2]:
self.vars["/%s/total"%(key)] = q.count()
Expand Down Expand Up @@ -264,6 +262,60 @@ def _filter_owner(self,model,model_setting,q):
owner_filtered = True
return owner_filtered,q

def _expr(self,model,model_param,model_expr):
if not isinstance(model_expr,list):
raise UliwebError("only accept array in @expr: '%s'"%(model_expr))
num = len(model_expr)
if (num<2 or num>3):
raise UliwebError("only accept 2 or 3 items in @expr: '%s'"%(model_expr))
op = model_expr[-2]
if op=='&':
if num!=3:
raise UliwebError("'&'(and) expression need 3 items: '%s'"%(model_expr))
c1 = self._get_filter_condition(model,model_param,model_expr[0],expr=True)
c2 = self._get_filter_condition(model,model_param,model_expr[2],expr=True)
return and_(c1,c2)
elif op=='|':
if num!=3:
raise UliwebError("'|'(or) expression need 3 items: '%s'"%(model_expr))
c1 = self._get_filter_condition(model,model_param,model_expr[0],expr=True)
c2 = self._get_filter_condition(model,model_param,model_expr[2],expr=True)
return or_(c1,c2)
elif op=='!':
if num!=2:
raise UliwebError("'!'(not) expression need 2 items: '%s'"%(model_expr))
return not_(self._get_filter_condition(model,model_param,model_expr[1],expr=True))
else:
raise UliwebError("unknown operator: '%s'"%(op))

def _get_filter_condition(self,model,model_param,item,expr=False):
if isinstance(item,list):
if expr:
return self._expr(model,model_param,model_expr=item)
else:
raise UliwebError("item can be array only in @expr: '%s'"%(item))
if not isinstance(item,str):
raise UliwebError("item should be array or string: '%s'"%(item))
n = item
if n[0]=="@":
raise UliwebError("param key should not begin with @: '%s'"%(n))
if n[-1]=="$":
name = n[:-1]
if hasattr(model,name):
return getattr(model.c,name).like(model_param[n])
else:
raise UliwebError("'%s' does not have '%s'"%(model_name,name))
elif n[-1]=="}" and n[-2]=="{":
name = n[:-2]
if hasattr(model,name):
# TODO
pass
raise UliwebError("still not support '%s'"%(name))
elif hasattr(model,n):
return getattr(model.c,n)==model_param[n]
else:
raise UliwebError("not support item: '%s'"%(item))

def head(self):
try:
for key in self.request_data:
Expand All @@ -278,22 +330,22 @@ def head(self):
return json(self.rdict)

def _head(self,key):
modelname = key
model_name = key
params = self.request_data[key]
params_role = params.get("@role")

try:
model = getattr(models,modelname)
model_setting = settings.APIJSON_MODELS.get(modelname,{})
model = getattr(models,model_name)
model_setting = settings.APIJSON_MODELS.get(model_name,{})
except ModelNotFound as e:
log.error("try to find model '%s' but not found: '%s'"%(modelname,e))
return json({"code":400,"msg":"model '%s' not found"%(modelname)})
log.error("try to find model '%s' but not found: '%s'"%(model_name,e))
return json({"code":400,"msg":"model '%s' not found"%(model_name)})

q = model.all()

HEAD = model_setting.get("HEAD")
if not HEAD:
return json({"code":400,"msg":"'%s' not accessible"%(modelname)})
return json({"code":400,"msg":"'%s' not accessible"%(model_name)})

roles = HEAD.get("roles")
permission_check_ok = False
Expand All @@ -303,7 +355,7 @@ def _head(self,key):
else:
params_role = "UNKNOWN"
if params_role not in roles:
return json({"code":400,"msg":"'%s' not accessible by role '%s'"%(modelname,params_role)})
return json({"code":400,"msg":"'%s' not accessible by role '%s'"%(model_name,params_role)})
if params_role == "UNKNOWN":
permission_check_ok = True
elif functions.has_role(request.user,params_role):
Expand All @@ -316,14 +368,14 @@ def _head(self,key):
if params_role=="OWNER":
owner_filtered,q = self._filter_owner(model,model_setting,q)
if not owner_filtered:
return json({"code":400,"msg":"'%s' cannot filter with owner"%(modelname)})
return json({"code":400,"msg":"'%s' cannot filter with owner"%(model_name)})
for n in params:
if n[0]=="@":
pass
else:
param = params[n]
if not hasattr(model.c,n):
return json({"code":400,"msg":"'%s' don't have field '%s'"%(modelname,n)})
return json({"code":400,"msg":"'%s' don't have field '%s'"%(model_name,n)})
q = model.filter(getattr(model.c,n)==param)
rdict = {
"code":200,
Expand Down Expand Up @@ -370,10 +422,9 @@ def _post_one(self,key,tag):
log.error("try to find model '%s' but not found: '%s'"%(model_name,e))
return json({"code":400,"msg":"model '%s' not found"%(model_name)})

request_tag_config = request_tag.get(model_name,{})
if not request_tag_config:
if not request_tag:
return json({"code":400,"msg":"tag '%s' not found"%(tag)})
tag_POST = request_tag_config.get("POST",{})
tag_POST = request_tag.get("POST",{})
if not tag_POST:
return json({"code":400,"msg":"tag '%s' not support apijson_post"%(tag)})
ADD = tag_POST.get("ADD")
Expand Down Expand Up @@ -482,10 +533,9 @@ def _put_one(self,key,tag):
log.error("try to find model '%s' but not found: '%s'"%(model_name,e))
return json({"code":400,"msg":"model '%s' not found"%(model_name)})

request_tag_config = request_tag.get(model_name,{})
if not request_tag_config:
if not request_tag:
return json({"code":400,"msg":"tag '%s' not found"%(tag)})
tag_PUT = request_tag_config.get("PUT",{})
tag_PUT = request_tag.get("PUT",{})
ADD = tag_PUT.get("ADD")
if ADD:
ADD_role = ADD.get("@role")
Expand Down Expand Up @@ -604,10 +654,9 @@ def _delete_one(self,key,tag):
log.error("try to find model '%s' but not found: '%s'"%(model_name,e))
return json({"code":400,"msg":"model '%s' not found"%(model_name)})

request_tag_config = request_tag.get(model_name,{})
if not request_tag_config:
if not request_tag:
return json({"code":400,"msg":"tag '%s' not found"%(tag)})
tag_DELETE = request_tag_config.get("DELETE",{})
tag_DELETE = request_tag.get("DELETE",{})
ADD = tag_DELETE.get("ADD")
if ADD:
ADD_role = ADD.get("@role")
Expand Down