def post(self, datapoint_id: str, model_id: str) -> ResponseType: form = ResultForm(request.get_json() or {}) if not form.validate(): return {"message": "invalid data", "errors": form.errors}, 400 with settings.session() as session: obj = DatapointModelResult(**form.valid_data) obj.datapoint = request.datapoint obj.model = request.model session.expunge(obj) existing_obj = obj.get_existing(session) # if a matching result already exists we do not create a new one if existing_obj: # we update the existing object instead update_form = ResultForm(request.get_json() or {}, is_update=True) if not update_form.validate(): return { "message": "invalid data", "errors": form.errors }, 400 for k, v in update_form.valid_data.items(): setattr(existing_obj, k, v) session.commit() return existing_obj.export(), 201 session.add(obj) session.commit() return obj.export(), 201
def get(self, datapoint_id: str, model_id: str) -> ResponseType: """ Return all objects that match the given criteria and that the user is allowed to see. """ with settings.session() as session: filters = [ DatapointModelResult.deleted_at == None, DatapointModelResult.datapoint == request.datapoint, DatapointModelResult.model == request.model, ] objs = session.query(DatapointModelResult).filter(*filters).all() return {"data": [obj.export() for obj in objs]}, 200
def _clean_db(settings, plugin): with settings.session() as session: if plugin is None: plugins = list(settings.get("plugins", {}).keys()) + ["core"] else: plugins = [plugin] for plugin in plugins: if plugin == "core": clean_db(session) continue config = settings.load_plugin_config(plugin) if "clean_db" in config: config["clean_db"](session)
def get(self, object_id: Optional[str] = None) -> ResponseType: """ Return all objects that match the given criteria and that the user is allowed to see. """ with settings.session() as session: if DependentTypes: dependent_type = DependentTypes[0]().type dependent_obj = getattr(request, dependent_type) filters = [Type.deleted_at == None] joins = [] if JoinBy: joins.append(JoinBy) filters.extend( [getattr(JoinBy, dependent_type) == dependent_obj]) else: filters.append( getattr(Type, dependent_type) == dependent_obj) query = session.query(Type).filter(*filters).join(*joins) else: visible_objs = ObjectRole.select_for( session, request.user, Type().type) # we add objects visible via the users organizations org_ids = admin_orgs_id_query(session, request.user) query = session.query(Type).filter( or_(Type.id.in_(visible_objs), Type.organization_id.in_(org_ids)), Type.deleted_at == None, ) # If requested, we join dependent objects for faster response times... if Joins: for j in Joins: joinedloads = None for Join in j: if joinedloads is None: joinedloads = joinedload(Join, innerjoin=True) else: joinedloads = joinedloads.joinedload( Join, innerjoin=True) query = query.options(joinedloads) objs = query.all() return {"data": [obj.export() for obj in objs]}, 200
def post(self, algorithm_id: str, dataset_id: str) -> ResponseType: form = ModelForm(request.get_json() or {}) if not form.validate(): return {"message": "invalid data", "errors": form.errors}, 400 with settings.session() as session: obj = Model(**form.valid_data) existing_obj = (session.query(Model).filter( Model.algorithm_id == request.algorithm.id, Model.dataset_id == request.dataset.id, Model.hash == obj.hash, Model.deleted_at == None, ).one_or_none()) if existing_obj: return existing_obj.export(), 201 obj.algorithm = request.algorithm obj.dataset = request.dataset session.add(obj) session.commit() return obj.export(), 201
def decorated_function(*args, **kwargs) -> ResponseType: if Type is None: # if not type is given, we return the original result without change return f(*args, **kwargs) object_id = kwargs.get(id_field) if not object_id: return {"message": "invalid ID"}, 400 def authorize( session: sqlalchemy.orm.session.Session) -> ResponseType: # required to make mypy happy assert Type is not None # we retrieve the requested object from the database query = session.query(Type).filter(Type.ext_id == object_id, Type.deleted_at == None) if Joins: for j in Joins: joinedloads = None for Join in j: if joinedloads is None: joinedloads = joinedload(Join, innerjoin=True) else: joinedloads = joinedloads.joinedload( Join, innerjoin=True) query = query.options(joinedloads) obj = query.one_or_none() if not obj: return not_found if Type is ObjectRole: # this is an object role, we check if the user has admin # privileges for the organization. if not "admin" in request.user.roles.roles: return not_found else: if DependentTypes: # this object depends on a chain of dependent objects from which it # inherits roles. We therefore need to retrieve these dependent objects # from the database. DependentType = DependentTypes[0] dependent_id = kwargs.get(dependent_id_field) if dependent_id: # if a dependent ID is given in the URL, we retrieve # the dependent object through this query = session.query(DependentType).filter( DependentType.ext_id == dependent_id, DependentType.deleted_at == None, ) else: # otherwise, we retrieve the object by its relation # to the main object. if JoinBy is not None: # if there is a M2M table that we should join by, we # include it in the query to ensure there is an actual entry between # the requested object and the dependent objects query = (session.query(DependentType).filter( DependentType.deleted_at == None).join( JoinBy).filter( getattr(JoinBy, obj.type) == obj, getattr( JoinBy, "{}_id".format( DependentType().type)) == DependentType.id, DependentType.deleted_at == None, )) else: query = session.query(DependentType).filter( DependentType.id == getattr( obj, "{}_id".format(DependentType().type)), DependentType.deleted_at == None, ) if len(DependentTypes) > 1: # if there are more than one dependent types, we add joinedload # conditions for all of them to make sure they get loaded efficiently # from the database. joinedloads = None for NextType in DependentTypes[1:]: nt = NextType().type query = query.filter( NextType.deleted_at == None) if joinedloads is None: joinedloads = joinedload(getattr( DependentType, nt), innerjoin=True) else: joinedloads = joinedloads.joinedload( getattr(DependentType, nt), innerjoin=True) DependentType = NextType # if the dependent type has an organization # we also load it... if hasattr(DependentType, "organization"): joinedloads = joinedloads.joinedload( DependentType.organization, innerjoin=True) query = query.options(joinedloads) dependent_obj = query.one_or_none() if not dependent_obj: return not_found # we extract the dependent types from the object and store them # on the request object setattr(request, dependent_obj.type, dependent_obj) for DependentType in DependentTypes[1:]: next_type = DependentType().type next_obj = getattr(dependent_obj, next_type) if next_obj is None: return not_found setattr(request, next_type, next_obj) dependent_obj = next_obj # we set the role object to the last object in the dependency chain role_obj = dependent_obj else: role_obj = obj role_found = False # this object is owned by an organization, so we check the roles of # the currently logged in user in the organization and see if the # the user is an admin or superuser, in which case he/she has access # to the object regardless of explicitly set object roles. if (hasattr(role_obj, "organization") and not role_obj.organization.deleted_at): for org_roles in request.user.roles: if (org_roles.organization.id == role_obj.organization.source_id and org_roles.organization.source == role_obj.organization.source): for role in ["admin", "superuser"]: if role in org_roles.roles: role_found = True break else: continue break # we retrieve the roles for the role object and the currently logged in user obj_roles = ObjectRole.roles_for(session, request.user, role_obj) obj_roles_set = set( [role.object_role for role in obj_roles]) # we check the roles against the required ones to see if the user has one of the # requested roles on the object, otherwise we return "not found" if roles is None: if obj_roles: role_found = True else: for role in roles: if role in obj_roles_set: role_found = True break if not role_found: return not_found # we add the roles to the object as a context information obj._roles = obj_roles setattr(request, obj.type, obj) return f(*args, **kwargs) if hasattr(request, "session"): return authorize(request.session) with settings.session() as session: request.session = session return authorize(session)
def post(self, object_id: Optional[str] = None, organization_id: Optional[str] = None) -> ResponseType: form = Form(request.get_json() or {}) if not form.validate(): return {"message": "invalid data", "errors": form.errors}, 400 dependent_obj: Optional[Base] = None org: Optional[Organization] = None join_by: Optional[Base] = None if DependentTypes: dependent_type = DependentTypes[0]().type dependent_obj = getattr(request, dependent_type) with settings.session() as session: obj = Type(**form.valid_data) if organization_id is not None: org = Organization.get_or_create(session, request.organization) obj.organization = org if dependent_obj: if JoinBy: # if this object has a M2M table, we create a row in # the table for the newly created object join_by = JoinBy() setattr(join_by, dependent_type, dependent_obj) setattr(join_by, obj.type, obj) else: setattr(obj, dependent_type, dependent_obj) # we expunge the object from the session, as it might have been added # when we associated the dependent properties with it... session.expunge(obj) existing_obj = obj.get_existing(session) if existing_obj: # we update the existing object instead update_form = Form(request.get_json() or {}, is_update=True) if not update_form.validate(): return { "message": "invalid data", "errors": form.errors }, 400 for k, v in update_form.valid_data.items(): setattr(existing_obj, k, v) session.commit() return existing_obj.export(), 201 if join_by: session.add(join_by) session.add(obj) if not DependentTypes: # we create an object role for the newly created object # only if it does not depends on another object assert isinstance(org, Organization) for org_role in ["admin", "superuser"]: ObjectRole.get_or_create(session, obj, org, "admin", org_role) session.commit() return obj.export(), 201