Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2a4357c

Browse files
add permission support in apijson get(one)/head/delete, 8 test cases
1 parent 39a1c38 commit 2a4357c

File tree

8 files changed

+285
-61
lines changed

8 files changed

+285
-61
lines changed

‎tests/README.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
commands to run the tests:
2+
3+
```
4+
cd tests
5+
nosetests --with-doctest
6+
```

‎tests/demo/apps/apijson_demo/dbinit.py‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
User = models.user
88
Privacy = models.privacy
99
Comment = models.comment
10+
Comment2 = models.comment2
1011
Moment = models.moment
1112
PublicNotice = models.publicnotice
1213

@@ -95,21 +96,21 @@
9596
"to_username" : "userb",
9697
"moment_id" : 1,
9798
"date" : "2018年12月1日",
98-
"content" : "comment haha",
99+
"content" : "comment from usera to userb",
99100
},
100101
{
101102
"username" : "userb",
102103
"to_username" : "usera",
103104
"moment_id" : 2,
104105
"date" : "2018年12月2日",
105-
"content" : "comment xixi",
106+
"content" : "comment from userb to usera",
106107
},
107108
{
108109
"username" : "userc",
109110
"to_username" : "usera",
110111
"moment_id" : 3,
111112
"date" : "2018年12月9日",
112-
"content" : "comment hoho",
113+
"content" : "comment from userc to usera",
113114
},
114115
]
115116

@@ -158,6 +159,7 @@
158159
d["to_id"] = User.get(User.c.username==d["to_username"]).id
159160
print("create comment record for user '%s'"%(d["username"]))
160161
Comment(**d).save()
162+
Comment2(**d).save()
161163
else:
162164
print("error: unknown user '%s'"%(d["username"]))
163165

‎tests/demo/apps/apijson_demo/models.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ class Comment(Model):
2828
date = Field(datetime.datetime, auto_now_add=True)
2929
content = Field(TEXT)
3030

31+
class Comment2(Model):
32+
user_id = Reference("user")
33+
to_id = Reference("user")
34+
moment_id = Reference("moment")
35+
date = Field(datetime.datetime, auto_now_add=True)
36+
content = Field(TEXT)
37+
3138
class PublicNotice(Model):
3239
date = Field(datetime.datetime, auto_now_add=True)
3340
content = Field(TEXT)

‎tests/demo/apps/apijson_demo/settings.ini‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
[MODELS]
22
privacy = 'apijson_demo.models.Privacy'
33
comment = 'apijson_demo.models.Comment'
4+
comment2 = 'apijson_demo.models.Comment2'
45
moment = 'apijson_demo.models.Moment'
56
publicnotice = 'apijson_demo.models.PublicNotice'
67
norequesttag = 'apijson_demo.models.NoRequestTag'
78

9+
[PERMISSIONS]
10+
get_comment2 = "get comment2", ["OWNER", "ADMIN"], ""
11+
head_comment2 = "head comment2", ["OWNER", "ADMIN"], ""
12+
post_comment2 = "post comment2", ["OWNER", "ADMIN"], ""
13+
put_comment2 = "put comment2", ["OWNER", "ADMIN"], ""
14+
delete_comment2 = "delete comment2", ["OWNER", "ADMIN"], ""
15+
816
[APIJSON_MODELS]
917
user = {
1018
"user_id_field" : "id",
@@ -39,6 +47,14 @@ comment = {
3947
"PUT" : { "roles" : ["OWNER","ADMIN"] },
4048
"DELETE" : { "roles" : ["OWNER","ADMIN"] },
4149
}
50+
comment2 = {
51+
"user_id_field" : "user_id",
52+
"GET" : { "permissions":["get_comment2"] },
53+
"HEAD" : { "permissions":["head_comment2"] },
54+
"POST" : { "permissions":["post_comment2"] },
55+
"PUT" : { "permissions":["put_comment2"]},
56+
"DELETE" : {"permissions":["delete_comment2"]},
57+
}
4258
publicnotice = {
4359
"GET" : { "roles" : ["OWNER","LOGIN","ADMIN","UNKNOWN"] },
4460
"HEAD" : { "roles" : ["OWNER","LOGIN","ADMIN","UNKNOWN"] },
@@ -73,6 +89,19 @@ comment = {
7389
},
7490
}
7591

92+
comment2 = {
93+
"POST" :{
94+
"ADD" :{"@role": "OWNER"},
95+
"DISALLOW" : ["id"],
96+
"NECESSARY" : ["moment_id","content"]
97+
},
98+
"PUT" :{
99+
"ADD":{"@role": "OWNER"},
100+
"NECESSARY" : ["id","content"],
101+
"DISALLOW" : ["user_id","to_id"],
102+
},
103+
}
104+
76105
publicnotice = {
77106
"PUT" :{
78107
"NECESSARY" : ["id","content"],

‎tests/test.py‎

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ def test_apijson_head():
11531153
>>> r = handler.post('/apijson/head', data=data, middlewares=[])
11541154
>>> d = json_loads(r.data)
11551155
>>> print(d)
1156-
{'code': 400, 'msg': "no login user for role 'ADMIN'"}
1156+
{'code': 400, 'msg': "user doesn't have role 'ADMIN'"}
11571157
11581158
>>> #apijson head, without user and @role
11591159
>>> data ='''{
@@ -1581,7 +1581,7 @@ def test_apijson_delete():
15811581
>>> print(d)
15821582
{'code': 400, 'msg': "model 'nonexist' not found"}
15831583
1584-
>>> #apijson delete, default to OWNER and delete other's record
1584+
>>> #apijson delete, try to delete other's moment
15851585
>>> data ='''{
15861586
... "moment": {
15871587
... "id": 2
@@ -1591,7 +1591,7 @@ def test_apijson_delete():
15911591
>>> r = handler.post('/apijson/delete', data=data, pre_call=pre_call_as("usera"), middlewares=[])
15921592
>>> d = json_loads(r.data)
15931593
>>> print(d)
1594-
{'code': 400, 'msg': 'no permission'}
1594+
{'code': 400, 'msg': 'no role to access the data'}
15951595
15961596
>>> #apijson delete, without id
15971597
>>> data ='''{
@@ -1647,7 +1647,7 @@ def test_apijson_delete():
16471647
>>> r = handler.post('/apijson/delete', data=data, pre_call=pre_call_as("usera"), middlewares=[])
16481648
>>> d = json_loads(r.data)
16491649
>>> print(d)
1650-
{'code': 400, 'msg': "'moment' not accessible by role 'UNKNOWN'"}
1650+
{'code': 400, 'msg': "role 'UNKNOWN' has no permission to access the data"}
16511651
16521652
>>> #apijson delete, with OWNER but not login
16531653
>>> data ='''{
@@ -1667,7 +1667,7 @@ def test_apijson_delete():
16671667
>>> r = handler.post('/apijson/delete', data=data, middlewares=[])
16681668
>>> d = json_loads(r.data)
16691669
>>> print(d)
1670-
{'code': 400, 'msg': 'need login user'}
1670+
{'code': 400, 'msg': 'no role to access the data'}
16711671
16721672
>>> #apijson delete, with UNKNOWN role
16731673
>>> data ='''{
@@ -1701,5 +1701,101 @@ def test_apijson_delete():
17011701
>>> r = handler.post('/apijson/delete', data=data, pre_call=pre_call_as("admin"), middlewares=[])
17021702
>>> d = json_loads(r.data)
17031703
>>> print(d)
1704-
{'code': 400, 'msg': "'moment' not accessible by role 'superuser'"}
1704+
{'code': 400, 'msg': "role 'superuser' has no permission to access the data"}
1705+
"""
1706+
1707+
def test_apijson_permission():
1708+
"""
1709+
>>> application = make_simple_application(project_dir='.')
1710+
>>> handler = application.handler()
1711+
1712+
>>> #apijson get, query with id, access with owner
1713+
>>> data ='''{
1714+
... "comment2":{
1715+
... "id": 1
1716+
... }
1717+
... }'''
1718+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
1719+
>>> d = json_loads(r.data)
1720+
>>> print(d)
1721+
{'code': 200, 'msg': 'success', 'comment2': {'user_id': 1, 'to_id': 3, 'moment_id': 1, 'date': '2018年11月01日 00:00:00', 'content': 'comment from admin', 'id': 1}}
1722+
1723+
>>> #apijson get, query with id, access other's comment, expect empty result
1724+
>>> data ='''{
1725+
... "comment2":{
1726+
... "id": 1
1727+
... }
1728+
... }'''
1729+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("userb"), middlewares=[])
1730+
>>> d = json_loads(r.data)
1731+
>>> print(d)
1732+
{'code': 200, 'msg': 'success', 'comment2': None}
1733+
1734+
>>> #apijson get, query array
1735+
>>> data ='''{
1736+
... "comment2":{
1737+
... }
1738+
... }'''
1739+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("usera"), middlewares=[])
1740+
>>> d = json_loads(r.data)
1741+
>>> print(d)
1742+
{'code': 200, 'msg': 'success', 'comment2': {'user_id': 2, 'to_id': 3, 'moment_id': 1, 'date': '2018年12月01日 00:00:00', 'content': 'comment from usera to userb', 'id': 2}}
1743+
1744+
>>> #apijson get, query one with admin as OWNER
1745+
>>> data ='''{
1746+
... "comment2":{
1747+
... "@role":"OWNER"
1748+
... }
1749+
... }'''
1750+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
1751+
>>> d = json_loads(r.data)
1752+
>>> print(d)
1753+
{'code': 200, 'msg': 'success', 'comment2': {'user_id': 1, 'to_id': 3, 'moment_id': 1, 'date': '2018年11月01日 00:00:00', 'content': 'comment from admin', 'id': 1}}
1754+
1755+
>>> #apijson get, query one with admin as ADMIN
1756+
>>> data ='''{
1757+
... "comment2":{
1758+
... "@role":"ADMIN",
1759+
... "user_id": 2
1760+
... }
1761+
... }'''
1762+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
1763+
>>> d = json_loads(r.data)
1764+
>>> print(d)
1765+
{'code': 200, 'msg': 'success', 'comment2': {'user_id': 2, 'to_id': 3, 'moment_id': 1, 'date': '2018年12月01日 00:00:00', 'content': 'comment from usera to userb', 'id': 2}}
1766+
1767+
>>> #apijson head
1768+
>>> data ='''{
1769+
... "comment2": {
1770+
... "user_id": 1
1771+
... }
1772+
... }'''
1773+
>>> r = handler.post('/apijson/head', data=data, pre_call=pre_call_as("userc"), middlewares=[])
1774+
>>> d = json_loads(r.data)
1775+
>>> print(d)
1776+
{'code': 200, 'msg': 'success', 'comment2': {'code': 200, 'msg': 'success', 'count': 0}}
1777+
1778+
>>> #apijson delete with a user which have no permission
1779+
>>> data ='''{
1780+
... "comment2": {
1781+
... "id": 1
1782+
... },
1783+
... "@tag": "comment2"
1784+
... }'''
1785+
>>> r = handler.post('/apijson/delete', data=data, pre_call=pre_call_as("userc"), middlewares=[])
1786+
>>> d = json_loads(r.data)
1787+
>>> print(d)
1788+
{'code': 400, 'msg': 'no permission'}
1789+
1790+
>>> #apijson delete with permission, ADMIN
1791+
>>> data ='''{
1792+
... "comment2": {
1793+
... "id": 1
1794+
... },
1795+
... "@tag": "comment2"
1796+
... }'''
1797+
>>> r = handler.post('/apijson/delete', data=data, pre_call=pre_call_as("admin"), middlewares=[])
1798+
>>> d = json_loads(r.data)
1799+
>>> print(d)
1800+
{'code': 200, 'msg': 'success', 'comment2': {'id': 1, 'code': 200, 'message': 'success', 'count': 1}}
17051801
"""

‎uliweb_apijson/apijson/__init__.py‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,71 @@ def associated_query_array(self):
260260
params.update(refs)
261261
q = self._get_array_q(params)
262262
item[self.name] = self._get_info(q.one())
263+
264+
def is_obj_owner(user, obj, user_id_field):
265+
if user and user_id_field:
266+
return obj.to_dict().get(user_id_field)==user.id
267+
return False
268+
269+
def has_obj_role(user, obj, user_id_field, as_role, *roles):
270+
from uliweb import functions
271+
if as_role:
272+
if as_role not in roles:
273+
return False, "role '%s' has no permission to access the data"%(as_role)
274+
if not functions.has_role(user, as_role):
275+
return False, "user has no role '%s'"%(as_role)
276+
if as_role == "OWNER":
277+
if not is_obj_owner(user, obj, user_id_field):
278+
return False, "user is not the owner of data"
279+
return True, None
280+
else:
281+
for role in roles:
282+
if functions.has_role(user, role):
283+
if isinstance(role,str):
284+
role_name = role
285+
elif hasattr(role, "name"):
286+
role_name = role.name
287+
else:
288+
continue
289+
if role_name == "OWNER":
290+
if is_obj_owner(user, obj, user_id_field):
291+
return True, None
292+
else:
293+
continue
294+
else:
295+
return True, None
296+
return False, "no role to access the data"
297+
298+
def has_obj_permission(user, obj, user_id_field, *perms):
299+
from uliweb import functions, models
300+
301+
Role = models.role
302+
Perm = models.permission
303+
304+
for name in perms:
305+
perm = Perm.get(Perm.c.name == name)
306+
if not perm:
307+
continue
308+
has, msg = functions.has_obj_role(user, obj, user_id_field, None, *list(perm.perm_roles.with_relation().all()))
309+
if has:
310+
return has, None
311+
return False, "no permission"
312+
313+
def has_permission_as_role(user, as_role, *perms):
314+
from uliweb import functions, models
315+
316+
Role = models.role
317+
Perm = models.permission
318+
319+
flag = functions.has_role(user, as_role)
320+
if not flag:
321+
return False, "user has no role '%s'"%(as_role)
322+
323+
for name in perms:
324+
perm = Perm.get(Perm.c.name==name)
325+
if not perm:
326+
continue
327+
for role in perm.perm_roles.with_relation().all():
328+
if role.name == as_role:
329+
return role, None
330+
return False, "no permission"

‎uliweb_apijson/apijson/settings.ini‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ user = {
1919

2020
[FUNCTIONS]
2121
get_apijson_tables = "uliweb_apijson.apijson.get_apijson_tables"
22-
get_apijson_table = "uliweb_apijson.apijson.get_apijson_table"
22+
get_apijson_table = "uliweb_apijson.apijson.get_apijson_table"
23+
has_obj_role = "uliweb_apijson.apijson.has_obj_role"
24+
has_obj_permission = "uliweb_apijson.apijson.has_obj_permission"
25+
has_permission_as_role = "uliweb_apijson.apijson.has_permission_as_role"

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /