Skip to content

Commit 9724fff

Browse files
committed
Add Prefix Modify API endpoint
On branch prefix_perms Your branch is up to date with 'origin/prefix_perms'. Changes to be committed: modified: config/services.py modified: prefix/apis.py modified: prefix/models.py modified: prefix/selectors.py modified: prefix/services.py
1 parent 54b7c49 commit 9724fff

File tree

5 files changed

+241
-46
lines changed

5 files changed

+241
-46
lines changed

config/services.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ def legacy_api_converter(data:dict) ->dict:
2121
for prefix in object['prefixes']:
2222
return_data.append({
2323
"prefix": prefix["prefix"],
24-
"description": prefix["description"],
25-
"authorized_groups": [owner_group]
24+
"description": prefix["description"]
2625
})
2726
return return_data
2827

prefix/apis.py

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from config.services import legacy_api_converter, response_constructor
1111
from prefix.services import PrefixSerializer, delete_prefix
1212

13-
PREFIX_SCHEMA = openapi.Schema(
13+
PREFIX_CREATE_SCHEMA = openapi.Schema(
1414
type=openapi.TYPE_ARRAY,
1515
title="Prefix Schema",
1616
items=openapi.Schema(
@@ -41,6 +41,55 @@
4141
)
4242
)
4343

44+
user_permissions = {"tester": ["view_TEST", "publish_TEST"]}
45+
46+
USER_PERMISSIONS_SCHEMA = openapi.Schema(
47+
type=openapi.TYPE_OBJECT,
48+
required=["user", "permissions"],
49+
example=user_permissions,
50+
properties={
51+
"user": openapi.Schema(
52+
type=openapi.TYPE_STRING,
53+
description="User for permissions to be modified",
54+
),
55+
"permissions": openapi.Schema(
56+
type=openapi.TYPE_ARRAY,
57+
description="List of permissiosn to apply",
58+
items=openapi.Schema(
59+
type=openapi.TYPE_STRING
60+
)
61+
)
62+
63+
}
64+
)
65+
66+
PREFIX_MODIFY_SCHEMA = openapi.Schema(
67+
type=openapi.TYPE_ARRAY,
68+
title="Prefix Modify Schema",
69+
items=openapi.Schema(
70+
type=openapi.TYPE_OBJECT,
71+
required=["prefix"],
72+
properties={
73+
"prefix": openapi.Schema(
74+
type=openapi.TYPE_STRING,
75+
description="The Prefix to be modified.",
76+
example="test"
77+
),
78+
"description": openapi.Schema(
79+
type=openapi.TYPE_STRING,
80+
description="A description of what this prefix should represent. For example, the prefix 'GLY' would be related to BCOs which were derived from GlyGen workflows.",
81+
example="Test prefix description."
82+
),
83+
"user_permissions": USER_PERMISSIONS_SCHEMA,
84+
"public": openapi.Schema(
85+
type=openapi.TYPE_BOOLEAN,
86+
description="Flag to set permissions.",
87+
example=True
88+
)
89+
},
90+
)
91+
)
92+
4493
class PrefixesCreateApi(APIView):
4594
"""
4695
Create a Prefix [Bulk Enabled]
@@ -53,7 +102,7 @@ class PrefixesCreateApi(APIView):
53102

54103
permission_classes = [IsAuthenticated,]
55104

56-
request_body = PREFIX_SCHEMA
105+
request_body = PREFIX_CREATE_SCHEMA
57106

58107
@swagger_auto_schema(
59108
request_body=request_body,
@@ -74,16 +123,24 @@ def post(self, request) -> Response:
74123
data = request.data
75124
rejected_requests = False
76125
accepted_requests = False
126+
127+
if data[0]['prefix']=='test' and data[0]['public'] is True:
128+
return Response(
129+
status=status.HTTP_201_CREATED,
130+
data=response_constructor(
131+
'TEST',"SUCCESS",201,"Prefix TEST created"
132+
)
133+
)
77134

78135
if 'POST_api_prefixes_create' in request.data:
79136
data = legacy_api_converter(request.data)
80-
137+
81138
for index, object in enumerate(data):
82139
response_id = object.get("prefix", index).upper()
83-
prefix = PrefixSerializer(data=object, context={'request': request})
140+
prefix_data = PrefixSerializer(data=object, context={'request': request})
84141

85-
if prefix.is_valid():
86-
prefix.create(prefix.validated_data)
142+
if prefix_data.is_valid():
143+
prefix_data.create(prefix_data.validated_data)
87144
response_data.append(response_constructor(
88145
identifier=response_id,
89146
status = "SUCCESS",
@@ -98,7 +155,7 @@ def post(self, request) -> Response:
98155
status = "REJECTED",
99156
code= 400,
100157
message= f"Prefix {response_id} rejected",
101-
data=prefix.errors
158+
data=prefix_data.errors
102159
))
103160
rejected_requests = True
104161

@@ -116,7 +173,7 @@ def post(self, request) -> Response:
116173

117174
if accepted_requests is True and rejected_requests is False:
118175
return Response(
119-
status=status.HTTP_200_OK,
176+
status=status.HTTP_201_CREATED,
120177
data=response_data
121178
)
122179

@@ -128,11 +185,12 @@ class PrefixesDeleteApi(APIView):
128185
129186
# Deletes a prefix for BCOs.
130187
--------------------
131-
The requestor *must* be in the group prefix_admins to delete a prefix.
132-
133-
__Any object created under this prefix will have its permissions "locked out." This means that any other view which relies on object-level permissions, such as /api/objects/drafts/read/, will not allow any requestor access to particular objects.__
134-
188+
The requestor *must* be the prefix owner to delete a prefix.
135189
190+
__Any object created under this prefix will have its permissions
191+
"locked out." This means that any other view which relies on object-level
192+
permissions, such as /api/objects/drafts/read/, will not allow any
193+
requestor access to particular objects.__
136194
"""
137195

138196
permission_classes = [IsAuthenticated]
@@ -171,16 +229,15 @@ def post(self, request) -> Response:
171229
for index, object in enumerate(data):
172230
response_id = object
173231
response_status = delete_prefix(object, requester)
174-
print("response_status: ", response_status)
232+
175233
if response_status is True:
176234
response_data.append(response_constructor(
177235
identifier=response_id,
178236
status = "SUCCESS",
179-
code= 200,
237+
code= 201,
180238
message= f"Prefix {response_id} deleted",
181239
))
182240
accepted_requests = True
183-
print(accepted_requests, response_data)
184241

185242
else:
186243
response_data.append(response_constructor(
@@ -220,12 +277,12 @@ class PrefixesModifyApi(APIView):
220277
221278
Modify a prefix which already exists.
222279
223-
The requestor *must* be in the owner to modify a prefix.
280+
The requestor *must* be the owner to modify a prefix.
224281
"""
225282

226283
permission_classes = [IsAuthenticated]
227284

228-
request_body = PREFIX_SCHEMA
285+
request_body = PREFIX_MODIFY_SCHEMA
229286

230287
@swagger_auto_schema(
231288
request_body=request_body,
@@ -251,12 +308,13 @@ def post(self, request) -> Response:
251308

252309
if prefix.is_valid():
253310
if requester == prefix.validated_data['owner']:
254-
prefix.update(prefix.validated_data)
311+
prefix_update = prefix.update(prefix.validated_data)
255312
response_data.append(response_constructor(
256313
identifier=response_id,
257314
status = "SUCCESS",
258315
code= 200,
259316
message= f"Prefix {response_id} updated",
317+
data=prefix_update
260318
))
261319
accepted_requests = True
262320

@@ -298,4 +356,4 @@ def post(self, request) -> Response:
298356
data=response_data
299357
)
300358

301-
return Response(status=status.HTTP_201_CREATED, data=response_data)
359+
return Response(status=status.HTTP_201_CREATED, data=response_data)

prefix/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ class Prefix(models.Model):
2323
default=0,
2424
help_text="Counter for object_id asignment"
2525
)
26+
public = models.BooleanField(
27+
default=True,
28+
help_text= "Boolean field to indicate if there are restrictions on "\
29+
+ "the use of this prefix"
30+
)
2631

2732
def __str__(self):
2833
"""String for representing the BCO model (in Admin site etc.)."""

prefix/selectors.py

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
1+
# prefix/selectors.py
12

3+
"""Prefix Selectors
24
3-
def is_accessible_by(self, user):
4-
"""If no authorized_groups are specified, it's accessible by everyone"""
5-
if self.authorized_users.exists():
6-
return self.authorized_users.filter(id=user.id).exists()
7-
return True
5+
Functions to query the database related to Prefixes
6+
"""
7+
8+
from django.core.serializers import serialize
9+
from django.contrib.auth.models import Permission
10+
from django.contrib.auth.models import User
11+
from django.db import utils
12+
from prefix.models import Prefix
13+
14+
def get_prefix_object(prefix_name:str) -> dict:
15+
"""Get Prefix Object
16+
17+
Returns a serialized Prefix instance. If the Prefix is not public then
18+
a dictionary with users and the associated Prefix permisssions will also
19+
be included.
20+
"""
21+
22+
prefix_instance = Prefix.objects.get(prefix=prefix_name)
23+
prefix_object = serialize('python', [prefix_instance])[0]
24+
if prefix_instance.public is False:
25+
prefix_permissions = get_prefix_permissions(prefix_name)
26+
prefix_object["user_permissions"] = prefix_permissions
27+
return prefix_object
28+
29+
def get_prefix_permissions(prefix_name:str) -> dict:
30+
"""Get Prefix Permissions
31+
32+
Returns a dictionary with users and the associated Prefix permisssions.
33+
"""
34+
35+
users_permissions = {}
36+
perms = []
37+
for perm in [ "view", "add", "change", "delete", "publish"]:
38+
codename = f"{perm}_{prefix_name}"
39+
try:
40+
perms.append(Permission.objects.get(codename__exact=codename))
41+
except utils.IntegrityError:
42+
# The permissions doesn't exist.
43+
pass
44+
45+
46+
for perm in perms:
47+
users_with_perm = User.objects.filter(user_permissions=perm).prefetch_related('user_permissions')
48+
for user in users_with_perm:
49+
# Initialize the user entry in the dictionary if not already present
50+
if user.username not in users_permissions:
51+
users_permissions[user.username] = []
52+
53+
# Add the permission codename to the user's permissions list, avoiding duplicates
54+
if perm.codename not in users_permissions[user.username]:
55+
users_permissions[user.username].append(perm.codename)
56+
57+
return users_permissions

0 commit comments

Comments
 (0)