Example #1
0
def main():
    """
    Main entry point for the FunPDBe client
    :return: None
    """

    logger = FunPDBeClientLogger(name="main", write_mode="w")

    try:
        opts, args = getopt.getopt(sys.argv[1:], "u:p:m:i:r:f:a:oh", [
            "user="******"pwd=", "mode=", "pdb_id=", "resource=", "path=", "api=",
            "overwrite", "help"
        ])
    except getopt.GetoptError as err:
        generic_error()
        logger.log().error(err)
        sys.exit(2)

    schema = Schema()
    user = User()
    client = Client(schema, user)
    if opts:
        Control(opts, client=client).run()
    else:
        Control([('--help', '')], client=client).run()
Example #2
0
class Client(object):
    """
    The FunPDBe deposition client allows users to deposit, delete and view
    data in the FunPDBe deposition system
    """
    def __init__(self, schema, user):
        self.user = user
        self.schema = schema
        self.api_url = API_URL
        self.json_data = None
        self.logger = FunPDBeClientLogger("client")

    def __str__(self):
        return """
The FunPDBe deposition client allows users to deposit, delete and view  
data in the FunPDBe deposition system                                   

Usage parameters:
-h, --help:       Help (this is what you see now)
-u, --user:       FunPDBe user name
-p, --pwd:        FunPDBe password
-m, --mode:       Running mode (get, post, delete, put)
-i, --pdbid:      PDB id of an entry
-r, --resource:   Name of a resource
-f, --path:       Path to JSON file (.json ending), or files (folder name)
-d, --debug:      Enable debug logging
        """

    def get_one(self, pdb_id, resource=None):
        """
        Get one FunPDBe entry based on PDB id and
        optionally resource name
        :param pdb_id: String, PDB id
        :param resource: String, resource name
        :return: None
        """
        message = "GET entry for %s" % pdb_id
        if resource:
            message += " from %s" % resource
        self.logger.log().info(message)

        if not self.check_pdb_id(pdb_id):
            return None

        self.user_info()
        url = self.construct_get_url(resource, pdb_id)
        r = requests.get(url, auth=(self.user.user_name, self.user.user_pwd))

        if (r.status_code == 200):
            self.logger.log().info("[%i] success" % r.status_code)
        else:
            self.log_api_error(r.status_code, r.text)

        print(r.text)
        return r

    def construct_get_url(self, resource=None, pdb_id=None):
        url = self.api_url
        if resource and self.check_resource(resource):
            url += "resource/%s/" % resource
        else:
            url += "pdb/"
        url += "%s/" % pdb_id
        return url

    def get_all(self, resource=None):
        """
        Get all FunPDBe entries, optionally filtered
        by resource name
        :param resource: String, resource name
        :return: None
        """
        message = "GET all entries"
        if resource:
            message += " from %s" % resource
        self.logger.log().info(message)

        self.user_info()
        url = self.api_url
        if resource and self.check_resource(resource):
            url += "resource/%s/" % resource
        r = requests.get(url, auth=(self.user.user_name, self.user.user_pwd))
        print(r.text)
        return r

    def post(self, path, resource):
        """
        POST JSON to deposition API
        :param path: String, path to JSON file
        :param resource: String, resource name
        :return: None
        """
        message = "POST %s to %s" % (path, resource)
        self.logger.log().info(message)
        self.user_info()
        if not self.check_resource(resource):
            return None
        if not self.parse_json(path):
            return None
        if not self.validate_json():
            return None
        url = self.api_url
        url += "resource/%s/" % resource
        r = requests.post(url,
                          json=self.json_data,
                          auth=(self.user.user_name, self.user.user_pwd))
        self.check_status(r, 201)
        return r

    def put(self, path, pdb_id, resource):
        """
        POST JSON to deposition API
        :param path: String, path to JSON file
        :param pdb_id, String, PDB id
        :param resource: String, resource name
        :return: None
        """
        message = "UPDATE %s in %s from %s" % (pdb_id, resource, path)
        self.logger.log().info(message)
        if not self.check_resource(resource) or not self.check_pdb_id(pdb_id):
            return None
        self.user_info()
        if not self.parse_json(path):
            return None
        if not self.validate_json():
            return None
        url = self.api_url
        url += "resource/%s/%s/" % (resource, pdb_id)
        r = requests.post(url,
                          json=self.json_data,
                          auth=(self.user.user_name, self.user.user_pwd))
        self.check_status(r, 201)
        return r

    def delete_one(self, pdb_id, resource):
        """
        DELETE entry based on PDB id
        :param pdb_id: String, PDB id
        :param resource: String, resource name
        :return: none
        """
        message = "DELETE entry %s from %s" % (pdb_id, resource)
        self.logger.log().info(message)

        if not self.check_resource(resource):
            return None
        if not self.check_pdb_id(pdb_id):
            return None
        self.user_info()
        url = self.api_url
        url += "resource/%s/%s/" % (resource, pdb_id)
        r = requests.delete(url,
                            auth=(self.user.user_name, self.user.user_pwd))
        self.check_status(r, 301)
        return r

    def check_pdb_id(self, pdb_id):
        """
        Check if PDB id exists and if it matches
        the regular expression pattern of a valid
        PDB identifier
        :param pdb_id: String
        :return: Boolean
        """
        if not self.check_exists(pdb_id, "no_pdb"):
            return False
        if re.match(PDB_ID_PATTERN, pdb_id):
            return True
        generic_error()
        self.logger.log().error(CLIENT_ERRORS["bad_pdb"])
        return False

    def check_resource(self, resource):
        """
        Check if resource name exists and
        if it is a known (registered) resource
        :param resource: String
        :return: Boolean
        """
        if not self.check_exists(resource, "no_resource"):
            return False
        if resource in RESOURCES:
            return True
        self.logger.log().error(CLIENT_ERRORS["unknown_resource"])
        generic_error()
        return False

    def parse_json(self, path):
        """
        Parse user JSON file
        :param path: String, path to JSON
        :return: Boolean
        """
        if not self.check_exists(path, "no_path"):
            return None
        try:
            with open(path) as json_file:
                try:
                    self.json_data = json.load(json_file)
                    self.logger.log().info("JSON parsed")
                    return True
                except ValueError as valerr:
                    self.logger.log().error(valerr)
                    generic_error()
                    return False
        except IOError as ioerr:
            self.logger.log().error(ioerr)
            generic_error()
            return False

    def validate_json(self):
        """
        Validate JSON against schema
        :return: Boolean, True if validated JSON, False if not
        """
        if not self.schema.json_schema:
            self.schema.get_schema()
        if self.schema.validate_json(self.json_data):
            self.logger.log().info("JSON complies with FunPDBe schema")
            self.json_data = self.schema.clean_json(self.json_data)
            return True
        self.logger.log().error(CLIENT_ERRORS["bad_json"])
        return False

    def check_status(self, response, expected):

        if response.status_code == expected:
            self.logger.log().info("[%i] SUCCESS" % response.status_code)
        else:
            self.logger.log().error("[%i] FAIL - %s" %
                                    (response.status_code, response.text))

    def log_api_error(self, status_code, text):
        self.logger.log().error("[%s] - %s" % (status_code, text))

    def check_exists(self, value, error):
        if value:
            return True
        self.logger.log().error(CLIENT_ERRORS[error])
        return False

    def user_info(self):
        """
        Prompting user to provide info if missing
        :return: None
        """
        self.user.set_user()
        self.user.set_pwd()
Example #3
0
class Control(object):
    def __init__(self, opts, client):
        self.opts = opts
        self.client = client
        self.path = self.loop_options("-f", "--path")
        self.pdb_id = self.loop_options("-i", "--pdb_id")
        self.mode = self.loop_options("-m", "--mode")
        self.resource = self.loop_options("-r", "--resource")
        self.user_name = self.loop_options("-u", "--user")
        self.pwd = self.loop_options("-p", "--pwd")
        self.help = False
        self.overwrite = False
        self.api_url = self.loop_options("-a", "--api")
        self.logger = FunPDBeClientLogger("control")

    def set_help_and_overwrite_flags(self):
        for option, value in self.opts:
            if option in ["-h", "--help"]:
                self.help = True
            elif option in ["-o", "--overwrite"]:
                self.overwrite = True

    def run(self):
        """
        Main entry point
        :return: Response.text or None
        """
        self.configure()
        self.set_help_and_overwrite_flags()
        if self.help:
            print(self.client)
        elif not self.mode:
            generic_error()
            self.logger.log().error(CONTROL_ERRORS["no_mode"])
        else:
            return self.action()

        return None

    def action(self):
        """
        API calls that can be performed by
        the client
        :return: Response.text or None
        """
        actions = {
            "get": self.get,
            "post": self.post,
            "delete": self.delete,
            "validate": self.validate
        }
        if self.mode in actions.keys():
            return actions[self.mode]()
        return None

    def configure(self):
        """
        Set the user name and password
        :return: None
        """
        self.client.user.user_name = self.user_name
        self.client.user.user_pwd = self.pwd
        if self.api_url:
            url_to_use = map_url(self.api_url)
            if url_to_use:
                self.client.set_api_url(url_to_use)

    def validate(self):
        """
        Validate one or more JSON files against
        FunPDBe Schema
        :return: True or False
        """
        if not self.check_path():
            return False

        if self.path.endswith(".json"):
            return self.single_validate(self.path)
        else:
            return self.multi_validate()

    def multi_validate(self):
        """
        Validate multiple JSON files against
        FunPDBe Schema
        :return: True or False
        """
        all_valid = True
        for json_path in glob.glob("%s/*.json" % self.path):
            if not self.single_validate(json_path):
                all_valid = False
        return all_valid

    def single_validate(self, path):
        """
        Validate a single JSON
        :param path: String
        :return: Boolean
        """
        print("Parsing and validating %s" % path)
        if self.client.parse_json(path):
            return self.client.validate_json()
        return False

    def get(self):
        """
        Make GET call
        :return: Response.text or None
        """
        if self.pdb_id and self.resource:
            return self.client.get_one(self.pdb_id, self.resource)
        self.logger.log().error(CONTROL_ERRORS["no_pdb_or_resource"])
        print("Please provide both --pdb_id and --resource")
        return None

    def post(self):
        """
        Make POST call
        :return: Response.text or None
        """
        response = None
        if not self.check_path():
            return response
        if self.path.endswith(".json"):
            response = self.client.post(self.path, self.resource,
                                        self.overwrite)
        else:
            response = self.batch_post()
        return response

    def batch_post(self):
        """
        Make batch POST call
        :return: Response
        """
        response = None
        attempted = 0
        succeeded = 0
        for json_path in glob.glob("%s/*.json" % self.path):
            self.log_delimiter("start")
            response = self.client.post(json_path, self.resource,
                                        self.overwrite)
            self.client.json_data = None
            if response and response.status_code == 201:
                succeeded += 1
            attempted += 1
            self.log_delimiter("end")
        message = "Batch POSTing: %i out of %i POSTed successfully" % (
            succeeded, attempted)
        self.logger.log().info(message)
        print(message)
        return response

    def check_entry_exists(self):
        response = self.client.get_one(self.pdb_id, self.resource)
        if response.status_code == 200:
            return True
        return False

    def delete(self):
        """
        Make DELETE call
        :return: Response.text or None
        """
        self.log_delimiter("start")
        response = self.client.delete_one(self.pdb_id, self.resource)
        self.log_delimiter("end")
        return response

    def loop_options(self, opt1, opt2):
        """
        Loop through options
        :param opt1: String
        :param opt2: String
        :return: String or None
        """
        for option, value in self.opts:
            if option == opt1 or option == opt2:
                return value
        return None

    def log_delimiter(self, mode):
        if mode == "start":
            self.logger.log().info("BEGIN")
        elif mode == "end":
            self.logger.log().info("END\n")

    def check_path(self):
        """
        Check if path exists
        :return: Boolean
        """
        if not self.path:
            self.logger.log().error(CONTROL_ERRORS["no_path"])
            return False
        return True
Example #4
0
class Client(object):
    """
    The FunPDBe deposition client allows users to deposit, delete and view
    data in the FunPDBe deposition system
    """
    def __init__(self, schema, user):
        self.user = user
        self.schema = schema
        self.api_url = PROD_API_URL
        self.json_data = None
        self.logger = FunPDBeClientLogger("client")

    def __str__(self):
        return """
The FunPDBe deposition client allows users to deposit, delete and view  
data in the FunPDBe deposition system                                   

Usage parameters:
-h, --help:       Help (this is what you see now)
-u, --user:       FunPDBe user name
-p, --pwd:        FunPDBe password
-m, --mode:       Running mode (get, post, delete, validate)
-o, --overwrite:  Overwrite existing entries
-i, --pdbid:      PDB id of an entry
-r, --resource:   Name of a resource
-f, --path:       Path to JSON file (.json ending), or files (folder name)
-d, --debug:      Enable debug logging
-a, --api:        API to be used (prod (default), dev, local)
        """

    def set_api_url(self, new_url):
        """
        Setting API to other than default
        :param new_url: String, API URL
        :return: None
        """
        self.api_url = new_url

    def get_all(self, resource):
        """
        Get all FunPDBe entries based on resource name
        :param resource: String, resource name
        :return: Response
        """
        message = "GET all entries for %s" % resource
        if not self.check_resource(resource):
            return None
        self.logger.log().info(message)

        self.user_info()
        url = self.construct_get_url(resource)
        r = requests.get(url, auth=(self.user.user_name, self.user.user_pwd))

        if r.status_code == 200:
            self.logger.log().info("[%i] success" % r.status_code)
        else:
            self.log_api_error(r.status_code, r.text)

        print(r.text)
        return r

    def get_one(self, pdb_id, resource):
        """
        Get one FunPDBe entry based on PDB id and
        resource name
        :param pdb_id: String, PDB id
        :param resource: String, resource name
        :return: Response
        """
        message = "GET entry for %s" % pdb_id
        if resource and self.check_pdb_id(pdb_id):
            message += " from %s" % resource
            self.logger.log().info(message)
        else:
            return None

        self.user_info()
        url = self.construct_get_url(resource, pdb_id)
        r = requests.get(url, auth=(self.user.user_name, self.user.user_pwd))

        if r.status_code == 200:
            self.logger.log().info("[%i] success" % r.status_code)
        else:
            self.log_api_error(r.status_code, r.text)

        print(r.text)
        return r

    def post(self, path, resource, overwrite, plugin=False):
        """
        POST JSON to deposition API
        :param path: String, path to JSON file
        :param resource: String, resource name
        :param plugin: Boolean, plugin mode
        :return: None
        """
        message = "POST %s to %s (overwrite=%s)" % (path, resource, overwrite)
        self.logger.log().info(message)
        self.user_info()
        if not self.pre_post_checks(path, resource, plugin):
            return None
        if overwrite:
            return self.post_with_overwrite(resource)
        else:
            return self.post_without_overwrite(resource)

    def pre_post_checks(self, path, resource, plugin):
        if not self.check_resource(resource):
            return False
        if not self.parse_json(path) and not plugin:
            return False
        if not self.validate_json():
            return False
        return True

    def post_with_overwrite(self, resource):
        pdb_id = self.json_data["pdb_id"]
        if not self.check_pdb_id(pdb_id):
            return None
        url = self.api_url
        url += "resource/%s/%s/" % (resource, pdb_id)
        r = requests.post(url,
                          json=self.json_data,
                          auth=(self.user.user_name, self.user.user_pwd))
        check_status(r, 201, self.logger)
        return r

    def post_without_overwrite(self, resource):
        url = self.api_url
        url += "resource/%s/" % resource
        r = requests.post(url,
                          json=self.json_data,
                          auth=(self.user.user_name, self.user.user_pwd))
        check_status(r, 201, self.logger)
        return r

    def delete_one(self, pdb_id, resource):
        """
        DELETE entry based on PDB id
        :param pdb_id: String, PDB id
        :param resource: String, resource name
        :return: none
        """
        message = "DELETE entry %s from %s" % (pdb_id, resource)
        print(message)
        self.logger.log().info(message)

        if not self.check_resource(resource):
            return None
        if not self.check_pdb_id(pdb_id):
            return None
        self.user_info()
        url = self.api_url
        url += "resource/%s/%s/" % (resource, pdb_id)
        r = requests.delete(url,
                            auth=(self.user.user_name, self.user.user_pwd))
        check_status(r, 301, self.logger)
        return r

    def construct_get_url(self, resource, pdb_id=None):
        """
        Create the GET URL based on resource
        and pdb_id
        :param resource: String
        :param pdb_id: String
        :return: String
        """
        url = self.api_url
        if resource and self.check_resource(resource):
            url += "resource/%s/" % resource
            if pdb_id:
                url += "%s/" % pdb_id
            return url
        return None

    def check_pdb_id(self, pdb_id):
        """
        Check if PDB id exists and if it matches
        the regular expression pattern of a valid
        PDB identifier
        :param pdb_id: String
        :return: Boolean
        """
        if not check_exists(pdb_id, "no_pdb", self.logger):
            return False
        if re.match(PDB_ID_PATTERN, pdb_id):
            return True
        generic_error()
        self.logger.log().error(CLIENT_ERRORS["bad_pdb"])
        return False

    def check_resource(self, resource):
        """
        Check if resource name exists and
        if it is a known (registered) resource
        :param resource: String
        :return: Boolean
        """
        if not check_exists(resource, "no_resource", self.logger):
            return False
        if resource in RESOURCES:
            return True
        self.logger.log().error(CLIENT_ERRORS["unknown_resource"])
        generic_error()
        return False

    def parse_json(self, path):
        """
        Parse user JSON file
        :param path: String, path to JSON
        :return: Boolean
        """
        if not check_exists(path, "no_path", self.logger):
            return None
        try:
            with open(path) as json_file:
                try:
                    self.json_data = json.load(json_file)
                    self.logger.log().info("JSON parsed")
                    return True
                except ValueError as valerr:
                    self.logger.log().error(valerr)
                    generic_error()
                    return False
        except IOError as ioerr:
            self.logger.log().error(ioerr)
            generic_error()
            return False

    def validate_json(self):
        """
        Validate JSON against schema
        :return: Boolean
        """
        if not self.schema.json_schema:
            self.schema.get_schema()
        if self.schema.validate_json(self.json_data):
            self.logger.log().info("JSON complies with FunPDBe schema")
            self.json_data = self.schema.clean_json(self.json_data)
            return True
        self.logger.log().error(CLIENT_ERRORS["bad_json"])
        generic_error()
        return False

    def log_api_error(self, status_code, text):
        """
        Log error based on status code and
        response text
        :param status_code: Int
        :param text: String
        :return: None
        """
        self.logger.log().error("[%s] - %s" % (status_code, text))

    def user_info(self):
        """
        Prompting user to provide info if missing
        :return: None
        """
        self.user.set_user()
        self.user.set_pwd()
Example #5
0
class Control(object):
    def __init__(self, opts, client):
        self.opts = opts
        self.client = client
        self.path = self.loop_options("-f", "--path")
        self.pdb_id = self.loop_options("-i", "--pdb_id")
        self.mode = self.loop_options("-m", "--mode")
        self.resource = self.loop_options("-r", "--resource")
        self.user_name = self.loop_options("-u", "--user")
        self.pwd = self.loop_options("-p", "--pwd")
        self.help = False
        for option, value in self.opts:
            if option in ["-h", "--help"]:
                self.help = True
        self.logger = FunPDBeClientLogger("control")

    def run(self):
        self.configure()
        if self.help:
            print(self.client)
        elif not self.mode:
            generic_error()
            self.logger.log().error(CONTROL_ERRORS["no_mode"])
        else:
            return self.action()

        return None

    def action(self):
        actions = {
            "get": self.get,
            "post": self.post,
            "put": self.put,
            "delete": self.delete
        }
        if self.mode in actions.keys():
            return actions[self.mode]()
        return None

    def configure(self):
        self.client.user.user_name = self.user_name
        self.client.user.user_pwd = self.pwd

    def get(self):
        if self.pdb_id:
            return self.client.get_one(self.pdb_id, self.resource)
        else:
            return self.client.get_all(self.resource)

    def post(self):
        if not self.check_path():
            return None
        if self.path.endswith(".json"):
            return self.client.post(self.path, self.resource)
        else:
            for json_path in glob.glob("%s/*.json" % self.path):
                self.client.post(json_path, self.resource)
                self.client.json_data = None
            return True

    def put(self):
        if not self.check_path():
            return None
        return self.client.put(self.path, self.pdb_id, self.resource)

    def delete(self):
        return self.client.delete_one(self.pdb_id, self.resource)

    def loop_options(self, opt1, opt2):
        for option, value in self.opts:
            if option == opt1 or option == opt2:
                return value
        return None

    def check_path(self):
        if not self.path:
            self.logger.log().error(CONTROL_ERRORS["no_path"])
            return False
        return True