async def patch_protocol( protocol_id: int, patch: list, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): if not check_access(enforcer, user=current_user.username, path=f"/protocol/{str(protocol_id)}", method="PUT"): raise HTTPException(status_code=403, detail='Insufficient Permissions') new_protocol = db.query(Protocol).get(protocol_id) if not new_protocol or new_protocol.is_deleted: raise HTTPException(status_code=404, detail='Protocol Not Found') protocol_dict = versioned_row_to_dict(new_protocol, new_protocol.current) json_patch = jsonpatch.JsonPatch(patch) protocol_dict = json_patch.apply(protocol_dict) if not change_allowed( versioned_row_to_dict(new_protocol, new_protocol.current), protocol_dict): raise HTTPException(status_code=403, detail='Insufficient Permissions') new_protocol_version = ProtocolVersion( data=strip_metadata(protocol_dict), server_version=settings.server_version) new_protocol_version.protocol = new_protocol add_updator(new_protocol_version, current_user.username) new_protocol.current = new_protocol_version db.add(new_protocol_version) db.commit() return versioned_row_to_dict(new_protocol, new_protocol.current)
async def get_protocols( run: Optional[int] = None, plate: Optional[str] = None, reagent: Optional[str] = None, sample: Optional[str] = None, creator: Optional[str] = None, archived: Optional[bool] = None, page: Optional[int] = None, per_page: Optional[int] = None, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): return crud_get_protocols( item_to_dict=lambda protocol: versioned_row_to_dict( protocol, protocol.current, include_large_fields=False), enforcer=enforcer, db=db, current_user=current_user, run=run, plate=plate, reagent=reagent, sample=sample, creator=creator, archived=archived, page=page, per_page=per_page, )
async def create_user( user: UserModel, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): user_dict = user.dict() # Drop the roles field if it was provided. user_dict.pop('roles', None) new_user = User(id=current_user.username if current_user.username else 42) new_user_version = UserVersion(data=strip_metadata(user_dict), server_version=settings.server_version) new_user_version.user = new_user new_user.current = new_user_version add_owner(new_user, current_user.username) db.add_all([new_user, new_user_version]) db.commit() add_policy(enforcer, user=current_user.username, path=f"/user/{str(new_user.id)}", method="GET") add_policy(enforcer, user=current_user.username, path=f"/user/{str(new_user.id)}", method="PUT") return add_role(enforcer, versioned_row_to_dict(new_user, new_user_version))
async def create_protocol( protocol: ProtocolModel, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): protocol_dict = protocol.dict() protocol = Protocol() protocol_version = ProtocolVersion(data=strip_metadata(protocol_dict), server_version=settings.server_version) protocol_version.protocol = protocol protocol.current = protocol_version add_owner(protocol, current_user.username) db.add_all([protocol, protocol_version]) db.commit() add_policy(enforcer, user=current_user.username, path=f"/protocol/{str(protocol.id)}", method="GET") add_policy(enforcer, user=current_user.username, path=f"/protocol/{str(protocol.id)}", method="PUT") add_policy(enforcer, user=current_user.username, path=f"/protocol/{str(protocol.id)}", method="DELETE") return versioned_row_to_dict(protocol, protocol_version)
def get_node(cls, info: ResolveInfo, id): db = get_session(info) row = db.query(cls._meta.db_model)\ .filter(and_( cls._meta.db_model.is_deleted != True, cls._meta.db_model.id == id, ))\ .first() return cls._meta.model.parse_obj(versioned_row_to_dict(row, row.current))
def resolve_all_users( root, info: ResolveInfo, # Search parameters archived: Optional[bool] = None, # Paging parameters page: Optional[int] = None, per_page: Optional[int] = None, # Currently unused before: Optional[str] = None, after: Optional[str] = None, first: Optional[int] = None, last: Optional[int] = None, ): enforcer = get_enforcer_from_request(info.context['request']) current_user = get_current_user_from_request(info.context['request']) if current_user is None: raise HTTPException(401, "Unauthorized") db = get_session(info) pagination_dict = crud_get_users( item_to_dict=lambda user: add_ids(versioned_row_to_dict(user, user.current), user_id=user.id), enforcer=enforcer, db=db, current_user=current_user, archived=archived, page=page, per_page=per_page, ) return UserConnection( page=pagination_dict.get('page', None), pageCount=pagination_dict.get('pageCount', None), edges=[ UserConnection.Edge( node=UserModel.parse_obj(r), cursor=f"{pagination_dict.get('page', 1)}.{i}", ) for i, r in enumerate(pagination_dict['users']) ], page_info=relay.PageInfo( has_next_page=pagination_dict.get('page', 1) < pagination_dict.get('pageCount', 1), has_previous_page=pagination_dict.get('page', 1) > pagination_dict.get('pageCount', 1), start_cursor="1.0", end_cursor=f"1.{len(pagination_dict['users'])}" if pagination_dict.get('pageCount', None) is None else f"{pagination_dict['pageCount']}.{len(pagination_dict['users'])}", ), )
def put(self, protocol_id): protocol_dict = request.json protocol = Protocol.query.get(protocol_id) if not protocol or protocol.is_deleted: abort(404) return if not change_allowed( versioned_row_to_dict(api, protocol, protocol.current), protocol_dict): abort(403) return protocol_version = ProtocolVersion( data=strip_metadata(protocol_dict), server_version=app.config['SERVER_VERSION']) protocol_version.protocol = protocol add_updator(protocol_version) protocol.current = protocol_version db.session.add(protocol_version) db.session.commit() return versioned_row_to_dict(api, protocol, protocol.current)
def get(self, protocol_id): version_id = int(request.args.get('version_id')) if request.args.get( 'version_id') else None if version_id: protocol_version = ProtocolVersion.query\ .filter(ProtocolVersion.id == version_id)\ .filter(Protocol.id == protocol_id)\ .first() if (not protocol_version) or protocol_version.protocol.is_deleted: abort(404) return return versioned_row_to_dict(api, protocol_version.protocol, protocol_version) protocol = Protocol.query.get(protocol_id) if (not protocol) or protocol.is_deleted: abort(404) return return versioned_row_to_dict(api, protocol, protocol.current)
def get(self, user_id): user_id = urllib.parse.unquote(user_id) version_id = int(request.args.get('version_id')) if request.args.get( 'version_id') else None if version_id: user_version = UserVersion.query\ .filter(UserVersion.id == version_id)\ .filter(User.id == user_id)\ .first() if (not user_version) or user_version.user.is_deleted: abort(404) return return add_role( versioned_row_to_dict(api, user_version.user, user_version)) user = User.query.get(user_id) if (not user) or user.is_deleted: abort(404) return return add_role(versioned_row_to_dict(api, user, user.current))
async def get_user( user_id: str, version_id: Optional[int] = None, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): return crud_get_user( item_to_dict=lambda user: add_role( enforcer, versioned_row_to_dict(user, user.current)), enforcer=enforcer, db=db, current_user=current_user, user_id=user_id, version_id=version_id, )
def post(self): protocol_dict = request.json protocol = Protocol() protocol_version = ProtocolVersion( data=strip_metadata(protocol_dict), server_version=app.config['SERVER_VERSION']) protocol_version.protocol = protocol protocol.current = protocol_version add_owner(protocol) db.session.add_all([protocol, protocol_version]) db.session.commit() add_policy(path=f"/protocol/{str(protocol.id)}", method="GET") add_policy(path=f"/protocol/{str(protocol.id)}", method="PUT") add_policy(path=f"/protocol/{str(protocol.id)}", method="DELETE") return versioned_row_to_dict(api, protocol, protocol_version)
async def get_protocol( protocol_id: int, version_id: Optional[int] = None, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): return crud_get_protocol( item_to_dict=lambda protocol: versioned_row_to_dict( protocol, protocol.current), enforcer=enforcer, db=db, current_user=current_user, protocol_id=protocol_id, version_id=version_id, )
def resolve_owner(root, info): enforcer = get_enforcer_from_request(info.context['request']) current_user = get_current_user_from_request(info.context['request']) if current_user is None: raise HTTPException(401, "Unauthorized") db = get_session(info) return UserModel.parse_obj( crud_get_user( item_to_dict=lambda user: add_ids(versioned_row_to_dict(user, user.current), user_id=user.id), enforcer=enforcer, db=db, current_user=current_user, user_id=root.created_by, ), )
def post(self): user_dict = request.json # Drop the roles field if it was provided. user_dict.pop('roles', None) user = User(id=request.current_user["sub"] if request. current_user["sub"] else 42) user_version = UserVersion(data=strip_metadata(user_dict), server_version=app.config['SERVER_VERSION']) user_version.user = user user.current = user_version add_owner(user) db.session.add_all([user, user_version]) db.session.commit() add_policy(path=f"/user/{str(user.id)}", method="GET") add_policy(path=f"/user/{str(user.id)}", method="PUT") return add_role(versioned_row_to_dict(api, user, user_version))
async def get_users( page: Optional[int] = None, per_page: Optional[int] = None, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user), ): return crud_get_users( item_to_dict=lambda user: add_role( enforcer, versioned_row_to_dict(user, user.current)), enforcer=enforcer, db=db, current_user=current_user, archived=False, page=page, per_page=per_page, )
def resolve_samples( root, info: ResolveInfo, # Paging parameters page: Optional[int] = None, per_page: Optional[int] = None, ): enforcer = get_enforcer_from_request(info.context['request']) current_user = get_current_user_from_request(info.context['request']) if current_user is None: raise HTTPException(401, "Unauthorized") db = get_session(info) pagination_dict = crud_get_run_samples( item_to_dict=lambda sample: versioned_row_to_dict(sample, sample.current), enforcer=enforcer, db=db, current_user=current_user, run_id=root.run_id, page=page, per_page=per_page, ) return SampleConnection( page=pagination_dict.get('page', None), pageCount=pagination_dict.get('pageCount', None), edges=[ SampleConnection.Edge( node=SampleResult.parse_obj(r), cursor=f"{pagination_dict.get('page', 1)}.{i}", ) for i, r in enumerate(pagination_dict['samples']) ], page_info=relay.PageInfo( has_next_page=pagination_dict.get('page', 1) < pagination_dict.get('pageCount', 1), has_previous_page=pagination_dict.get('page', 1) > pagination_dict.get('pageCount', 1), start_cursor="1.0", end_cursor=f"1.{len(pagination_dict['samples'])}" if pagination_dict.get('pageCount', None) is None else f"{pagination_dict['pageCount']}.{len(pagination_dict['samples'])}", ), )
def resolve_protocol(root, info: ResolveInfo, id: int, version_id: Optional[int]): enforcer = get_enforcer_from_request(info.context['request']) current_user = get_current_user_from_request(info.context['request']) if current_user is None: raise HTTPException(401, "Unauthorized") db = get_session(info) model_dict = crud_get_protocol( item_to_dict=lambda protocol: add_ids(versioned_row_to_dict(protocol, protocol.current), protocol_id=protocol.id), enforcer=enforcer, db=db, current_user=current_user, protocol_id=id, version_id=version_id, ) return ProtocolModel.parse_obj(model_dict)
def resolve_user(root, info: ResolveInfo, id: str, version_id: Optional[int]): enforcer = get_enforcer_from_request(info.context['request']) current_user = get_current_user_from_request(info.context['request']) if current_user is None: raise HTTPException(401, "Unauthorized") db = get_session(info) model_dict = crud_get_user( item_to_dict=lambda user: add_ids(versioned_row_to_dict(user, user.current), user_id=user.id), enforcer=enforcer, db=db, current_user=current_user, user_id=id, version_id=version_id, ) return UserModel.parse_obj(model_dict)
def put(self, user_id): user_id = urllib.parse.unquote(user_id) user_dict = request.json # Drop the roles field if it was provided. user_dict.pop('roles', None) user_dict = request.json user = User.query.get(user_id) if not user or user.is_deleted: abort(404) return user_version = UserVersion(data=strip_metadata(user_dict), server_version=app.config['SERVER_VERSION']) user_version.user = user add_updator(user_version) user.current = user_version db.session.add(user_version) db.session.commit() return add_role(versioned_row_to_dict(api, user, user.current))
def resolve_sample(root, info: ResolveInfo, sample_id: str, plate_id: str, run_version_id: int, protocol_version_id: int, version_id: Optional[int]): enforcer = get_enforcer_from_request(info.context['request']) current_user = get_current_user_from_request(info.context['request']) if current_user is None: raise HTTPException(401, "Unauthorized") db = get_session(info) model_dict = crud_get_sample( item_to_dict=lambda sample: versioned_row_to_dict(sample, sample.current), enforcer=enforcer, db=db, current_user=current_user, sample_id=sample_id, plate_id=plate_id, run_version_id=run_version_id, protocol_version_id=protocol_version_id, version_id=version_id, ) return SampleResult.parse_obj(model_dict)
def get(self): results = {} if request.args.get('page') is not None or request.args.get( 'per_page') is not None: page = int( request.args.get('page')) if request.args.get('page') else 1 per_page = int(request.args.get('per_page')) if request.args.get( 'per_page') else 20 page_query = User.query.filter(User.is_deleted != True).paginate( page=page, per_page=per_page) results['page'] = page_query.page results['pageCount'] = page_query.pages query = page_query.items else: query = User.query.filter(User.is_deleted != True).all() results['users'] = [ add_role(versioned_row_to_dict(api, user, user.current)) for user in query if check_access(path=f"/user/{user.id}", method="GET") ] return results
async def update_user( user_id: str, user: UserModel, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): user_id = urllib.parse.unquote(user_id) user_dict = user.dict() # Drop the roles field if it was provided. user_dict.pop('roles', None) new_user = db.query(User).get(user_id) if not new_user or new_user.is_deleted: raise HTTPException(status_code=404, detail='User Not Found') new_user_version = UserVersion(data=strip_metadata(user_dict), server_version=settings.server_version) new_user_version.user = new_user add_updator(new_user_version, current_user.username) new_user.current = new_user_version db.add(new_user_version) db.commit() return add_role(enforcer, versioned_row_to_dict(new_user, new_user.current))
def resolve_run( root, info: ResolveInfo, id: int, version_id: int, ): enforcer = get_enforcer_from_request(info.context['request']) current_user = get_current_user_from_request(info.context['request']) if current_user is None: raise HTTPException(401, "Unauthorized") db = get_session(info) model_dict = crud_get_run( item_to_dict=lambda run: add_ids(versioned_row_to_dict(run, run.current), run_id=run.id), enforcer=enforcer, db=db, current_user=current_user, run_id=id, version_id=version_id, ) return RunModel.parse_obj(model_dict)
async def patch_run( request: Request, run_id: int, patch: list, enforcer: casbin.Enforcer = Depends(get_enforcer), db: Session = Depends(get_db), current_user: Auth0ClaimsPatched = Depends(get_current_user)): if not check_access(enforcer, user=current_user.username, path=f"/run/{str(run_id)}", method="PUT"): raise HTTPException(status_code=403, detail='Insufficient Permissions') new_run = db.query(Run).get(run_id) original_run_version = new_run.current if not new_run or new_run.is_deleted: raise HTTPException(status_code=404, detail='Run Not Found') record_timing(request, note=f"Fetched run {run_id}") run_dict = versioned_row_to_dict(new_run, new_run.current) run_dict.pop('protocol', None) json_patch = jsonpatch.JsonPatch(patch) run_dict.pop('protocol', None) run_dict = json_patch.apply(run_dict) if not change_allowed(run_to_dict(new_run, new_run.current), run_dict): raise HTTPException(status_code=403, detail='Insufficient Permissions') new_run_version = RunVersion(data=strip_metadata(run_dict), server_version=settings.server_version) new_run_version.run = new_run add_updator(new_run_version, current_user.username) original_run_version = new_run.current new_run.current = new_run_version db.add(new_run_version) db.commit() record_timing(request, note=f"Saved changes to run {run_id}") samples_dirty = False for operation in patch: operation_path = operation.get('path', '') # Check for changes to the path: /sections/*/blocks/*/plates if re.search( "^/(sections/([^/]+/(blocks/([^/]+/(plates(/.*)?)?)?)?)?)?$", operation_path): samples_dirty = True break # Check for changes to the path: /sections/*/blocks/*/plateSequencingResults if re.search( "^/(sections/([^/]+/(blocks/([^/]+/(plateSequencingResults(/.*)?)?)?)?)?)?$", operation_path): samples_dirty = True break # Check for changes to the path: /protocol/sections/*/blocks/*/plateMarkers if re.search( "^/(protocol/(sections/([^/]+/(blocks/([^/]+/(plateMarkers(/.*)?)?)?)?)?)?)?$", operation_path): samples_dirty = True break if samples_dirty: logger.info("======================================") logger.info( f"Regenerating samples for run_version: ({new_run.id}, {new_run_version.id})" ) samples = get_samples(new_run_version, new_run.protocol_version) record_timing( request, note=f"Regenerated run {new_run.id} samples (len: {len(samples)})") if samples: for sample in samples: db.merge(sample) logger.info( f"Generated {len(samples)} samples for run_version: ({new_run.id}, {new_run_version.id})" ) logger.info("======================================") record_timing( request, note=f"Saved {len(samples)} regenerated samples to run {new_run.id}" ) else: logger.info("======================================") logger.info( f"Using old samples for run_version: ({new_run.id}, {new_run_version.id})" ) samples = db.query(Sample)\ .filter(Sample.run_version_id == original_run_version.id)\ .distinct() sample_count = 0 for sample in samples: new_sample_version = clone_model(db, sample.current, run_version_id=new_run_version.id) new_sample = clone_model(db, sample, current=new_sample_version, run_version_id=new_run_version.id) db.merge(new_sample) sample_count += 1 logger.info( f"Attached {sample_count} existing samples to run_version: ({new_run.id}, {new_run_version.id})" ) logger.info("======================================") record_timing( request, note=f"Attached {sample_count} existing samples to run {new_run.id}" ) db.commit() return run_to_dict(new_run, new_run.current)
def run_to_dict(run, run_version): run_dict = versioned_row_to_dict(api, run, run_version) run_dict['protocol'] = versioned_row_to_dict(api, run.protocol_version.protocol, run.protocol_version) return run_dict
def run_to_dict(run, run_version, include_large_fields=True): run_dict = versioned_row_to_dict(run, run_version, include_large_fields) run_dict['protocol'] = versioned_row_to_dict(run.protocol_version.protocol, run.protocol_version, include_large_fields) return run_dict
def get(self): run = int(request.args.get('run')) if request.args.get('run') else None plate = request.args.get('plate') reagent = request.args.get('reagent') sample = request.args.get('sample') creator = request.args.get('creator') archived = request.args.get('archived') == 'true' if request.args.get( 'archived') else False protocols_queries = [] if run: protocols_queries.append( all_protocols(archived)\ .join(ProtocolVersion, ProtocolVersion.protocol_id == Protocol.id)\ .join(Run, Run.protocol_version_id == ProtocolVersion.id)\ .filter(Run.id == run) ) if plate: run_version_query = all_protocols(archived)\ .join(ProtocolVersion, ProtocolVersion.protocol_id == Protocol.id)\ .join(Run, Run.protocol_version_id == ProtocolVersion.id)\ .join(RunVersion, RunVersion.id == Run.version_id) protocols_subquery = filter_by_plate_label(run_version_query, plate) protocols_queries.append(protocols_subquery) if reagent: run_version_query = all_protocols(archived)\ .join(ProtocolVersion, ProtocolVersion.protocol_id == Protocol.id)\ .join(Run, Run.protocol_version_id == ProtocolVersion.id)\ .join(RunVersion, RunVersion.id == Run.version_id) protocols_subquery = filter_by_reagent_label( run_version_query, reagent) protocols_queries.append(protocols_subquery) if sample: run_version_query = all_protocols(archived)\ .join(ProtocolVersion, ProtocolVersion.protocol_id == Protocol.id)\ .join(Run, Run.protocol_version_id == ProtocolVersion.id)\ .join(RunVersion, RunVersion.id == Run.version_id) protocols_subquery = filter_by_sample_label( run_version_query, sample) protocols_queries.append(protocols_subquery) if creator: protocols_queries.append( all_protocols(archived)\ # .filter(Protocol.id == protocol)\ .filter(Protocol.created_by == creator) ) # Add a basic non-deleted items query if no filters were specified. if len(protocols_queries) == 0: protocols_queries.append(all_protocols(archived)) # Only return the intersection of all queries. protocols_query = reduce(lambda a, b: a.intersect(b), protocols_queries) results = {} if request.args.get('page') is not None or request.args.get( 'per_page') is not None: page = int( request.args.get('page')) if request.args.get('page') else 1 per_page = int(request.args.get('per_page')) if request.args.get( 'per_page') else 20 page_query = protocols_query.distinct().order_by( Protocol.created_on.desc()).paginate(page=page, per_page=per_page) results['page'] = page_query.page results['pageCount'] = page_query.pages query = page_query.items else: query = protocols_query.distinct().order_by( Protocol.created_on.desc()) results['protocols'] = [ versioned_row_to_dict(api, protocol, protocol.current) for protocol in query if check_access(path=f"/protocol/{str(protocol.id)}", method="GET") and protocol and protocol.current ] return results