def user_edit(): error_list = [] with sessionMaker.session_scope() as session: data = request.get_json( force=True) # Force = true if not set as application/json' user = data.get('user', None) if user is None: out = jsonify(success=None, error_list=["No user"]) return out, 400, {'ContentType': 'application/json'} # May want to update users other than the requesting user... #db_user = session.query(User).filter_by(email=user['email']).first() # Permissions model here assumes that we know who the user is # So therefore can only update for self db_user = session.query(User).filter(User.id == getUserID()).one() # Update info # TODO lots of checks and things to consider here... db_user.first_name = user.get('first_name', None) db_user.last_name = user.get('last_name', None) session.add(db_user) out = jsonify(success=True, errors=[], user=db_user.serialize()) return out, 200, {'ContentType': 'application/json'}
def user_upload_profile_image(): file = request.files.get('file') if not file: return "No file", 400 extension = os.path.splitext(file.filename)[1].lower() if extension in images_allowed_file_names: file.filename = secure_filename( file.filename ) # http://flask.pocoo.org/docs/0.12/patterns/fileuploads/ temp_dir = tempfile.mkdtemp() file_name = temp_dir + "/" + file.filename file.save(file_name) with sessionMaker.session_scope() as session: with open(file_name, "rb") as file: content_type = "image/" + str(extension) short_file_name = os.path.split(file_name)[1] user = session.query(User).filter(User.id == getUserID()).one() image = process_profile_image(session=session, user=user, file=file, file_name=short_file_name, content_type=content_type, extension=extension) Event.new(kind="profile_image_update", session=session, member=user.member, success=True) return jsonify(success=True, user=user.serialize()), 200, { 'ContentType': 'application/json' } return jsonify(success=False), 400, {'ContentType': 'application/json'}
def check_permissions(Roles, project_string_id, session, apis_project_list=None, apis_user_list=None): """ TODO this could use better organization ie project_string_id is None check could be here, but we seem to do it an extra time on line 123 """ if project_string_id is None: # TODO merge None checks from other thing up top here. raise Forbidden("project_string_id is None") if 'allow_anonymous' in Roles: return True project = Project.get(session, project_string_id) if project is None: raise Forbidden(default_denied_message) # Careful here! Just becuase a project is public # Doesn't mean public is allowed acccess to all # routes. ie only admins can delete project # if a project is public we don't need to check a user's apis right? if 'allow_if_project_is_public' in Roles: if project: if project.is_public is True: return True # TODO merge LoggedIn() with getUserID() similar internal logic if LoggedIn() != True: raise Forbidden(default_denied_message) if 'allow_any_logged_in_user' in Roles: # TODO not happy with this name, want more clarity on how this effects other permissions like apis / project etc. return True user = session.query(User).filter(User.id == getUserID()).one() if user.is_super_admin == True: return True if apis_project_list: check_all_apis(project=project, apis_required_list=apis_project_list) if apis_user_list: User_Permissions.general(user=user, apis_user_list=apis_user_list) # This could be slow if a user has a lot of projects? for project, Permissions in user.permissions_projects.items(): if Permissions is None: continue if project_string_id == project: check_role_result = check_roles(Roles, Permissions) if check_role_result is True: return True # Default # Good to have this here so we can call # this function as one line and don't ahve to worry # About returning False (must have returned True eariler) raise Forbidden(default_denied_message)
def label_edit(project_string_id): with sessionMaker.session_scope() as session: data = request.get_json( force=True) # Force = true if not set as application/json' label_file = data.get('label_file', None) if label_file is None: return json.dumps("file is None"), 400, { 'ContentType': 'application/json' } label_proposed = label_file.get('label', None) if label_proposed is None: return json.dumps("label is None"), 400, { 'ContentType': 'application/json' } name_proposed = label_proposed.get('name', None) if name_proposed is None or len(name_proposed) < 1: return json.dumps("label less than 1 character"), 400, { 'ContentType': 'application/json' } label_file_id = label_file.get('id', None) if label_file_id is None: return json.dumps("no label id"), 400, { 'ContentType': 'application/json' } # WIP... user_id = getUserID() existing_file = File.get_by_id_untrusted(session, user_id, project_string_id, label_file_id) if existing_file is None: return jsonify("No file"), 400 if existing_file.committed is True: return jsonify("File committed"), 400 # TODO # WIP WIP new_file = File.copy_file_from_existing(session, working_dir, existing_file) label_file = File.new_label_file( session=session, name=name_proposed, default_sequences_to_single_frame=None, working_dir_id=project.directory_default_id, project=project, colour=colour_proposed, log=log, existing_file=new_file) # WIP if existing_file.committed is not True: project = Project.get(session, project_string_id) user = session.query(User).filter(User.id == user_id).one() working_dir = project.directory_default colour_proposed = label_file.get("colour", None) # Caution note, 'label_proposed' not file default_sequences_to_single_frame_proposed = label_proposed.get( "default_sequences_to_single_frame") if default_sequences_to_single_frame_proposed is None: default_sequences_to_single_frame_proposed = False # Caution # We need this because we are trying to # maintain unique labels... # It's the Label() class we are getting not the File() # (Which we already have). label = Label.new(session, name=name_proposed, default_sequences_to_single_frame= default_sequences_to_single_frame_proposed) existing_file.label_id = label.id existing_file.colour = colour_proposed session.add(existing_file) working_dir.label_file_colour_map[ existing_file.id] = colour_proposed # Caution: https://stackoverflow.com/questions/42559434/updates-to-json-field-dont-persist-to-db flag_modified(working_dir, "label_file_colour_map") # This seems to be needed to reliably detect changes # Maybe didn't need it prior as was editing sub "lists" vs editing ID directly # This still feels better than passing whole item to python memory and editing it # (Which still also doesn't always work as expected.) session.add(working_dir) # return existing_file """ Option 1 Create new files for a label change ie get all file attached to the label Create a new file for every one, and attach it to that new label Then any future changes to label don't have to create new files Till it's comitted Then would whave to create new ones again ie Instance.label_id == """ out = 'success' return json.dumps(out), 200, {'ContentType': 'application/json'}
def get(session): return session.query(User).filter_by(id=getUserID()).first()
def get_current_user(session): return session.query(User).filter_by(id=getUserID()).first()
def inner(*args, **kwds): job_id = kwds.get('job_id', None) if job_id is None or job_id == "null" or job_id == "undefined": raise Forbidden("job_id is invalid") with sessionMaker.session_scope() as session: # Permissions cascading from project project_string_id = get_project_string_from_job_id( session, job_id) # API if request.authorization is not None: result = API_Permissions.by_project( session=session, project_string_id=project_string_id, Roles=project_role_list) if result is True: return func(*args, **kwds) else: raise Forbidden("API access invalid") # TODO do we need to validate user has applicable mode? # ie they pass mode builder but are trainer? # Basics should fail on project level check anyway here... # User # TODO move login stuff into the general User_Permissions if LoggedIn() != True: raise Forbidden("Login again.") user = session.query(User).filter( User.id == getUserID()).first() if user is None: raise Forbidden("Login again.") # Want to use the builder API permissions instead of # flags since a user may be testing this as a builder # TODO deprecate 'mode' flag or have it as something else # like "builder_only" or something # Jan 3, 2020 # One downside of doing it this way is it means # that we need to be careful with # project_role_list list... if user.api_enabled_builder is True: result = Project_permissions.check_permissions( session=session, project_string_id=project_string_id, Roles=project_role_list, apis_project_list=apis_project_list, apis_user_list=apis_user_list) if result is True: return func(*args, **kwds) else: raise Forbidden("Project access invalid") if user.api_enabled_trainer is True: # TODO refactor into function # TODO handle "info" case of a trainer not yet # on a job seeing basic stuff on active jobs... # We allow trainers to see # Basic info before they apply # as long as job is active... #if job.status != "active": # raise Forbidden("No access.") User_Permissions.general(user=user, apis_user_list=apis_user_list) user_to_job = User_To_Job.get_single_by_ids( session=session, user_id=user.id, job_id=job_id) # TODO other status checking on this... if user_to_job is None: raise Forbidden( "No access to this job. Please apply first.") # Success case for trainer return func(*args, **kwds) raise Forbidden("No access.")