Skip to content
Open
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
8 changes: 1 addition & 7 deletions src/mavedb/lib/authentication.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import os
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Optional
Expand All @@ -19,6 +18,7 @@
from mavedb import deps
from mavedb.lib.logging.context import format_raised_exception_info_as_dict, logging_context, save_to_logging_context
from mavedb.lib.orcid import fetch_orcid_user_email
from mavedb.lib.types.authentication import UserData
from mavedb.models.access_key import AccessKey
from mavedb.models.enums.user_role import UserRole
from mavedb.models.user import User
Expand All @@ -45,12 +45,6 @@ class AuthenticationMethod(str, Enum):
jwt = "jwt"


@dataclass
class UserData:
user: User
active_roles: list[UserRole]


####################################################################################################
# JWT authentication
####################################################################################################
Expand Down
3 changes: 2 additions & 1 deletion src/mavedb/lib/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

from fastapi import Depends, HTTPException

from mavedb.lib.authentication import UserData, get_current_user
from mavedb.lib.authentication import get_current_user
from mavedb.lib.logging.context import logging_context, save_to_logging_context
from mavedb.lib.types.authentication import UserData
from mavedb.models.enums.user_role import UserRole

logger = logging.getLogger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions src/mavedb/lib/experiments.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import logging
from typing import Optional

from sqlalchemy import func, or_, not_
from sqlalchemy import func, not_, or_
from sqlalchemy.orm import Session

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import logging_context, save_to_logging_context
from mavedb.lib.permissions import Action
from mavedb.lib.score_sets import find_superseded_score_set_tail
from mavedb.lib.types.authentication import UserData
from mavedb.models.contributor import Contributor
from mavedb.models.controlled_keyword import ControlledKeyword
from mavedb.models.experiment import Experiment
Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/collection.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Optional

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import save_to_logging_context
from mavedb.lib.permissions.actions import Action
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.permissions.utils import deny_action_for_entity, roles_permitted
from mavedb.lib.types.authentication import UserData
from mavedb.models.collection import Collection
from mavedb.models.enums.contribution_role import ContributionRole
from mavedb.models.enums.user_role import UserRole
Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/core.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Any, Callable, Optional

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import save_to_logging_context
from mavedb.lib.permissions.actions import Action
from mavedb.lib.permissions.exceptions import PermissionException
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.types.authentication import UserData
from mavedb.lib.types.permissions import EntityType
from mavedb.models.collection import Collection
from mavedb.models.experiment import Experiment
Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/experiment.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Optional

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import save_to_logging_context
from mavedb.lib.permissions.actions import Action
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.permissions.utils import deny_action_for_entity, roles_permitted
from mavedb.lib.types.authentication import UserData
from mavedb.models.enums.user_role import UserRole
from mavedb.models.experiment import Experiment

Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/experiment_set.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Optional

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import save_to_logging_context
from mavedb.lib.permissions.actions import Action
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.permissions.utils import deny_action_for_entity, roles_permitted
from mavedb.lib.types.authentication import UserData
from mavedb.models.enums.user_role import UserRole
from mavedb.models.experiment_set import ExperimentSet

Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/score_calibration.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Optional

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import save_to_logging_context
from mavedb.lib.permissions.actions import Action
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.permissions.utils import deny_action_for_entity, roles_permitted
from mavedb.lib.types.authentication import UserData
from mavedb.models.enums.user_role import UserRole
from mavedb.models.score_calibration import ScoreCalibration

Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/score_set.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Optional

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import save_to_logging_context
from mavedb.lib.permissions.actions import Action
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.permissions.utils import deny_action_for_entity, roles_permitted
from mavedb.lib.types.authentication import UserData
from mavedb.models.enums.user_role import UserRole
from mavedb.models.score_set import ScoreSet

Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/user.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Optional

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import save_to_logging_context
from mavedb.lib.permissions.actions import Action
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.permissions.utils import deny_action_for_entity, roles_permitted
from mavedb.lib.types.authentication import UserData
from mavedb.models.enums.user_role import UserRole
from mavedb.models.user import User

Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/lib/permissions/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import logging
from typing import Optional, Union, overload

from mavedb.lib.authentication import UserData
from mavedb.lib.logging.context import logging_context, save_to_logging_context
from mavedb.lib.permissions.models import PermissionResponse
from mavedb.lib.types.authentication import UserData
from mavedb.lib.types.permissions import EntityType
from mavedb.models.enums.contribution_role import ContributionRole
from mavedb.models.enums.user_role import UserRole
Expand Down
33 changes: 24 additions & 9 deletions src/mavedb/lib/score_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
VARIANT_SCORE_DATA,
)
from mavedb.lib.mave.utils import is_csv_null
from mavedb.lib.permissions import Action, has_permission
from mavedb.lib.types.authentication import UserData
from mavedb.lib.validation.constants.general import null_values_list
from mavedb.lib.validation.utilities import is_null as validate_is_null
from mavedb.lib.variants import get_digest_from_post_mapped, get_hgvs_from_post_mapped, is_hgvs_g, is_hgvs_p
Expand Down Expand Up @@ -55,7 +57,6 @@
from mavedb.view_models.search import ScoreSetsSearch

if TYPE_CHECKING:
from mavedb.lib.authentication import UserData
from mavedb.lib.permissions import Action

VariantData = dict[str, Optional[dict[str, dict]]]
Expand Down Expand Up @@ -298,21 +299,40 @@ def score_set_search_filter_options_from_counter(counter: Counter):
return [{"value": value, "count": count} for value, count in counter.items()]


def fetch_score_set_search_filter_options(db: Session, owner_or_contributor: Optional[User], search: ScoreSetsSearch):
def fetch_score_set_search_filter_options(
db: Session, requester: Optional[UserData], owner_or_contributor: Optional[User], search: ScoreSetsSearch
):
save_to_logging_context({"score_set_search_criteria": search.model_dump()})

query = db.query(ScoreSet)
query = build_search_score_sets_query_filter(db, query, owner_or_contributor, search)

score_sets: list[ScoreSet] = query.all()
if not score_sets:
score_sets = []

# Target related counters
target_category_counter: Counter[str] = Counter()
target_name_counter: Counter[str] = Counter()
target_organism_name_counter: Counter[str] = Counter()
target_accession_counter: Counter[str] = Counter()
# Publication related counters
publication_author_name_counter: Counter[str] = Counter()
publication_db_name_counter: Counter[str] = Counter()
publication_journal_counter: Counter[str] = Counter()

# --- PERFORMANCE NOTE ---
# The following counter construction loop is a bottleneck for large score set queries.
# Practical future optimizations might include:
# - Batch permission checks and attribute access outside the loop if possible
# - Use parallelization (e.g., multiprocessing or concurrent.futures) for large datasets
# - Pre-fetch or denormalize target/publication data in the DB query
# - Profile and refactor nested attribute lookups to minimize Python overhead
for score_set in score_sets:
# Check read permission for each score set, skip if no permission
if not has_permission(requester, score_set, Action.READ).permitted:
continue

# Target related options
for target in getattr(score_set, "target_genes", []):
category = getattr(target, "category", None)
if category:
Expand All @@ -335,10 +355,7 @@ def fetch_score_set_search_filter_options(db: Session, owner_or_contributor: Opt
if accession:
target_accession_counter[accession] += 1

publication_author_name_counter: Counter[str] = Counter()
publication_db_name_counter: Counter[str] = Counter()
publication_journal_counter: Counter[str] = Counter()
for score_set in score_sets:
# Publication related options
for publication_association in getattr(score_set, "publication_identifier_associations", []):
publication = getattr(publication_association, "publication", None)

Expand Down Expand Up @@ -443,8 +460,6 @@ def find_meta_analyses_for_experiment_sets(db: Session, urns: list[str]) -> list
def find_superseded_score_set_tail(
score_set: ScoreSet, action: Optional["Action"] = None, user_data: Optional["UserData"] = None
) -> Optional[ScoreSet]:
from mavedb.lib.permissions import has_permission

while score_set.superseding_score_set is not None:
next_score_set_in_chain = score_set.superseding_score_set

Expand Down
12 changes: 12 additions & 0 deletions src/mavedb/lib/types/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from mavedb.models.enums.user_role import UserRole
from mavedb.models.user import User


@dataclass
class UserData:
user: "User"
active_roles: list["UserRole"]
2 changes: 1 addition & 1 deletion src/mavedb/routers/access_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
from sqlalchemy.orm import Session

from mavedb import deps
from mavedb.lib.authentication import UserData
from mavedb.lib.authorization import require_current_user
from mavedb.lib.logging import LoggedRoute
from mavedb.lib.logging.context import logging_context, save_to_logging_context
from mavedb.lib.types.authentication import UserData
from mavedb.models.access_key import AccessKey
from mavedb.models.enums.user_role import UserRole
from mavedb.routers.shared import ACCESS_CONTROL_ERROR_RESPONSES, PUBLIC_ERROR_RESPONSES, ROUTER_BASE_PREFIX
Expand Down
3 changes: 2 additions & 1 deletion src/mavedb/routers/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound

from mavedb import deps
from mavedb.lib.authentication import UserData, get_current_user
from mavedb.lib.authentication import get_current_user
from mavedb.lib.authorization import require_current_user, require_current_user_with_email
from mavedb.lib.logging import LoggedRoute
from mavedb.lib.logging.context import (
Expand All @@ -18,6 +18,7 @@
save_to_logging_context,
)
from mavedb.lib.permissions import Action, assert_permission, has_permission
from mavedb.lib.types.authentication import UserData
from mavedb.models.collection import Collection
from mavedb.models.collection_user_association import CollectionUserAssociation
from mavedb.models.enums.contribution_role import ContributionRole
Expand Down
3 changes: 2 additions & 1 deletion src/mavedb/routers/experiment_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
from sqlalchemy.orm import Session

from mavedb import deps
from mavedb.lib.authentication import UserData, get_current_user
from mavedb.lib.authentication import get_current_user
from mavedb.lib.experiments import enrich_experiment_with_num_score_sets
from mavedb.lib.logging import LoggedRoute
from mavedb.lib.logging.context import logging_context, save_to_logging_context
from mavedb.lib.permissions import Action, assert_permission, has_permission
from mavedb.lib.types.authentication import UserData
from mavedb.models.experiment_set import ExperimentSet
from mavedb.routers.shared import ACCESS_CONTROL_ERROR_RESPONSES, PUBLIC_ERROR_RESPONSES, ROUTER_BASE_PREFIX
from mavedb.view_models import experiment_set
Expand Down
3 changes: 2 additions & 1 deletion src/mavedb/routers/experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from sqlalchemy.orm import Session

from mavedb import deps
from mavedb.lib.authentication import UserData, get_current_user
from mavedb.lib.authentication import get_current_user
from mavedb.lib.authorization import require_current_user, require_current_user_with_email
from mavedb.lib.contributors import find_or_create_contributor
from mavedb.lib.exceptions import NonexistentOrcidUserError
Expand All @@ -25,6 +25,7 @@
from mavedb.lib.logging.context import logging_context, save_to_logging_context
from mavedb.lib.permissions import Action, assert_permission, has_permission
from mavedb.lib.score_sets import find_superseded_score_set_tail
from mavedb.lib.types.authentication import UserData
from mavedb.lib.validation.exceptions import ValidationError
from mavedb.lib.validation.keywords import validate_keyword_list
from mavedb.models.contributor import Contributor
Expand Down
2 changes: 1 addition & 1 deletion src/mavedb/routers/mapped_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
variant_study_result,
)
from mavedb.lib.annotation.exceptions import MappingDataDoesntExistException
from mavedb.lib.authentication import UserData
from mavedb.lib.authorization import get_current_user
from mavedb.lib.logging import LoggedRoute
from mavedb.lib.logging.context import (
logging_context,
save_to_logging_context,
)
from mavedb.lib.permissions import Action, assert_permission, has_permission
from mavedb.lib.types.authentication import UserData
from mavedb.models.mapped_variant import MappedVariant
from mavedb.models.variant import Variant
from mavedb.routers.shared import ACCESS_CONTROL_ERROR_RESPONSES, PUBLIC_ERROR_RESPONSES, ROUTER_BASE_PREFIX
Expand Down
3 changes: 2 additions & 1 deletion src/mavedb/routers/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
from sqlalchemy.orm import Session

from mavedb import deps
from mavedb.lib.authentication import UserData, get_current_user
from mavedb.lib.authentication import get_current_user
from mavedb.lib.logging import LoggedRoute
from mavedb.lib.logging.context import logging_context, save_to_logging_context
from mavedb.lib.permissions import Action, has_permission
from mavedb.lib.types.authentication import UserData
from mavedb.models.collection import Collection
from mavedb.models.experiment import Experiment
from mavedb.models.experiment_set import ExperimentSet
Expand Down
3 changes: 2 additions & 1 deletion src/mavedb/routers/score_calibrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy.orm import Session, selectinload

from mavedb import deps
from mavedb.lib.authentication import UserData, get_current_user
from mavedb.lib.authentication import get_current_user
from mavedb.lib.authorization import require_current_user
from mavedb.lib.logging import LoggedRoute
from mavedb.lib.logging.context import (
Expand All @@ -21,6 +21,7 @@
promote_score_calibration_to_primary,
publish_score_calibration,
)
from mavedb.lib.types.authentication import UserData
from mavedb.models.score_calibration import ScoreCalibration
from mavedb.models.score_set import ScoreSet
from mavedb.view_models import score_calibration
Expand Down
5 changes: 3 additions & 2 deletions src/mavedb/routers/score_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
variant_study_result,
)
from mavedb.lib.annotation.exceptions import MappingDataDoesntExistException
from mavedb.lib.authentication import UserData
from mavedb.lib.authorization import (
get_current_user,
require_current_user,
Expand Down Expand Up @@ -61,6 +60,7 @@
)
from mavedb.lib.target_genes import find_or_create_target_gene_by_accession, find_or_create_target_gene_by_sequence
from mavedb.lib.taxonomies import find_or_create_taxonomy
from mavedb.lib.types.authentication import UserData
from mavedb.lib.urns import (
generate_experiment_set_urn,
generate_experiment_urn,
Expand Down Expand Up @@ -598,8 +598,9 @@ def search_score_sets(
def get_filter_options_for_search(
search: ScoreSetsSearch,
db: Session = Depends(deps.get_db),
user_data: Optional[UserData] = Depends(get_current_user),
) -> Any:
return fetch_score_set_search_filter_options(db, None, search)
return fetch_score_set_search_filter_options(db, user_data, None, search)


@router.get(
Expand Down
3 changes: 2 additions & 1 deletion src/mavedb/routers/target_genes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
from sqlalchemy.orm import Session, selectinload

from mavedb import deps
from mavedb.lib.authentication import UserData, get_current_user
from mavedb.lib.authentication import get_current_user
from mavedb.lib.authorization import require_current_user
from mavedb.lib.permissions import Action, has_permission
from mavedb.lib.score_sets import find_superseded_score_set_tail
from mavedb.lib.target_genes import (
search_target_genes as _search_target_genes,
)
from mavedb.lib.types.authentication import UserData
from mavedb.models.score_set import ScoreSet
from mavedb.models.target_gene import TargetGene
from mavedb.routers.shared import ACCESS_CONTROL_ERROR_RESPONSES, PUBLIC_ERROR_RESPONSES, ROUTER_BASE_PREFIX
Expand Down
Loading