1
1
#coding=utf-8
2
- from uliweb import expose ,functions ,models
2
+ from uliweb import expose ,functions ,models , UliwebError
3
3
from uliweb .orm import ModelNotFound
4
+ from sqlalchemy .sql import and_ ,or_ ,not_
4
5
from json import loads
5
6
import logging
6
7
import traceback
@@ -50,22 +51,22 @@ def get(self):
50
51
return json (self .rdict )
51
52
52
53
def _get_one (self ,key ):
53
- modelname = key
54
+ model_name = key
54
55
params = self .request_data [key ]
55
56
params_role = params .get ("@role" )
56
57
57
58
try :
58
- model = getattr (models ,modelname )
59
- model_setting = settings .APIJSON_MODELS .get (modelname ,{})
59
+ model = getattr (models ,model_name )
60
+ model_setting = settings .APIJSON_MODELS .get (model_name ,{})
60
61
except ModelNotFound as e :
61
- log .error ("try to find model '%s' but not found: '%s'" % (modelname ,e ))
62
- return json ({"code" :400 ,"msg" :"model '%s' not found" % (modelname )})
62
+ log .error ("try to find model '%s' but not found: '%s'" % (model_name ,e ))
63
+ return json ({"code" :400 ,"msg" :"model '%s' not found" % (model_name )})
63
64
model_column_set = None
64
65
q = model .all ()
65
66
66
67
GET = model_setting .get ("GET" )
67
68
if not GET :
68
- return json ({"code" :400 ,"msg" :"'%s' not accessible" % (modelname )})
69
+ return json ({"code" :400 ,"msg" :"'%s' not accessible" % (model_name )})
69
70
70
71
roles = GET .get ("roles" )
71
72
permission_check_ok = False
@@ -75,7 +76,7 @@ def _get_one(self,key):
75
76
else :
76
77
params_role = "UNKNOWN"
77
78
if params_role not in roles :
78
- return json ({"code" :400 ,"msg" :"'%s' not accessible by role '%s'" % (modelname ,params_role )})
79
+ return json ({"code" :400 ,"msg" :"'%s' not accessible by role '%s'" % (model_name ,params_role )})
79
80
if params_role == "UNKNOWN" :
80
81
permission_check_ok = True
81
82
elif functions .has_role (request .user ,params_role ):
@@ -88,7 +89,7 @@ def _get_one(self,key):
88
89
if params_role == "OWNER" :
89
90
owner_filtered ,q = self ._filter_owner (model ,model_setting ,q )
90
91
if not owner_filtered :
91
- return json ({"code" :400 ,"msg" :"'%s' cannot filter with owner" % (modelname )})
92
+ return json ({"code" :400 ,"msg" :"'%s' cannot filter with owner" % (model_name )})
92
93
93
94
params = self .request_data [key ]
94
95
if isinstance (params ,dict ):
@@ -99,7 +100,7 @@ def _get_one(self,key):
99
100
elif hasattr (model ,n ):
100
101
q = q .filter (getattr (model .c ,n )== params [n ])
101
102
else :
102
- return json ({"code" :400 ,"msg" :"'%s' have no attribute '%s'" % (modelname ,n )})
103
+ return json ({"code" :400 ,"msg" :"'%s' have no attribute '%s'" % (model_name ,n )})
103
104
o = q .one ()
104
105
if o :
105
106
o = o .to_dict ()
@@ -116,7 +117,7 @@ def _get_one(self,key):
116
117
117
118
def _get_array (self ,key ):
118
119
params = self .request_data [key ]
119
- modelname = None
120
+ model_name = None
120
121
model_param = None
121
122
model_column_set = None
122
123
@@ -147,14 +148,14 @@ def _get_array(self,key):
147
148
for n in params :
148
149
if n [0 ]!= "@" :
149
150
# TODO: support join in the future, now only support 1 model
150
- modelname = n
151
+ model_name = n
151
152
break
152
153
153
- if not modelname :
154
+ if not model_name :
154
155
return json ({"code" :400 ,"msg" :"no model found in array query" })
155
156
156
157
#model settings
157
- model_setting = settings .APIJSON_MODELS .get (modelname ,{})
158
+ model_setting = settings .APIJSON_MODELS .get (model_name ,{})
158
159
secret_fields = model_setting .get ("secret_fields" )
159
160
160
161
#model params
@@ -164,18 +165,18 @@ def _get_array(self,key):
164
165
if model_column :
165
166
model_column_set = set (model_column .split ("," ))
166
167
try :
167
- model = getattr (models ,modelname )
168
+ model = getattr (models ,model_name )
168
169
except ModelNotFound as e :
169
- log .error ("try to find model '%s' but not found: '%s'" % (modelname ,e ))
170
- return json ({"code" :400 ,"msg" :"model '%s' not found" % (modelname )})
170
+ log .error ("try to find model '%s' but not found: '%s'" % (model_name ,e ))
171
+ return json ({"code" :400 ,"msg" :"model '%s' not found" % (model_name )})
171
172
#order
172
173
model_order = model_param .get ("@order" )
173
174
174
175
q = model .all ()
175
176
176
177
GET = model_setting .get ("GET" )
177
178
if not GET :
178
- return json ({"code" :400 ,"msg" :"'%s' not accessible by apijson" % (modelname )})
179
+ return json ({"code" :400 ,"msg" :"'%s' not accessible by apijson" % (model_name )})
179
180
180
181
roles = GET .get ("roles" )
181
182
params_role = model_param .get ("@role" )
@@ -186,7 +187,7 @@ def _get_array(self,key):
186
187
else :
187
188
params_role = "UNKNOWN"
188
189
if params_role not in roles :
189
- return json ({"code" :400 ,"msg" :"'%s' not accessible by role '%s'" % (modelname ,params_role )})
190
+ return json ({"code" :400 ,"msg" :"'%s' not accessible by role '%s'" % (model_name ,params_role )})
190
191
if params_role == "UNKNOWN" :
191
192
permission_check_ok = True
192
193
elif functions .has_role (request .user ,params_role ):
@@ -200,21 +201,18 @@ def _get_array(self,key):
200
201
if params_role == "OWNER" :
201
202
owner_filtered ,q = self ._filter_owner (model ,model_setting ,q )
202
203
if not owner_filtered :
203
- return json ({"code" :400 ,"msg" :"'%s' cannot filter with owner" % (modelname )})
204
+ return json ({"code" :400 ,"msg" :"'%s' cannot filter with owner" % (model_name )})
204
205
205
- for n in model_param :
206
- if n [0 ]!= "@" :
207
- if n [- 1 ]== "$" :
208
- name = n [:- 1 ]
209
- if hasattr (model ,name ):
210
- q = q .filter (getattr (model .c ,name ).like (model_param [n ]))
211
- elif n [- 1 ]== "}" and n [- 2 ]== "{" :
212
- name = n [:- 2 ]
213
- if hasattr (model ,name ):
214
- # TODO
215
- pass
216
- elif hasattr (model ,n ):
217
- q = q .filter (getattr (model .c ,n )== model_param [n ])
206
+ model_expr = model_param .get ("@expr" )
207
+
208
+ if model_expr :
209
+ c = self ._expr (model ,model_param ,model_expr )
210
+ q = q .filter (c )
211
+ else :
212
+ for n in model_param :
213
+ if n [0 ]!= "@" :
214
+ c = self ._get_filter_condition (model ,model_param ,n )
215
+ q = q .filter (c )
218
216
219
217
if query_type in [1 ,2 ]:
220
218
self .vars ["/%s/total" % (key )]= q .count ()
@@ -264,6 +262,60 @@ def _filter_owner(self,model,model_setting,q):
264
262
owner_filtered = True
265
263
return owner_filtered ,q
266
264
265
+ def _expr (self ,model ,model_param ,model_expr ):
266
+ if not isinstance (model_expr ,list ):
267
+ raise UliwebError ("only accept array in @expr: '%s'" % (model_expr ))
268
+ num = len (model_expr )
269
+ if (num < 2 or num > 3 ):
270
+ raise UliwebError ("only accept 2 or 3 items in @expr: '%s'" % (model_expr ))
271
+ op = model_expr [- 2 ]
272
+ if op == '&' :
273
+ if num != 3 :
274
+ raise UliwebError ("'&'(and) expression need 3 items: '%s'" % (model_expr ))
275
+ c1 = self ._get_filter_condition (model ,model_param ,model_expr [0 ],expr = True )
276
+ c2 = self ._get_filter_condition (model ,model_param ,model_expr [2 ],expr = True )
277
+ return and_ (c1 ,c2 )
278
+ elif op == '|' :
279
+ if num != 3 :
280
+ raise UliwebError ("'|'(or) expression need 3 items: '%s'" % (model_expr ))
281
+ c1 = self ._get_filter_condition (model ,model_param ,model_expr [0 ],expr = True )
282
+ c2 = self ._get_filter_condition (model ,model_param ,model_expr [2 ],expr = True )
283
+ return or_ (c1 ,c2 )
284
+ elif op == '!' :
285
+ if num != 2 :
286
+ raise UliwebError ("'!'(not) expression need 2 items: '%s'" % (model_expr ))
287
+ return not_ (self ._get_filter_condition (model ,model_param ,model_expr [1 ],expr = True ))
288
+ else :
289
+ raise UliwebError ("unknown operator: '%s'" % (op ))
290
+
291
+ def _get_filter_condition (self ,model ,model_param ,item ,expr = False ):
292
+ if isinstance (item ,list ):
293
+ if expr :
294
+ return self ._expr (model ,model_param ,model_expr = item )
295
+ else :
296
+ raise UliwebError ("item can be array only in @expr: '%s'" % (item ))
297
+ if not isinstance (item ,str ):
298
+ raise UliwebError ("item should be array or string: '%s'" % (item ))
299
+ n = item
300
+ if n [0 ]== "@" :
301
+ raise UliwebError ("param key should not begin with @: '%s'" % (n ))
302
+ if n [- 1 ]== "$" :
303
+ name = n [:- 1 ]
304
+ if hasattr (model ,name ):
305
+ return getattr (model .c ,name ).like (model_param [n ])
306
+ else :
307
+ raise UliwebError ("'%s' does not have '%s'" % (model_name ,name ))
308
+ elif n [- 1 ]== "}" and n [- 2 ]== "{" :
309
+ name = n [:- 2 ]
310
+ if hasattr (model ,name ):
311
+ # TODO
312
+ pass
313
+ raise UliwebError ("still not support '%s'" % (name ))
314
+ elif hasattr (model ,n ):
315
+ return getattr (model .c ,n )== model_param [n ]
316
+ else :
317
+ raise UliwebError ("not support item: '%s'" % (item ))
318
+
267
319
def head (self ):
268
320
try :
269
321
for key in self .request_data :
@@ -278,22 +330,22 @@ def head(self):
278
330
return json (self .rdict )
279
331
280
332
def _head (self ,key ):
281
- modelname = key
333
+ model_name = key
282
334
params = self .request_data [key ]
283
335
params_role = params .get ("@role" )
284
336
285
337
try :
286
- model = getattr (models ,modelname )
287
- model_setting = settings .APIJSON_MODELS .get (modelname ,{})
338
+ model = getattr (models ,model_name )
339
+ model_setting = settings .APIJSON_MODELS .get (model_name ,{})
288
340
except ModelNotFound as e :
289
- log .error ("try to find model '%s' but not found: '%s'" % (modelname ,e ))
290
- return json ({"code" :400 ,"msg" :"model '%s' not found" % (modelname )})
341
+ log .error ("try to find model '%s' but not found: '%s'" % (model_name ,e ))
342
+ return json ({"code" :400 ,"msg" :"model '%s' not found" % (model_name )})
291
343
292
344
q = model .all ()
293
345
294
346
HEAD = model_setting .get ("HEAD" )
295
347
if not HEAD :
296
- return json ({"code" :400 ,"msg" :"'%s' not accessible" % (modelname )})
348
+ return json ({"code" :400 ,"msg" :"'%s' not accessible" % (model_name )})
297
349
298
350
roles = HEAD .get ("roles" )
299
351
permission_check_ok = False
@@ -303,7 +355,7 @@ def _head(self,key):
303
355
else :
304
356
params_role = "UNKNOWN"
305
357
if params_role not in roles :
306
- return json ({"code" :400 ,"msg" :"'%s' not accessible by role '%s'" % (modelname ,params_role )})
358
+ return json ({"code" :400 ,"msg" :"'%s' not accessible by role '%s'" % (model_name ,params_role )})
307
359
if params_role == "UNKNOWN" :
308
360
permission_check_ok = True
309
361
elif functions .has_role (request .user ,params_role ):
@@ -316,14 +368,14 @@ def _head(self,key):
316
368
if params_role == "OWNER" :
317
369
owner_filtered ,q = self ._filter_owner (model ,model_setting ,q )
318
370
if not owner_filtered :
319
- return json ({"code" :400 ,"msg" :"'%s' cannot filter with owner" % (modelname )})
371
+ return json ({"code" :400 ,"msg" :"'%s' cannot filter with owner" % (model_name )})
320
372
for n in params :
321
373
if n [0 ]== "@" :
322
374
pass
323
375
else :
324
376
param = params [n ]
325
377
if not hasattr (model .c ,n ):
326
- return json ({"code" :400 ,"msg" :"'%s' don't have field '%s'" % (modelname ,n )})
378
+ return json ({"code" :400 ,"msg" :"'%s' don't have field '%s'" % (model_name ,n )})
327
379
q = model .filter (getattr (model .c ,n )== param )
328
380
rdict = {
329
381
"code" :200 ,
@@ -370,10 +422,9 @@ def _post_one(self,key,tag):
370
422
log .error ("try to find model '%s' but not found: '%s'" % (model_name ,e ))
371
423
return json ({"code" :400 ,"msg" :"model '%s' not found" % (model_name )})
372
424
373
- request_tag_config = request_tag .get (model_name ,{})
374
- if not request_tag_config :
425
+ if not request_tag :
375
426
return json ({"code" :400 ,"msg" :"tag '%s' not found" % (tag )})
376
- tag_POST = request_tag_config .get ("POST" ,{})
427
+ tag_POST = request_tag .get ("POST" ,{})
377
428
if not tag_POST :
378
429
return json ({"code" :400 ,"msg" :"tag '%s' not support apijson_post" % (tag )})
379
430
ADD = tag_POST .get ("ADD" )
@@ -482,10 +533,9 @@ def _put_one(self,key,tag):
482
533
log .error ("try to find model '%s' but not found: '%s'" % (model_name ,e ))
483
534
return json ({"code" :400 ,"msg" :"model '%s' not found" % (model_name )})
484
535
485
- request_tag_config = request_tag .get (model_name ,{})
486
- if not request_tag_config :
536
+ if not request_tag :
487
537
return json ({"code" :400 ,"msg" :"tag '%s' not found" % (tag )})
488
- tag_PUT = request_tag_config .get ("PUT" ,{})
538
+ tag_PUT = request_tag .get ("PUT" ,{})
489
539
ADD = tag_PUT .get ("ADD" )
490
540
if ADD :
491
541
ADD_role = ADD .get ("@role" )
@@ -604,10 +654,9 @@ def _delete_one(self,key,tag):
604
654
log .error ("try to find model '%s' but not found: '%s'" % (model_name ,e ))
605
655
return json ({"code" :400 ,"msg" :"model '%s' not found" % (model_name )})
606
656
607
- request_tag_config = request_tag .get (model_name ,{})
608
- if not request_tag_config :
657
+ if not request_tag :
609
658
return json ({"code" :400 ,"msg" :"tag '%s' not found" % (tag )})
610
- tag_DELETE = request_tag_config .get ("DELETE" ,{})
659
+ tag_DELETE = request_tag .get ("DELETE" ,{})
611
660
ADD = tag_DELETE .get ("ADD" )
612
661
if ADD :
613
662
ADD_role = ADD .get ("@role" )