Skip to content

Commit d8a0916

Browse files
authored
Release 4.3.0 (#233)
1 parent 6d510f3 commit d8a0916

75 files changed

Lines changed: 6610 additions & 471 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
This changelog was started for release 4.2.0.
99

10+
## [4.3.0] - 2021-06-10
11+
12+
### Added
13+
14+
- Added 'Date' entity type, with associated Date picker in UI
15+
- Added API-key authentication for most endpoints. The api key should be passed with the header "X-API-KEY".
16+
- Added CLI (using token-auth) (https://github.com/askomics/askoclics). Still a WIP, with the python package 'askoclics'.
17+
- "Not" filter for categories
18+
- URI management in first column (and link column). Manage both full URI and CURIE. Check #223 for details.
19+
- 'Forms' : Minimal templates (users only access a basic form for modifying parameters, and not the graph) Restricted to admins. Form creators can customized entities and attributes display names to improve usability.
20+
21+
### Changed
22+
23+
- Faldo entity "Strand" now default to "faldo:BothStrandPosition" when the value is empty. The label will be "unknown/both" for CSV. For GFF and BED, "." will be "faldo:BothStrandPosition" instead of being ignored.
24+
- If one of the column name of a CSV file is empty, raise an Exception.
25+
- Now return the created result id (instead of celery task id) in the sparql query endpoint
26+
- Now return the created file id (instead of celery task id) in the create file endpoint
27+
- Fixed Flask version to < 2.0.0 due to compatibility issues
28+
29+
30+
### Fixed
31+
32+
- Fixed the console restriction to admin/users (was not fully functional)
33+
- Fixed an issue with spaces (and other characters) in URIs
34+
- Fixed an issue with "Optional" button when using categories (and faldo entities) (either wrong values or nothing showing up) (Cf Changed category)
35+
- Fixed table ordering in results for numerical values (they were managed as strings)
36+
- Fixed UNION and MINUS blocks
37+
- Fixed an issue with Faldo "same strand" (clicking on the link between Faldo nodes)
38+
- Fixed Node/Link filter issue when using values with caps.
39+
40+
### Security
41+
42+
- Bump hosted-git-info from 2.8.8 to 2.8.9
43+
44+
## [4.2.2] - 2021-06-09
45+
46+
### Fixed
47+
48+
- Fixed startup issue: race condition on config file creation
49+
1050
## [4.2.1] - 2021-03-29
1151

1252
### Fixed

Pipfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name = "pypi"
55

66
[packages]
77
werkzeug = "==0.16.1"
8-
flask = "*"
8+
flask = "==1.1.4"
99
flask-reverse-proxy-fix = "*"
1010
validate-email = "*"
1111
gunicorn = "*"
@@ -28,6 +28,7 @@ configparser = "*"
2828
tld = "*"
2929
argh = "*"
3030
python-ldap = "*"
31+
python-dateutil = "*"
3132

3233
[dev-packages]
3334
pytest = "*"

Pipfile.lock

Lines changed: 212 additions & 226 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

askomics/api/admin.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sys
33
import traceback
44

5-
from askomics.api.auth import admin_required
5+
from askomics.api.auth import api_auth, admin_required
66
from askomics.libaskomics.DatasetsHandler import DatasetsHandler
77
from askomics.libaskomics.FilesHandler import FilesHandler
88
from askomics.libaskomics.LocalAuth import LocalAuth
@@ -16,6 +16,7 @@
1616

1717

1818
@admin_bp.route('/api/admin/getusers', methods=['GET'])
19+
@api_auth
1920
@admin_required
2021
def get_users():
2122
"""Get all users
@@ -46,6 +47,7 @@ def get_users():
4647

4748

4849
@admin_bp.route('/api/admin/getdatasets', methods=['GET'])
50+
@api_auth
4951
@admin_required
5052
def get_datasets():
5153
"""Get all datasets
@@ -76,6 +78,7 @@ def get_datasets():
7678

7779

7880
@admin_bp.route('/api/admin/getfiles', methods=['GET'])
81+
@api_auth
7982
@admin_required
8083
def get_files():
8184
"""Get all files info
@@ -107,6 +110,7 @@ def get_files():
107110

108111

109112
@admin_bp.route('/api/admin/getqueries', methods=['GET'])
113+
@api_auth
110114
@admin_required
111115
def get_queries():
112116
"""Get all public queries
@@ -138,6 +142,7 @@ def get_queries():
138142

139143

140144
@admin_bp.route('/api/admin/setadmin', methods=['POST'])
145+
@api_auth
141146
@admin_required
142147
def set_admin():
143148
"""change admin status of a user
@@ -167,6 +172,7 @@ def set_admin():
167172

168173

169174
@admin_bp.route('/api/admin/setquota', methods=["POST"])
175+
@api_auth
170176
@admin_required
171177
def set_quota():
172178
"""Change quota of a user
@@ -200,6 +206,7 @@ def set_quota():
200206

201207

202208
@admin_bp.route('/api/admin/setblocked', methods=['POST'])
209+
@api_auth
203210
@admin_required
204211
def set_blocked():
205212
"""Change blocked status of a user
@@ -229,6 +236,7 @@ def set_blocked():
229236

230237

231238
@admin_bp.route('/api/admin/publicize_dataset', methods=['POST'])
239+
@api_auth
232240
@admin_required
233241
def toogle_public_dataset():
234242
"""Toggle public status of a dataset
@@ -269,6 +277,7 @@ def toogle_public_dataset():
269277

270278

271279
@admin_bp.route('/api/admin/publicize_query', methods=['POST'])
280+
@api_auth
272281
@admin_required
273282
def togle_public_query():
274283
"""Publish a query template from a result
@@ -305,6 +314,7 @@ def togle_public_query():
305314

306315

307316
@admin_bp.route("/api/admin/adduser", methods=["POST"])
317+
@api_auth
308318
@admin_required
309319
def add_user():
310320
"""Change blocked status of a user
@@ -360,6 +370,7 @@ def add_user():
360370

361371

362372
@admin_bp.route("/api/admin/delete_users", methods=["POST"])
373+
@api_auth
363374
@admin_required
364375
def delete_users():
365376
"""Delete users data
@@ -411,6 +422,7 @@ def delete_users():
411422

412423

413424
@admin_bp.route("/api/admin/delete_files", methods=["POST"])
425+
@api_auth
414426
@admin_required
415427
def delete_files():
416428
"""Delete files
@@ -443,6 +455,7 @@ def delete_files():
443455

444456

445457
@admin_bp.route("/api/admin/delete_datasets", methods=["POST"])
458+
@api_auth
446459
@admin_required
447460
def delete_datasets():
448461
"""Delete some datasets (db and triplestore) with a celery task

askomics/api/auth.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ def decorated_function(*args, **kwargs):
2626
return decorated_function
2727

2828

29+
def api_auth(f):
30+
"""Get info from token"""
31+
@wraps(f)
32+
def decorated_function(*args, **kwargs):
33+
"""Login required decorator"""
34+
if request.headers.get("X-API-KEY"):
35+
key = request.headers.get("X-API-KEY")
36+
local_auth = LocalAuth(current_app, session)
37+
authentication = local_auth.authenticate_user_with_apikey(key)
38+
if not authentication["error"]:
39+
session["user"] = authentication["user"]
40+
return f(*args, **kwargs)
41+
42+
return decorated_function
43+
44+
2945
def admin_required(f):
3046
"""Login required function"""
3147
@wraps(f)
@@ -69,11 +85,17 @@ def signup():
6985
'error': True,
7086
'errorMessage': "Account creation is disabled",
7187
'user': {}
72-
}), 500
88+
}), 400
7389

7490
user = {}
7591

7692
data = request.get_json()
93+
if not data:
94+
return jsonify({
95+
'error': True,
96+
'errorMessage': "Missing parameters",
97+
'user': {}
98+
}), 400
7799

78100
local_auth = LocalAuth(current_app, session)
79101
local_auth.check_inputs(data)
@@ -100,6 +122,12 @@ def login():
100122
Information about the logged user
101123
"""
102124
data = request.get_json()
125+
if not (data and data.get("login") and data.get("password")):
126+
return jsonify({
127+
'error': True,
128+
'errorMessage': "Missing login or password",
129+
'user': None
130+
}), 400
103131

104132
local_auth = LocalAuth(current_app, session)
105133
authentication = local_auth.authenticate_user(data["login"], data["password"])
@@ -171,6 +199,11 @@ def update_profile():
171199
The updated user
172200
"""
173201
data = request.get_json()
202+
if not (data and any([key in data for key in ["newFname", "newLname", "newEmail"]])):
203+
return jsonify({
204+
"error": True,
205+
"errorMessage": "Missing parameters"
206+
}), 400
174207

175208
local_auth = LocalAuth(current_app, session)
176209
updated_user = local_auth.update_profile(data, session['user'])
@@ -195,6 +228,11 @@ def update_password():
195228
The user
196229
"""
197230
data = request.get_json()
231+
if not (data and all([key in data for key in ["oldPassword", "newPassword", "confPassword"]])):
232+
return jsonify({
233+
"error": True,
234+
"errorMessage": "Missing parameters"
235+
}), 400
198236

199237
local_auth = LocalAuth(current_app, session)
200238
updated_user = local_auth.update_password(data, session['user'])
@@ -238,6 +276,12 @@ def update_galaxy():
238276
The user with his new apikey
239277
"""
240278
data = request.get_json()
279+
if not (data and data.get("gurl") and data.get("gkey")):
280+
return jsonify({
281+
'error': True,
282+
'errorMessage': "Missing parameters",
283+
'user': session["user"]
284+
}), 400
241285

242286
local_auth = LocalAuth(current_app, session)
243287
if session["user"]["galaxy"]:
@@ -274,6 +318,11 @@ def logout():
274318
def reset_password():
275319
"""Reset password route"""
276320
data = request.get_json()
321+
if not data:
322+
return jsonify({
323+
"error": True,
324+
"errorMessage": "Missing parameters"
325+
}), 400
277326

278327
# Send a reset link
279328
if "login" in data:
@@ -318,7 +367,7 @@ def reset_password():
318367
})
319368

320369
# Update password
321-
else:
370+
elif all([key in data for key in ["token", "password", "passwordConf"]]):
322371
try:
323372
local_auth = LocalAuth(current_app, session)
324373
result = local_auth.reset_password_with_token(data["token"], data["password"], data["passwordConf"])
@@ -333,6 +382,11 @@ def reset_password():
333382
"error": result["error"],
334383
"errorMessage": result["message"]
335384
})
385+
else:
386+
return jsonify({
387+
"error": True,
388+
"errorMessage": "Missing parameters"
389+
}), 400
336390

337391

338392
@auth_bp.route("/api/auth/delete_account", methods=["GET"])

askomics/api/data.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""Api routes"""
2+
import urllib.parse
23
import sys
34
import traceback
45

6+
from askomics.api.auth import api_auth
57
from askomics.libaskomics.SparqlQuery import SparqlQuery
68
from askomics.libaskomics.SparqlQueryLauncher import SparqlQueryLauncher
79

@@ -12,6 +14,7 @@
1214

1315

1416
@data_bp.route('/api/data/<string:uri>', methods=['GET'])
17+
@api_auth
1518
def get_data(uri):
1619
"""Get information about uri
1720
@@ -33,10 +36,11 @@ def get_data(uri):
3336
# If the user do not have access to any endpoint (no viewable graph), skip
3437
if endpoints:
3538

39+
uri = urllib.parse.quote(uri)
3640
base_uri = current_app.iniconfig.get('triplestore', 'namespace_data')
3741
full_uri = "<%s%s>" % (base_uri, uri)
3842

39-
raw_query = "SELECT DISTINCT ?predicat ?object\nWHERE {\n%s ?predicat ?object\n}" % (full_uri)
43+
raw_query = "SELECT DISTINCT ?predicat ?object\nWHERE {\n?URI ?predicat ?object\nVALUES ?URI {%s}}\n" % (full_uri)
4044
federated = query.is_federated()
4145
replace_froms = query.replace_froms()
4246

0 commit comments

Comments
 (0)