def download_result_archive(run_id): """Download a compressed tar archive containing all result files that were generated by a given workflow run. NOTE: At this point, the user is not authenticated for file downloads to allow download in the GUI via browser redirect. Parameters ---------- run_id: string Unique run identifier Returns ------- flask.response_class Raises ------ flowserv.error.UnknownWorkflowGroupError """ from robflask.service import service with service() as api: ioBuffer = api.runs().get_result_archive(run_id=run_id) return send_file(ioBuffer.open(), as_attachment=True, attachment_filename='run.tar.gz', mimetype='application/gzip')
def client(benchmark_id, tmpdir): """Create the app client.""" # Set the environment variables and create the database. connect_url = TEST_DB(tmpdir) DB(connect_url=connect_url).init() # Create a single benchmark. Need to ensure that the API factory points to # the newly created database. from robflask.service import init_service init_service(basedir=tmpdir, database=connect_url) from robflask.service import service with service() as api: # Get the benchmark repository instance from the API api.workflows().create_workflow(identifier=benchmark_id, name='Hello World', description='Hello World Demo', source=BENCHMARK_DIR) # Set the maximum upload file size to 1KB os.environ[config.ROB_WEBAPI_CONTENTLENGTH] = '1024' # Set the UI path. os.environ[config.ROB_UI_PATH] = ROB_UI_PATH # Create the Flask app from robflask.api import create_app app = create_app({'TESTING': True}) with app.test_client() as client: yield client
def delete_run(run_id): """Delete the run with the given identifier. The user has to be a member of the run submission in order to be authorized to delete the run. Parameters ---------- run_id: string Unique run identifier Returns ------- flask.response_class Raises ------ flowserv.error.UnauthenticatedAccessError flowserv.error.UnauthorizedAccessError flowserv.error.UnknownWorkflowGroupError """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). from robflask.service import service with service(access_token=ACCESS_TOKEN(request)) as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. api.runs().delete_run(run_id=run_id) return make_response(jsonify(dict()), 204)
def create_submission(workflow_id): """Create a new submission for a given benchmark. The user has to be authenticated in order to be able to create a new submission. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). token = ACCESS_TOKEN(request) # Verify that the request contains a valid Json object that contains the # submission name and an optional list of member identifier. obj = jsonbody(request, mandatory=[labels.GROUP_NAME], optional=[labels.GROUP_MEMBERS]) name = obj[labels.GROUP_NAME] members = obj.get(labels.GROUP_MEMBERS) if members is not None and not isinstance(members, list): raise err.InvalidRequestError('{} not a list'.format( labels.GROUP_MEMBERS)) from robflask.service import service with service(access_token=token) as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. try: r = api.groups().create_group(workflow_id=workflow_id, name=name, members=members) except UnknownUserError as ex: # Change error type from unknown object to invalid request if a # user in the member list is unknown raise err.InvalidRequestError(str(ex)) return make_response(jsonify(r), 201)
def upload_file(group_id): """Upload a new file as part of a given submission. The user has to be a member of the submission in order to be allowed to upload files. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). token = ACCESS_TOKEN(request) # Ensure that the upload request contains a file object if request.files and 'file' in request.files: file = request.files['file'] # A browser may submit a empty part without filename if file.filename == '': raise err.InvalidRequestError('empty file name') # Save uploaded file to a bytes buffer. filename = secure_filename(file.filename) from robflask.service import service with service(access_token=token) as api: # Authentication of the user from the expected api_token in the # header will fail if the user is not logged in. r = api.uploads().upload_file(group_id=group_id, file=FlaskFile(file), name=filename) return make_response(jsonify(r), 201) else: raise err.InvalidRequestError('no file request')
def download_result_file(run_id, file_id): """Download a resource file that was generated by a successful workflow run. The user has to be a member of the submission in order to be allowed to access files. NOTE: At this point, the user is not authenticated for file downloads to allow download in the GUI via browser redirect. Parameters ---------- run_id: string Unique run identifier file_id: string Unique resource file identifier Returns ------- flask.response_class Raises ------ flowserv.error.UnauthenticatedAccessError flowserv.error.UnauthorizedAccessError flowserv.error.UnknownWorkflowGroupError """ print('download {} {}'.format(run_id, file_id)) from robflask.service import service with service() as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. fh = api.runs().get_result_file(run_id=run_id, file_id=file_id) return send_file(fh.open(), as_attachment=True, attachment_filename=fh.name, mimetype=fh.mime_type)
def register_user(): """Create a new user. Raises an InvalidRequest object if the request does not contain a JSON object with a user name and password for the new user. If the request body contains the optional verify flag and if the flag is set to False, the user will be activated immediately. Returns ------- flask.response_class Raises ------ robflask.error.InvalidRequest """ # Verify that the request contains a valid Json object obj = jsonbody(request, mandatory=[labels.USER_NAME, labels.USER_PASSWORD], optional=[labels.VERIFY_USER]) # Get the name and password for the new user and the value of the verify # flag. By default the flag is set to True user = obj[labels.USER_NAME] passwd = obj[labels.USER_PASSWORD] if labels.VERIFY_USER in obj: verify = bool(obj[labels.VERIFY_USER]) else: verify = True # Register user in the database and return the serialized user handle. from robflask.service import service with service() as api: r = api.users().register_user(username=user, password=passwd, verify=verify) return make_response(jsonify(r), 201)
def service_descriptor(): """Get the API service descriptor.""" # If the request contains an access token we validate that the token is # still active. The access token is optional for the service descriptor. # Make sure not to raise an error if no token is present. from robflask.service import service with service(access_token=ACCESS_TOKEN(request, raise_error=False)) as api: return jsonify(api.server().to_dict()), 200
def list_benchmarks(): """Get listing of available benchmarks. The benchmark listing is available to everyone, independent of whether they are currently authenticated or not. """ from robflask.service import service with service() as api: r = api.workflows().list_workflows() return make_response(jsonify(r), 200)
def list_submission(workflow_id): """Get a list of all submissions for a given benchmark. The user has to be authenticated in order to be able to access the submission list. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). from robflask.service import service with service(access_token=ACCESS_TOKEN(request)) as api: r = api.groups().list_groups(workflow_id=workflow_id) return make_response(jsonify(r), 200)
def get_submission(group_id): """Get handle for the submission with the given identifier. The user has to be authenticated in order to access a submission. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). from robflask.service import service with service(access_token=ACCESS_TOKEN(request)) as api: r = api.groups().get_group(group_id=group_id) return make_response(jsonify(r), 200)
def delete_submission(group_id): """Delete the submission with the given identifier. The user has to be a submission member in order to be authorized to delete the submission. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). from robflask.service import service with service(access_token=ACCESS_TOKEN(request)) as api: api.groups().delete_group(group_id=group_id) return make_response(jsonify(dict()), 204)
def get_benchmark(workflow_id): """Get handle for given a benchmark. Benchmarks are available to everyone, independent of whether they are currently authenticated or not. """ # Get the access token first. Do not raise raise an error if no token is # present. from robflask.service import service with service(access_token=ACCESS_TOKEN(request, raise_error=False)) as api: r = api.workflows().get_workflow(workflow_id=workflow_id) return make_response(jsonify(r), 200)
def delete_file(group_id, file_id): """Delete a given file that was perviously uploaded for a submission. The user has to be a member of the submission in order to be allowed to delete files. """ from robflask.service import service with service(access_token=ACCESS_TOKEN(request)) as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. api.uploads().delete_file(group_id=group_id, file_id=file_id) return make_response(jsonify(dict()), 204)
def list_runs(group_id): """Get a listing of all runs for a given submission. The user has to be a submission member in order to be authorized to list the runs. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). from robflask.service import service with service(access_token=ACCESS_TOKEN(request)) as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. r = api.runs().list_runs(group_id=group_id) return make_response(jsonify(r), 200)
def download_benchmark_archive(workflow_id): """Download a compressed tar archive containing all current resource files for a benchmark that were created during post-processing. """ from robflask.service import service with service() as api: fh = api.workflows().get_result_archive(workflow_id) return send_file( fh.open(), as_attachment=True, attachment_filename='results.tar.gz', mimetype='application/gzip' )
def download_file(group_id, file_id): """Download a given file that was perviously uploaded for a submission. NOTE: At this point, the user is not authenticated for file downloads to allow download in the GUI via browser redirect. """ from robflask.service import service with service() as api: fh = api.uploads().get_uploaded_file_handle(group_id=group_id, file_id=file_id) return send_file(fh.open(), as_attachment=True, attachment_filename=fh.name, mimetype=fh.mime_type)
def logout_user(): """Logout user. Expects an access token for the authenticated user that is being logged out. Returns ------- flask.response_class Raises ------ flowserv.error.UnauthenticatedAccessError """ from robflask.service import service with service() as api: r = api.users().logout_user(api_key=ACCESS_TOKEN(request)) return make_response(jsonify(r), 200)
def request_password_reset(): """Request to rest the passowrd for a given user. Returns ------- flask.response_class """ # Verify that the request contains a valid Json object and get the name of # the user whose password is being rest. obj = jsonbody(request, mandatory=[labels.USER_NAME]) user = obj[labels.USER_NAME] # Request password reset. from robflask.service import service with service() as api: r = api.users().request_password_reset(username=user) return make_response(jsonify(r), 200)
def get_benchmark_resource(workflow_id, file_id): """Download the current resource file for a benchmark resource that was created during post-processing. """ from robflask.service import service with service() as api: fh = api.workflows().get_result_file( workflow_id=workflow_id, file_id=file_id ) attachment_filename = fh.name mimetype = fh.mime_type return send_file( fh.open(), as_attachment=True, attachment_filename=attachment_filename, mimetype=mimetype )
def list_users(): """Get listing of registered users. Only users that are registered and currently logged in are allowed to query the database. Returns ------- flask.response_class Raises ------ flowserv.error.UnauthenticatedAccessError """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). from robflask.service import service with service(access_token=ACCESS_TOKEN(request)) as api: r = api.users().list_users(query=request.args.get('query')) return make_response(jsonify(r), 200)
def whoami_user(): """Get information about user that is associated with the provided access token. Returns ------- flask.response_class Raises ------ flowserv.error.UnauthenticatedAccessError """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). token = ACCESS_TOKEN(request) from robflask.service import service with service() as api: r = api.users().whoami_user(api_key=token) return make_response(jsonify(r), 200)
def activate_user(): """Activate a newly registered user based on their unique user identifier. Returns ------- flask.response_class Raises ------ robflask.error.InvalidRequest """ # Verify that the request contains a valid Json object and get the user # identifier obj = jsonbody(request, mandatory=[labels.USER_ID]) user_id = obj[labels.USER_ID] # Activate user in the database and return the serialized user handle. from robflask.service import service with service() as api: r = api.users().activate_user(user_id=user_id) return make_response(jsonify(r), 200)
def login_user(): """Authenticate a user based on the given credentials. Returns the access token that the user will use in subsequent requests. Returns ------- flask.response_class Raises ------ robflask.error.InvalidRequest """ # Verify that the request contains a valid Json object obj = jsonbody(request, mandatory=[labels.USER_NAME, labels.USER_PASSWORD]) # Get the name and password for the new user user = obj[labels.USER_NAME] passwd = obj[labels.USER_PASSWORD] # Authenticate user. from robflask.service import service with service() as api: r = api.users().login_user(username=user, password=passwd) return make_response(jsonify(r), 200)
def update_submission(group_id): """Update the submission with the given identifier. The request body can contain a modified submission name and/or a modified list of submission members. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). token = ACCESS_TOKEN(request) # Verify that the request contains a valid Json object that contains an # optional submission name and/or a list of member identifier. obj = jsonbody(request, mandatory=[], optional=[labels.GROUP_NAME, labels.GROUP_MEMBERS]) name = obj.get(labels.GROUP_NAME) members = obj.get(labels.GROUP_MEMBERS) from robflask.service import service with service(access_token=token) as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. r = api.groups().update_group(group_id=group_id, name=name, members=members) return make_response(jsonify(r), 200)
def start_run(group_id): """Start a new run. Expects argument values for each mandatory benchmark parameter in the request body. The user has to be a submission member in order to be authorized to start new submission runs. """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). token = ACCESS_TOKEN(request) # Verify that the request contains a valid Json object that contains a # optional list of workflow arguments. obj = jsonbody(request, optional=[labels.RUN_ARGUMENTS]) args = obj[labels.RUN_ARGUMENTS] if labels.RUN_ARGUMENTS in obj else dict() from robflask.service import service with service(access_token=token) as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. try: r = api.runs().start_run(group_id=group_id, arguments=args) except UnknownParameterError as ex: # Convert unknown parameter errors into invalid request errors # to avoid sending a 404 response raise err.InvalidRequestError(str(ex)) return make_response(jsonify(r), 201)
def get_leaderboard(workflow_id): """Get leader board for a given benchmark. Benchmarks and their results are available to everyone, independent of whether they are authenticated or not. """ # The orderBy argument can include a list of column names. Each column name # may be suffixed by the sort order. order_by = request.args.get('orderBy') if order_by is not None: sort_columns = list() for col in order_by.split(','): sort_desc = None pos = col.find(':') if pos > -1: if col[pos + 1:].lower() == 'asc': sort_desc = False col = col[:pos] sort_columns.append(SortColumn(col, sort_desc=sort_desc)) else: sort_columns = None # The includeAll argument is a flag. If the argument is given without value # the default is True. Otherwise, we expect a string that is equal to true. include_all = request.args.get('includeAll') if include_all is not None: if include_all == '': include_all = True else: include_all = include_all.lower() == 'true' # Get serialization of the result ranking from robflask.service import service with service() as api: r = api.workflows().get_ranking( workflow_id, order_by=sort_columns, include_all=include_all ) return make_response(jsonify(r), 200)
def cancel_run(run_id): """Get handle for a given run. The user has to be a member of the run submission in order to be authorized to access the run. Parameters ---------- run_id: string Unique run identifier Returns ------- flask.response_class Raises ------ flowserv.error.UnauthenticatedAccessError flowserv.error.UnauthorizedAccessError flowserv.error.UnknownWorkflowGroupError """ # Get the access token first to raise an error immediately if no token is # present (to avoid unnecessarily instantiating the service API). token = ACCESS_TOKEN(request) # If the body contains a Json object verify that the object has the # mandatory element 'reason' reason = None if request.json: try: obj = util.validate_doc(request.json, mandatory=['reason']) reason = obj['reason'] except ValueError as ex: raise err.InvalidRequestError(str(ex)) from robflask.service import service with service(access_token=token) as api: # Authentication of the user from the expected api_token in the header # will fail if no token is given or if the user is not logged in. r = api.runs().cancel_run(run_id=run_id, reason=reason) return make_response(jsonify(r), 200)
def reset_password(): """Reset the passowrd for a user. The user is identified by the request identifier in the request body. This identifier is expected to have been generated by a preceeding reset request. Returns ------- flask.response_class Raises ------ robflask.error.ConstraintViolationError """ # Verify that the request contains a valid Json object mandatory_labels = [labels.REQUEST_ID, labels.USER_PASSWORD] obj = jsonbody(request, mandatory=mandatory_labels) # Get the unique request identifier and the new user password req_id = obj[labels.REQUEST_ID] passwd = obj[labels.USER_PASSWORD] # Reset the password for the user that is identified by the request id. from robflask.service import service with service() as api: r = api.users().reset_password(request_id=req_id, password=passwd) return make_response(jsonify(r), 200)