def check_existance_and_fetch_image(image_id: str, user_hash: str) -> tuple: """checks if the image_id is in the database for the user and returns it. :param image_id: image_id to find :type image_id: str :param user_hash: hash that identifies a user :type user_hash: str :return: Success, error message, Image :rtype: tuple """ # Verify input types t_ok, t_err = is_type_ok(image_id, "str") if t_ok is False: return False, t_err, None t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return False, t_err, None if db.image_exists(image_id, user_hash) is False: return False, 'No image id: ' + image_id + ' found for the user', None else: image = db.get_image(image_id, user_hash) if image is not None: return True, '', image else: return False, 'Error fetching image' + image_id, None
def get_single_image(image_id: str, user_hash: str) -> dict: """get single image from server :param image_id: id of the image to download :type image_id: str :param user_hash: hash identifying user :type user_hash: str :return: dictionary with the info. see protocol :rtype: dict """ # Validate image_id type t_ok, t_err = is_type_ok(image_id, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate user_hash type t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} d = { 'image_ids': [image_id], 'format': 'PNG', 'user_hash': user_hash } try: r = requests.get(api_host+"/api/download/", json=d) return json.loads(r.text) except: return { 'success': False, 'error_msg': 'Could not connect to server', }
def get_download_images( image_ids: list, im_format: str, user_hash: str ) -> dict: """run a get request to download images :param image_ids: list of ids to download :type image_ids: list :param im_format: format to download :type im_format: str :param user_hash: hash identifying user :type user_hash: str :return: dictionary with info. see protocol :rtype: dict """ # Validate image_ids type t_ok, t_err = is_type_ok(image_ids, "list[str, ...]") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate im_format type t_ok, t_err = is_type_ok(im_format, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate user_hash type t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} d = { 'image_ids': image_ids, 'format': im_format, 'user_hash': user_hash } try: r = requests.get(api_host+"/api/download/", json=d) return json.loads(r.text) except: return { 'success': False, 'error_msg': 'Could not connect to server', }
def upload_image(image_b64s: str, filename: str, user_hash: str) -> dict: """upload a single image to the server :param image_b64s: image data as a base 64 string :type image_b64s: str :param filename: filename for the image :type filename: str :param user_hash: hash identifying the user :type user_hash: str :return: dictionary with info. see protocol :rtype: dict """ # Validate image_b64s type t_ok, t_err = is_type_ok(image_b64s, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate filename type t_ok, t_err = is_type_ok(filename, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate user_hash type t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} d = { 'filename': filename, 'user_hash': user_hash, 'description': filename, 'data': image_b64s, } try: r = requests.post(api_host+"/api/upload/image", json=d) return json.loads(r.text) except: return { 'success': False, 'error_msg': 'Could not connect to server', }
def edit_description(image_id: str, new_desc: str, user_hash: str) -> dict: """edit description of an image :param image_id: id of the image to edit :type image_id: str :param new_desc: new description for the image :type new_desc: str :param user_hash: hash identifying a user :type user_hash: str :return: dictionary with info. see protocol :rtype: dict """ # Validate image_id type t_ok, t_err = is_type_ok(image_id, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate new_desc type t_ok, t_err = is_type_ok(new_desc, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate user_hash type t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} data = { 'image_id': image_id, 'description': new_desc, 'user_hash': user_hash } try: r = requests.post(api_host + '/api/edit/description', json=data) return json.loads(r.text) except: return { 'success': False, 'error_msg': 'Could not connect to server', }
def upload_zip(zip_b64s: str, filename: str, user_hash: str) -> dict: """upload multiple images as a zip :param zip_b64s: zip file data as a base 64 string :type zip_b64s: str :param filename: filename of the zip :type filename: str :param user_hash: hash identifying a user :type user_hash: str :return: dictionary with info. see protocol :rtype: dict """ # Validate zip_b64s type t_ok, t_err = is_type_ok(zip_b64s, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate filename type t_ok, t_err = is_type_ok(filename, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate user_hash type t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} d = { 'filename': filename, 'user_hash': user_hash, 'data': zip_b64s, } try: r = requests.post(api_host+"/api/upload/zip", json=d) return json.loads(r.text) except: return { 'success': False, 'error_msg': 'Could not connect to server', }
def get_image_info(user_hash: str) -> dict: """ get information of all the user images Get the following information: ['filename', 'img_format', 'timestamp', 'size', 'description'] from all the images that belong the the user. :param user_hash: hash that identifies a user :type user_hash: str :return: dictionary with success(bool), error_msg(str) or the images information :rtype: dict """ # Verify input types t_ok, t_err = is_type_ok( user_hash, "str" ) if t_ok is False: return { 'success': False, 'error_msg': t_err, } # Log Action logging.info("{} - {} - CALLED: {} INPUT_ARGS: {}".format( user_hash, datetime.now(), 'get_image_info', '' ) ) # fetch all images for the user images = db.get_all_user_images(user_hash) # create a dictionary with all the image info out_dict = {} if images is not None: for img in images: out_dict[str(img._id)] = { 'filename': img.filename, 'img_format': img.img_format, 'timestamp': img.timestamp, 'size': img.size, 'description': img.description, } # return the info return out_dict
def get_images_info(user_hash: str) -> dict: """get information of all the images that belong to the user :param user_hash: hash identifying a user :type user_hash: str :return: dictionary with all the info. see protocol :rtype: dict """ # Validate user_hash type t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} try: r = requests.get(api_host + '/api/image_info/' + user_hash) return json.loads(r.text) except: return { 'success': False, 'error_msg': 'Could not connect to server', }
def apply_algorithm( image_id: str, algorithm: str, im_format: str, out_filename: str, user_hash: str ) -> dict: """Apply an image processing algorithm ot an image :param image_id: id of the image to process :type image_id: str :param algorithm: algorithm to apply :type algorithm: str :param im_format: format of the output image :type im_format: str :param out_filename: name of the output image :type out_filename: str :param user_hash: hash identifying a user :type user_hash: str :return: dictionary with info. see protocol :rtype: dict """ # Validate image_id type t_ok, t_err = is_type_ok(image_id, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate algorithm type t_ok, t_err = is_type_ok(algorithm, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate im_format type t_ok, t_err = is_type_ok(im_format, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate out_filename type t_ok, t_err = is_type_ok(out_filename, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} # Validate user_hash type t_ok, t_err = is_type_ok(user_hash, "str") if t_ok is False: return {'success': False, 'error_msg': t_err} d = { 'image_id': image_id, 'algorithm': algorithm, 'out_image_format': im_format, 'out_image_filename': out_filename, 'user_hash': user_hash, } try: r = requests.post(api_host+"/api/image_process", json=d) return json.loads(r.text) except: return { 'success': False, 'error_msg': 'Could not connect to server', }
def image_process(image_process_dict: dict) -> dict: """ Apply processing algorithm to an image This function validates input data, fetches an image, applies a processing algorithm to it, converts it to a new format and stores it in the database as a new image with a new image filename, :param image_process_dict: dictionary with all the required information :type image_process_dict: dict :return: dictionary with success(bool), error_msg(str) :rtype: dict """ # Verify input types t_ok, t_err = is_type_ok( image_process_dict, """ dict{ 'image_id': str, 'algorithm':str, 'out_image_format': str, 'out_image_filename':str, 'user_hash': str, } """ ) if t_ok is False: return { 'success': False, 'error_msg': t_err, } # Log Action logging.info("{} - {} - CALLED: {} INPUT_ARGS: {}".format( image_process_dict['user_hash'], datetime.now(), 'image_process', ";".join( [ 'image_id: ' + image_process_dict['image_id'], 'algorithm: ' + image_process_dict['algorithm'], 'out_image_format: ' + image_process_dict['out_image_format'], 'out_image_filename: ' + image_process_dict['out_image_filename'], ] ) ) ) image_id = image_process_dict['image_id'] algorithm = image_process_dict['algorithm'] out_image_format = image_process_dict['out_image_format'] out_image_filename = image_process_dict['out_image_filename'] user_hash = image_process_dict['user_hash'] # Check if algorithm is correct if img_proc.is_valid_algorithm(algorithm) is False: return { 'success': False, 'error_msg': 'Unknown algorithm: ' + algorithm, 'processing_time': 0.0 } # Check if image exists and fetch it result, errmsg, in_image = check_existance_and_fetch_image( image_id, user_hash ) if result is False: return { 'success': False, 'error_msg': errmsg, 'processing_time': 0.0 } # Start measuring ellapsed time start_time = datetime.now() image_fio = b64s_to_fio(in_image.data) # Extract size from image data im_size = img_proc.get_image_size(image_fio) # Transform image using algorithm out_image_fio = img_proc.transform_image(image_fio, algorithm) # Convert image format out_image_fio = img_proc.format_convert(out_image_fio, out_image_format) result = db.add_image( filename=out_image_filename, img_format=out_image_format, description='Created using ' + algorithm + ' on ' + in_image.filename, size=im_size, timestamp=datetime.now(), data=fio_to_b64s(out_image_fio), user_hash=user_hash ) if result is False: return { 'success': False, 'error_msg': 'Error adding image' + out_image_filename + ' to database\n', 'processing_time': 0.0 } # Stop measuring ellapsed time end_time = datetime.now() ellapsed_time = end_time-start_time return { 'success': True, 'error_msg': '', 'processing_time': ellapsed_time.total_seconds() }
def download(download_images_dict: dict) -> dict: """ download single or multiple images To download a single or multiple images from the server, the user calls this api function through the RESTapi. This function validates the input dict and calls: download_signle_image or download_multiple_images And returns a dicionary with success and error message :param download_images_dict: dictionary with all the required info (see protocol) :type download_images_dict: dict :return: dictionary with success(bool), error_msg(str) :rtype: dict """ # Verify input types t_ok, t_err = is_type_ok( download_images_dict, """ dict{ 'image_ids': list[str...], 'format': str, 'user_hash': str } """ ) if t_ok is False: return { 'success': False, 'error_msg': t_err, } # Log Action logging.info("{} - {} - CALLED: {} INPUT_ARGS: {}".format( download_images_dict['user_hash'], datetime.now(), 'download', ";".join( [ 'image_ids: ' + ','.join(download_images_dict['image_ids']), 'format: ' + download_images_dict['format'] ] ) ) ) # Extract image id, format and user hash from input data img_ids = download_images_dict['image_ids'] img_format = download_images_dict['format'] user_hash = download_images_dict['user_hash'] if len(img_ids) == 1: return download_signle_image( image_id=img_ids[0], image_format=img_format, user_hash=user_hash ) else: return download_multiple_images( image_ids=img_ids, image_format=img_format, user_hash=user_hash )
def edit_image_filename(edit_image_filename_dict: dict) -> dict: """ edit the filename of an image This function validates the input dict, fetches the image and changes its filename. And returns a dicionary with success and error message TODO: Add this function to the client and protocol :param edit_image_filename_dict: dictionary with all the required info (see protocol) :type edit_image_filename_dict: dict :return: dictionary with success(bool), error_msg(str) :rtype: dict """ # Verify input types t_ok, t_err = is_type_ok( edit_image_filename_dict, """ dict{ 'image_id': str, 'filename': str, 'user_hash': str } """ ) if t_ok is False: return { 'success': False, 'error_msg': t_err, } # Log Action logging.info("{} - {} - CALLED: {} INPUT_ARGS: {}".format( edit_image_filename_dict['user_hash'], datetime.now(), 'edit_image_filename', ";".join( [ 'image_id: ' + edit_image_filename_dict['image_id'], 'filename: ' + edit_image_filename_dict['filename'] ] ) ) ) # Extract image id and user hash from input data image_id = edit_image_filename_dict['image_id'] user_hash = edit_image_filename_dict['user_hash'] # Check if image id exists (and fetch it) result, errmsg, image = check_existance_and_fetch_image( image_id, user_hash ) if result is False: return { 'success': False, 'error_msg': errmsg, } # Edit Description image.filename = edit_image_filename_dict['filename'] # Save image try: image.save() except: return { 'success': False, 'error_msg': 'Could not save edited image', } return { 'success': True, 'error_msg': '', }
def upload_image(upload_img_dict: dict) -> dict: """ upload single image this function receives an image file in base64 string and adds it to the database. :param upload_img_dict: dictionary with all the info :type upload_img_dict: dict :return: dictionary with success(bool), error_msg(str) :rtype: dict """ # Verify input types t_ok, t_err = is_type_ok( upload_img_dict, """ dict{ 'filename': str, 'description': str, 'data': str, 'user_hash': str } """ ) if t_ok is False: return { 'success': False, 'error_msg': t_err, } # Log Action logging.info("{} - {} - CALLED: {} INPUT_ARGS: {}".format( upload_img_dict['user_hash'], datetime.now(), 'upload_image', ";".join( [ 'filename: ' + upload_img_dict['filename'], 'description: ' + upload_img_dict['description'] ] ) ) ) # Create image file IO image_fio = b64s_to_fio(upload_img_dict['data']) # Verify that the received data is actually an image if img_proc.is_image(image_fio) is False: return { 'success': False, 'error_msg': 'image_data cant be identified as an base64 formatted image file', } # Extract size and format from image data im_size = img_proc.get_image_size(image_fio) im_format = img_proc.get_image_format(image_fio) im_filename = name_from_path(upload_img_dict['filename']) # Store the new image in the database result = db.add_image( filename=im_filename, img_format=im_format, description=upload_img_dict['description'], size=im_size, timestamp=datetime.now(), data=upload_img_dict['data'], user_hash=upload_img_dict['user_hash'], ) if result is False: return { 'success': False, 'error_msg': 'Error adding image to database', } # If everything went well return { 'success': True, 'error_msg': '', }
def upload_multiple_images(upload_mult_img_dict: dict) -> dict: """ upload multiple images as a zip file this function receives a zip file in base64 string and extracts all the images from it and adds them to the database. :param upload_mult_img_dict: dictionary with all the info :type upload_mult_img_dict: dict :return: dictionary with success(bool), error_msg(str) :rtype: dict """ # Verify input types t_ok, t_err = is_type_ok( upload_mult_img_dict, """ dict{ 'filename': str, 'user_hash': str, 'data': str, } """ ) if t_ok is False: return { 'success': False, 'error_msg': t_err, } # Log Action logging.info("{} - {} - CALLED: {} INPUT_ARGS: {}".format( upload_mult_img_dict['user_hash'], datetime.now(), 'upload_multiple_images', ";".join( [ 'filename: ' + upload_mult_img_dict['filename'] ] ) ) ) # Extract user hash from input data user_hash = upload_mult_img_dict['user_hash'] # Create zip file IO zip_fio = b64s_to_fio(upload_mult_img_dict['data']) # Verify that the received data is actually a zip file if is_zip(zip_fio) is False: return { 'success': False, 'error_msg': 'data cant be identified as a zip file in base64 string format', } # Process each file inside the zip results = [] errs = [] for name, image_fio in files_from_zip(zip_fio): # Verify that the current file is actually an image if img_proc.is_image(image_fio) is False: results.append(False) errs.append( name + 'file can not be identified as an image. Ignored \n' ) continue # Extract size and format from image data im_size = img_proc.get_image_size(image_fio) im_format = img_proc.get_image_format(image_fio) im_filename = name_from_path(name) # Store the new image in the database result = db.add_image( filename=im_filename, img_format=im_format, description="extracted from " + upload_mult_img_dict['filename'], size=im_size, timestamp=datetime.now(), data=fio_to_b64s(image_fio), user_hash=user_hash, ) if result is False: results.append(False) errs.append( 'Error adding image' + name + ' to database\n' ) continue # return all the error messages return { 'success': all(results), 'error_msg': '\n'.join(errs), }
def test_is_type_ok(str_type, var, expected): from core.verification import is_type_ok valid, errorstr = is_type_ok(var, str_type) assert valid == expected