Skip to content

Commit 062daa0

Browse files
committed
Add a key and client defined value column to metadata table
1 parent ba71d77 commit 062daa0

File tree

4 files changed

+184
-111
lines changed

4 files changed

+184
-111
lines changed

lib/pbench/server/api/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ def register_endpoints(api, app, config):
8888

8989
api.add_resource(
9090
UserMetadata,
91-
f"{base_uri}/metadata",
91+
f"{base_uri}/metadata/<string:key>",
9292
resource_class_args=(config, logger, token_auth),
9393
)
9494
api.add_resource(
9595
QueryMetadata,
96-
f"{base_uri}/metadata/<string:id>",
96+
f"{base_uri}/metadata/<int:id>",
9797
resource_class_args=(config, logger),
9898
)
9999

lib/pbench/server/api/resources/metadata_api.py

Lines changed: 85 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from flask_restful import Resource, abort
22
from flask import request, make_response, jsonify
3-
from pbench.server.database.models.metadata import Metadata
3+
from pbench.server.database.models.metadata import Metadata, MetadataKeys
44
from pbench.server.api.auth import Auth
55

66

@@ -14,58 +14,70 @@ def __init__(self, config, logger, auth):
1414
self.logger = logger
1515
self.auth = auth
1616

17-
@Auth.token_auth.login_required()
18-
def post(self):
17+
@Auth.token_auth.login_required(optional=True)
18+
def post(self, key):
1919
"""
2020
Post request for creating metadata instance for a user.
21-
This requires a Pbench auth token in the header field
21+
22+
The url requires a metadata session key such as /metadata/<key>
23+
the only keys acceptable to create the metadata sessions are favourite/saved
2224
2325
This requires a JSON data with required user metadata fields
2426
{
25-
"config": "config",
26-
"description": "description",
27+
"value": "blog text" <Client defined text, can be a string of json>,
2728
}
29+
Example: {"value": '{"config": "config", "description": "description"}'}
2830
29-
Required headers include
31+
Authorization header can be included as
3032
Authorization: Bearer <Pbench authentication token (user received upon login)>
33+
If the authorization header is not present, the created metadata session becomes public by default
3134
3235
:return: JSON Payload
3336
response_object = {
3437
"message": "success"
3538
"data" {
3639
"id": "metadata_id",
37-
"config": "Config string"
38-
"description": "Description string"
40+
"value": "client text blob",
41+
"created": "datetime string",
42+
"updated": "datetime string",
43+
"key": favorite/saved
3944
}
4045
}
4146
"""
47+
metadata_key = key.upper()
48+
if metadata_key not in [key.name for key in MetadataKeys]:
49+
self.logger.warning(
50+
"Invalid Metadata key provided during metadata creation. Key: {}",
51+
metadata_key,
52+
)
53+
abort(
54+
400,
55+
message="Invalid metadata key. Key need to be either Favorite/Saved",
56+
)
57+
4258
post_data = request.get_json()
4359
if not post_data:
4460
self.logger.warning("Invalid json object: {}", request.url)
4561
abort(400, message="Invalid json object in request")
4662

47-
current_user_id = self.auth.token_auth.current_user().id
48-
49-
config = post_data.get("config")
50-
if not config:
51-
self.logger.warning(
52-
"Config not provided during metadata creation. user_id: {}",
53-
current_user_id,
54-
)
55-
abort(400, message="Config field missing")
63+
current_user = self.auth.token_auth.current_user()
64+
if current_user:
65+
current_user_id = current_user.id
66+
else:
67+
current_user_id = None
5668

57-
description = post_data.get("description")
58-
if not description:
69+
value = post_data.get("value")
70+
if not value:
5971
self.logger.warning(
60-
"Description not provided during metadata creation by user: {}",
72+
"value not provided during metadata creation. user_id: {}",
6173
current_user_id,
6274
)
63-
abort(400, message="Description field missing")
75+
abort(400, message="Value field missing")
6476

6577
try:
6678
# Create a new metadata session
6779
metadata_session = Metadata(
68-
config=config, description=description, user_id=current_user_id
80+
value=value, key=metadata_key, user_id=current_user_id
6981
)
7082
# insert the metadata session for a user
7183
metadata_session.add()
@@ -78,16 +90,12 @@ def post(self):
7890
else:
7991
response_object = {
8092
"message": "success",
81-
"data": {
82-
"id": metadata_session.id,
83-
"config": metadata_session.config,
84-
"description": metadata_session.description,
85-
},
93+
"data": metadata_session.get_json(),
8694
}
8795
return make_response(jsonify(response_object), 201)
8896

89-
@Auth.token_auth.login_required()
90-
def get(self):
97+
@Auth.token_auth.login_required(optional=True)
98+
def get(self, key):
9199
"""
92100
Get request for querying all the metadata sessions for a user.
93101
returns the list of all the metadata sessions associated with a logged in user.
@@ -98,20 +106,38 @@ def get(self):
98106
99107
:return: JSON Payload
100108
response_object = {
101-
"status": "success"
109+
"message": "success"
102110
"data": {
103111
"sessions": [
104112
{"id": "metadata_id",
105-
"config": "Config string"
106-
"description": "Description string"},
113+
"value": "client text blob",
114+
"key": "key string",
115+
"created": "datetime string",
116+
"updated": "datetime string", },
107117
{}]
108118
}
109119
}
110120
"""
111-
current_user_id = self.auth.token_auth.current_user().id
121+
if not key:
122+
self.logger.warning("Metadata key not provided during metadata query")
123+
abort(400, message="Missing metadata key in the query url")
124+
125+
current_user = self.auth.token_auth.current_user()
126+
if current_user:
127+
current_user_id = current_user.id
128+
else:
129+
current_user_id = None
130+
print(current_user_id)
112131
try:
113-
# Fetch the metadata session
114-
metadata_sessions = Metadata.query(user_id=current_user_id)
132+
# Fetch the metadata sessions
133+
# If the key is favorite, we return only favorite sessions,
134+
# else we return all the saved and favorite sessions
135+
if key.upper() == "FAVORITE":
136+
metadata_sessions = Metadata.query(
137+
user_id=current_user_id, key=MetadataKeys[key.upper()].value
138+
)
139+
else:
140+
metadata_sessions = Metadata.query(user_id=current_user_id)
115141
data = [session.get_json() for session in metadata_sessions]
116142
except Exception:
117143
self.logger.exception(
@@ -153,18 +179,20 @@ def get(self, id=None):
153179
Get request for querying a metadata session of a user given a metadata id.
154180
This requires a Pbench auth token in the header field
155181
156-
The url requires a metadata session id such as /user/metadata/<string:id>
182+
The url requires a metadata session id such as /user/metadata/<int:id>
157183
158184
Required headers include
159185
Authorization: Bearer <Pbench authentication token (user received upon login)>
160186
161187
:return: JSON Payload
162188
response_object = {
163-
"message": "success"
164-
"data" {
189+
"message": "success",
190+
"data": {
165191
"id": "metadata_id",
166-
"config": "Config string"
167-
"description": "Description string"
192+
"value": "client text blob"
193+
"created": "Datetime string"
194+
"updated": "Datetime String"
195+
"key": "key string"
168196
}
169197
}
170198
"""
@@ -174,7 +202,7 @@ def get(self, id=None):
174202

175203
try:
176204
# Fetch the metadata session
177-
metadata_session = Metadata.query(id=id)
205+
metadata_session = Metadata.query(id=id)[0]
178206
except Exception:
179207
self.logger.exception(
180208
"Exception occurred in the GET request while querying the Metadata model, id: {}",
@@ -187,11 +215,7 @@ def get(self, id=None):
187215

188216
response_object = {
189217
"message": "success",
190-
"data": {
191-
"id": metadata_session.id,
192-
"config": metadata_session.config,
193-
"description": metadata_session.description,
194-
},
218+
"data": metadata_session.get_json(),
195219
}
196220
return make_response(jsonify(response_object), 200)
197221

@@ -201,23 +225,27 @@ def put(self, id=None):
201225
Put request for updating a metadata session of a user given a metadata id.
202226
This requires a Pbench auth token in the header field
203227
204-
The url requires a metadata session id such as /user/metadata/<string:id>
228+
The url requires a metadata session id such as /user/metadata/<int:id>
205229
206230
This requires a JSON data with required user metadata fields to update
207231
{
208-
"description": "description",
232+
"value": "new text value",
233+
...
209234
}
235+
To update the value field, it is required to send the complete text blob again
210236
211237
Required headers include
212238
Authorization: Bearer <Pbench authentication token (user received upon login)>
213239
214240
:return: JSON Payload
215241
response_object = {
216-
"message": "success"
217-
"data" {
242+
"message": "success",
243+
"data": {
218244
"id": "metadata_id",
219-
"config": "Config string"
220-
"description": "Description string"
245+
"value": "client text blob"
246+
"created": "Datetime string"
247+
"updated": "Datetime String"
248+
"key": "key string"
221249
}
222250
}
223251
"""
@@ -231,7 +259,7 @@ def put(self, id=None):
231259
abort(400, message="Invalid json object in request")
232260

233261
try:
234-
metadata_session = Metadata.query(id=id)
262+
metadata_session = Metadata.query(id=id)[0]
235263
except Exception:
236264
self.logger.exception(
237265
"Exception occurred in the PUT request while querying the Metadata model, id: {}",
@@ -274,11 +302,7 @@ def put(self, id=None):
274302
else:
275303
response_object = {
276304
"message": "success",
277-
"data": {
278-
"id": metadata_session.id,
279-
"config": metadata_session.config,
280-
"description": metadata_session.description,
281-
},
305+
"data": metadata_session.get_json(),
282306
}
283307
return make_response(jsonify(response_object), 200)
284308

@@ -288,7 +312,7 @@ def delete(self, id=None):
288312
Delete request for deleting a metadata session of a user given a metadata id.
289313
This requires a Pbench auth token in the header field
290314
291-
The url requires a metadata session id such as /user/metadata/<string:id>
315+
The url requires a metadata session id such as /user/metadata/<int:id>
292316
293317
Required headers include
294318
Authorization: Bearer <Pbench authentication token (user received upon login)>
@@ -304,7 +328,7 @@ def delete(self, id=None):
304328

305329
try:
306330
# Fetch the metadata session
307-
metadata_session = Metadata.query(id=id)
331+
metadata_session = Metadata.query(id=id)[0]
308332
except Exception:
309333
self.logger.exception(
310334
"Exception occurred in the Delete request while querying the Metadata model, id: {}",

lib/pbench/server/database/models/metadata.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
import enum
12
import datetime
23
from pbench.server.database.database import Database
3-
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Text
4+
from sqlalchemy import Column, Integer, DateTime, ForeignKey, Text
5+
from sqlalchemy.orm import validates
6+
7+
8+
class MetadataKeys(enum.Enum):
9+
FAVORITE = 1
10+
SAVED = 2
411

512

613
class Metadata(Database.Base):
@@ -12,38 +19,34 @@ class Metadata(Database.Base):
1219
id = Column(Integer, primary_key=True, autoincrement=True)
1320
created = Column(DateTime, nullable=False, default=datetime.datetime.now())
1421
updated = Column(DateTime, nullable=False, default=datetime.datetime.now())
15-
config = Column(Text, unique=False, nullable=False)
16-
description = Column(String(255), nullable=False)
17-
user_id = Column(Integer, ForeignKey("users.id"))
22+
value = Column(Text, unique=False, nullable=False)
23+
key = Column(Integer, nullable=False)
24+
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=True)
1825

19-
def __str__(self):
20-
return f"Url id: {self.id}, created on: {self.created}, description: {self.description}"
26+
@validates("key")
27+
def evaluate_key(self, key, value):
28+
return MetadataKeys[value].value
2129

2230
def get_json(self):
2331
return {
2432
"id": self.id,
25-
"config": self.config,
26-
"description": self.description,
33+
"value": self.value,
2734
"created": self.created,
2835
"updated": self.updated,
36+
"key": MetadataKeys(self.key).name,
2937
}
3038

3139
@staticmethod
3240
def get_protected():
33-
return ["id", "created"]
41+
return ["id", "created", "user_id"]
3442

3543
@staticmethod
36-
def query(id=None, user_id=None):
37-
# Currently we would only query with single argument. Argument need to be either id/user_id
38-
if id:
39-
metadata = Database.db_session.query(Metadata).filter_by(id=id).first()
40-
elif user_id:
41-
# If the query parameter is user_id then we return the list of all the metadata linked to that user
42-
metadata = Database.db_session.query(Metadata).filter_by(user_id=user_id)
43-
else:
44-
metadata = None
45-
46-
return metadata
44+
def query(**kwargs):
45+
query = Database.db_session.query(Metadata)
46+
for attr, value in kwargs.items():
47+
print(getattr(Metadata, attr), value)
48+
query = query.filter(getattr(Metadata, attr) == value)
49+
return query.all()
4750

4851
def add(self):
4952
"""

0 commit comments

Comments
 (0)