Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/mavedb/lib/mave/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import re

import pandas as pd

NA_VALUE = "NA"

NULL_VALUES = ("", "na", "nan", "nil", "none", "null", "n/a", "undefined", NA_VALUE)
Expand All @@ -22,6 +24,9 @@

def is_csv_null(value):
"""Return True if a string from a CSV file represents a NULL value."""
# Avoid any boolean miscasts from comparisons by handling NA types up front.
if pd.isna(value):
return True
# Number 0 is treated as False so that all 0 will be converted to NA value.
if value == 0:
return value
Expand Down
26 changes: 19 additions & 7 deletions src/mavedb/lib/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ def has_permission(user_data: Optional[UserData], item: Base, action: Action) ->
elif private:
# Do not acknowledge the existence of a private entity.
return PermissionResponse(False, 404, f"experiment set with URN '{item.urn}' not found")
elif user_data is None or user_data.user is None:
return PermissionResponse(False, 401, f"insufficient permissions for URN '{item.urn}'")
else:
return PermissionResponse(False)
return PermissionResponse(False, 403, f"insufficient permissions for URN '{item.urn}'")
elif action == Action.UPDATE:
if user_may_edit:
return PermissionResponse(True)
Expand All @@ -106,8 +108,10 @@ def has_permission(user_data: Optional[UserData], item: Base, action: Action) ->
elif private:
# Do not acknowledge the existence of a private entity.
return PermissionResponse(False, 404, f"experiment set with URN '{item.urn}' not found")
elif user_data is None or user_data.user is None:
return PermissionResponse(False, 401, f"insufficient permissions for URN '{item.urn}'")
else:
return PermissionResponse(False)
return PermissionResponse(False, 403, f"insufficient permissions for URN '{item.urn}'")
elif action == Action.DELETE:
# Owner may only delete an experiment set if it has not already been published.
if user_may_edit:
Expand Down Expand Up @@ -143,8 +147,10 @@ def has_permission(user_data: Optional[UserData], item: Base, action: Action) ->
elif private:
# Do not acknowledge the existence of a private entity.
return PermissionResponse(False, 404, f"experiment with URN '{item.urn}' not found")
elif user_data is None or user_data.user is None:
return PermissionResponse(False, 401, f"insufficient permissions for URN '{item.urn}'")
else:
return PermissionResponse(False)
return PermissionResponse(False, 403, f"insufficient permissions for URN '{item.urn}'")
elif action == Action.UPDATE:
if user_may_edit:
return PermissionResponse(True)
Expand All @@ -154,8 +160,10 @@ def has_permission(user_data: Optional[UserData], item: Base, action: Action) ->
elif private:
# Do not acknowledge the existence of a private entity.
return PermissionResponse(False, 404, f"experiment with URN '{item.urn}' not found")
elif user_data is None or user_data.user is None:
return PermissionResponse(False, 401, f"insufficient permissions for URN '{item.urn}'")
else:
return PermissionResponse(False)
return PermissionResponse(False, 403, f"insufficient permissions for URN '{item.urn}'")
elif action == Action.DELETE:
# Owner may only delete an experiment if it has not already been published.
if user_may_edit:
Expand Down Expand Up @@ -191,8 +199,10 @@ def has_permission(user_data: Optional[UserData], item: Base, action: Action) ->
elif private:
# Do not acknowledge the existence of a private entity.
return PermissionResponse(False, 404, f"score set with URN '{item.urn}' not found")
elif user_data is None or user_data.user is None:
return PermissionResponse(False, 401, f"insufficient permissions for URN '{item.urn}'")
else:
return PermissionResponse(False)
return PermissionResponse(False, 403, f"insufficient permissions for URN '{item.urn}'")
elif action == Action.UPDATE:
if user_may_edit:
return PermissionResponse(True)
Expand All @@ -202,8 +212,10 @@ def has_permission(user_data: Optional[UserData], item: Base, action: Action) ->
elif private:
# Do not acknowledge the existence of a private entity.
return PermissionResponse(False, 404, f"score set with URN '{item.urn}' not found")
elif user_data is None or user_data.user is None:
return PermissionResponse(False, 401, f"insufficient permissions for URN '{item.urn}'")
else:
return PermissionResponse(False)
return PermissionResponse(False, 403, f"insufficient permissions for URN '{item.urn}'")
elif action == Action.DELETE:
# Owner may only delete a score set if it has not already been published.
if user_may_edit:
Expand Down Expand Up @@ -247,7 +259,7 @@ def has_permission(user_data: Optional[UserData], item: Base, action: Action) ->
elif roles_permitted(active_roles, [UserRole.admin]):
return PermissionResponse(True)
else:
return PermissionResponse(False)
return PermissionResponse(False, 403, "Insufficient permissions for user update.")
elif action == Action.UPDATE:
if user_is_self:
return PermissionResponse(True)
Expand Down
10 changes: 7 additions & 3 deletions src/mavedb/routers/score_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -854,9 +854,13 @@ async def update_score_set(
scores_data = pd.DataFrame(
variants_to_csv_rows(item.variants, columns=score_columns, dtype="score_data")
).replace("NA", pd.NA)
count_data = pd.DataFrame(
variants_to_csv_rows(item.variants, columns=count_columns, dtype="count_data")
).replace("NA", pd.NA)

if item.dataset_columns["count_columns"]:
count_data = pd.DataFrame(
variants_to_csv_rows(item.variants, columns=count_columns, dtype="count_data")
).replace("NA", pd.NA)
else:
count_data = None

# Although this is also updated within the variant creation job, update it here
# as well so that we can display the proper UI components (queue invocation delay
Expand Down
5 changes: 5 additions & 0 deletions src/mavedb/routers/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,11 @@ def record_object_statistics(
Model names and fields should be members of the Enum classes defined above. Providing an invalid model name or
model field will yield a 422 Unprocessable Entity error with details about valid enum values.
"""
# Validation to ensure 'keywords' is only used with 'experiment'.
if model == RecordNames.scoreSet and field == RecordFields.keywords:
raise HTTPException(status_code=422,
detail="The 'keywords' field can only be used with the 'experiment' model.")

count_data = _record_from_field_and_model(db, model, field)

return {field_val: count for field_val, count in count_data if field_val is not None}