22import io
33import logging
44import re
5- from typing import Any , BinaryIO , Iterable , Optional , Sequence
5+ from operator import attrgetter
6+ from typing import Any , BinaryIO , Iterable , Optional , TYPE_CHECKING , Sequence
67
78import numpy as np
89import pandas as pd
4344from mavedb .models .taxonomy import Taxonomy
4445from mavedb .models .uniprot_identifier import UniprotIdentifier
4546from mavedb .models .uniprot_offset import UniprotOffset
46- from mavedb .models .user import User
4747from mavedb .models .variant import Variant
4848from mavedb .view_models .search import ScoreSetsSearch
4949
50+ if TYPE_CHECKING :
51+ from mavedb .lib .authentication import UserData
52+ from mavedb .lib .permissions import Action
53+
5054VariantData = dict [str , Optional [dict [str , dict ]]]
5155
5256logger = logging .getLogger (__name__ )
@@ -62,20 +66,19 @@ def options(cls) -> list[str]:
6266 return [cls .NUCLEOTIDE , cls .TRANSCRIPT , cls .PROTEIN ]
6367
6468
65- def search_score_sets (db : Session , owner_or_contributor : Optional [User ], search : ScoreSetsSearch ) -> list [ScoreSet ]:
69+ def search_score_sets (db : Session , owner_or_contributor : Optional ["UserData" ], search : ScoreSetsSearch ) -> list [ScoreSet ]:
70+ # Prevent circular import
71+ from mavedb .lib .permissions import Action
6672 save_to_logging_context ({"score_set_search_criteria" : search .dict ()})
6773
6874 query = db .query (ScoreSet ) # \
6975 # .filter(ScoreSet.private.is_(False))
7076
71- # filter out the score sets that are replaced by other score sets
72- query = query .filter (~ ScoreSet .superseding_score_set .has ())
73-
7477 if owner_or_contributor is not None :
7578 query = query .filter (
7679 or_ (
77- ScoreSet .created_by_id == owner_or_contributor .id ,
78- ScoreSet .contributors .any (Contributor .orcid_id == owner_or_contributor .username ),
80+ ScoreSet .created_by_id == owner_or_contributor .user . id ,
81+ ScoreSet .contributors .any (Contributor .orcid_id == owner_or_contributor .user . username ),
7982 )
8083 )
8184
@@ -253,13 +256,36 @@ def search_score_sets(db: Session, owner_or_contributor: Optional[User], search:
253256 .order_by (Experiment .title )
254257 .all ()
255258 )
259+ # Remove superseded score set
256260 if not score_sets :
257- score_sets = []
258-
259- save_to_logging_context ({"matching_resources" : len (score_sets )})
260- logger .debug (msg = f"Score set search yielded { len (score_sets )} matching resources." , extra = logging_context ())
261+ final_score_sets : list [ScoreSet ] = []
262+ else :
263+ published_filter = search .published if search .published is not None else None
264+ print (len (score_sets ))
265+ filtered_score_sets = [
266+ find_superseded_score_set_tail (
267+ score_set ,
268+ Action .READ ,
269+ owner_or_contributor ,
270+ published_filter
271+ ) for score_set in score_sets
272+ ]
273+ print (len (filtered_score_sets ))
274+ # Remove None item.
275+ filtered_score_sets = [score_set for score_set in filtered_score_sets if score_set is not None ]
276+ print (len (filtered_score_sets ))
277+ if filtered_score_sets :
278+ # final_score_sets = sorted(set(filtered_score_sets), key=attrgetter("urn"))
279+ final_score_sets = filtered_score_sets .sort (key = attrgetter ("urn" ))
280+ for f in filtered_score_sets :
281+ print (f .urn )
282+ else :
283+ final_score_sets = []
261284
262- return score_sets # filter_visible_score_sets(score_sets)
285+ save_to_logging_context ({"matching_resources" : len (final_score_sets )})
286+ logger .debug (msg = f"Score set search yielded { len (final_score_sets )} matching resources." , extra = logging_context ())
287+ print (len (final_score_sets ))
288+ return final_score_sets # filter_visible_score_sets(score_sets)
263289
264290
265291def find_meta_analyses_for_experiment_sets (db : Session , urns : list [str ]) -> list [ScoreSet ]:
@@ -306,6 +332,54 @@ def find_meta_analyses_for_experiment_sets(db: Session, urns: list[str]) -> list
306332 )
307333
308334
335+ def find_superseded_score_set_tail (
336+ score_set : ScoreSet ,
337+ action : Optional ["Action" ] = None ,
338+ user_data : Optional ["UserData" ] = None ,
339+ publish : Optional [bool ] = None ) -> Optional [ScoreSet ]:
340+ from mavedb .lib .permissions import has_permission
341+ if publish is not None :
342+ if publish is True :
343+ while score_set .superseding_score_set is not None :
344+ next_score_set_in_chain = score_set .superseding_score_set
345+ # Find the final published one.
346+ if action is not None and has_permission (user_data , score_set , action ).permitted \
347+ and next_score_set_in_chain .published_date is None :
348+ return score_set
349+ score_set = next_score_set_in_chain
350+ else :
351+ # Unpublished score set should not be superseded.
352+ # It should not have superseding score set, but possible have superseded score set.
353+ if action is not None and score_set .published_date is None \
354+ and has_permission (user_data , score_set , action ).permitted :
355+ return score_set
356+ else :
357+ return None
358+ else :
359+ while score_set .superseding_score_set is not None :
360+ next_score_set_in_chain = score_set .superseding_score_set
361+
362+ # If we were given a permission to check and the next score set in the chain does not have that permission,
363+ # pretend like we have reached the end of the chain. Otherwise, continue to the next score set.
364+ if action is not None and not has_permission (user_data , next_score_set_in_chain , action ).permitted :
365+ return score_set
366+
367+ score_set = next_score_set_in_chain
368+
369+ # Handle unpublished superseding score set case.
370+ # The score set has superseded score set but has not superseding score set.
371+ if action is not None and not has_permission (user_data , score_set , action ).permitted :
372+ while score_set .superseded_score_set is not None :
373+ next_score_set_in_chain = score_set .superseded_score_set
374+ if has_permission (user_data , next_score_set_in_chain , action ).permitted :
375+ return next_score_set_in_chain
376+ else :
377+ score_set = next_score_set_in_chain
378+ return None
379+
380+ return score_set
381+
382+
309383def get_score_set_counts_as_csv (
310384 db : Session ,
311385 score_set : ScoreSet ,
0 commit comments