def wrapper(*args, **kwargs): if not current_user.is_authenticated: api_errors = ApiErrors() api_errors.status_code = 403 api_errors.add_error('global', "API key or login required") raise api_errors return f(*args, **kwargs)
def check_has_role(user, role_type): try: Role.query.filter_by(user=user, type=role_type).one() return True except NoResultFound: api_errors = ApiErrors() api_errors.add_error('global', "You don't have the rights for this") raise api_errors
def get_scrap(): try: content = content_from_url(request.args.get('url')) except ArticleException: api_errors = ApiErrors() api_errors.add_error('url', 'url is invalid') raise api_errors return jsonify(as_dict(content))
def internal_error(exception): tb = traceback.format_exc() oneline_stack = ''.join(tb).replace('\n', ' ### ') app.logger.error('500 on %s %s — %s', request.method, request.url, oneline_stack) api_errors = ApiErrors() api_errors.add_error( 'global', "Il semble que nous ayons des problèmes techniques :(" + " On répare ça au plus vite.") return jsonify([api_errors.errors]), 500
def check_allowed_changes_for_user(data): changes_allowed = {'email'} changes_asked = set(data) api_errors = ApiErrors() changes_not_allowed = changes_asked.difference(changes_allowed) if changes_not_allowed: for change in changes_not_allowed: api_errors.add_error( change, 'Vous ne pouvez pas changer cette information') raise api_errors
def internal_error(exception): tb = traceback.format_exc() oneline_stack = ''.join(tb).replace('\n', ' ### ') app.logger.error('500 on %s %s — %s', request.method, request.url, oneline_stack) api_errors = ApiErrors() api_errors.add_error( 'global', 'It seems whe have troubles with our server... We will fix soon as we can !' ) return jsonify([api_errors.errors]), 500
def check_single_order_by_string(order_by_string): order_by_string = order_by_string.strip(' ') optional_table_prefix = '("?\\w+"?\\.|)' column_identifier = '"?\\w+"?' optional_sorting_order = '(|\\s+desc|\\s+asc)' if not re.match(f'^{optional_table_prefix}{column_identifier}{optional_sorting_order}$', order_by_string, re.IGNORECASE): api_errors = ApiErrors() api_errors.add_error('order_by', 'Invalid order_by field : "%s"' % order_by_string) raise api_errors
def get_trending(source_id): trending_type = request.args.get('type', 'article') trending = trending_from(trending_type, source_id) if not trending: api_errors = ApiErrors() api_errors.add_error( 'sourceId', '{} {} not found'.format(trending_type, source_id)) raise api_errors return jsonify(trending), 200
def get_sandbox(getter_name): for key in dir(getters): module = getattr(getters, key) if hasattr(module, getter_name): getter = getattr(module, getter_name) obj = getter() return jsonify(obj) errors = ApiErrors() errors.add_error( 'getter', 'Il n\'existe pas de tel \"{}\" getter pour la sandbox'.format( getter_name)) raise errors
def post_new_password(): validate_new_password_request(request) token = request.get_json()['token'] new_password = request.get_json()['newPassword'] user = find_user_by_reset_password_token(token) if not user: api_errors = ApiErrors() api_errors.add_error('token', 'Votre lien de changement de mot de passe est invalide.') raise api_errors check_reset_token_validity(user) check_password_strength('newPassword', new_password) user.set_password(new_password) ApiHandler.save(user) return '', 204
def query_with_order_by(query, order_by): if order_by: if type(order_by) == str: order_by = text(order_by) try: order_by = [order_by] if not isinstance(order_by, list) \ else order_by query = query.order_by(*order_by) except ProgrammingError as e: field = re.search('column "?(.*?)"? does not exist', e._message, re.IGNORECASE) if field: errors = ApiErrors() errors.add_error('order_by', 'order_by value references an unknown field : ' + field.group(1)) raise errors else: raise e return query
def get_credentials_from_service_account_string(service_account_string): if service_account_string is None: errors = ApiErrors() errors.add_error('file', 'Bad google credentials.') raise errors json_payload = json.loads(service_account_string) json_path = '{}/{}_client_secret.json'.format( GOOGLE_TMP_PATH, json_payload['client_email'].split('@')[0].replace('-', '_')) with open(json_path, 'w') as outfile: json.dump(json_payload, outfile) credentials = service_account.Credentials.from_service_account_file( json_path, scopes=SCOPES) return credentials
def find_file_from_name(name, drive_id=None, parent_folder_id=None, service_account_string=None): files = find_files_from_name(name, drive_id=drive_id, parent_folder_id=parent_folder_id, service_account_string=service_account_string) files_count = len(files) if files_count == 1: return files[0] if files_count > 1: errors = ApiErrors() errors.add_error('file', 'Found several files for this name') raise errors
def validate_reset_request(request): if 'email' not in request.get_json(): errors = ApiErrors() errors.add_error('email', 'Email is missing.') raise errors if not request.get_json()['email']: errors = ApiErrors() errors.add_error('email', 'This Email is empty.') raise errors
def validate_new_password_request(request): if 'token' not in request.get_json(): errors = ApiErrors() errors.add_error('token', 'Your token link is invalid.') raise errors if 'newPassword' not in request.get_json(): errors = ApiErrors() errors.add_error('newPassword', 'You need to enter a new password.') raise errors
def get_credentials_from_service_account_string(service_account_string): if service_account_string is None: errors = ApiErrors() errors.add_error('file', 'Bad google credentials.') raise errors json_payload = json.loads(service_account_string) json_path = '/tmp/client_secret.json' with open(json_path, 'w') as outfile: json.dump(json_payload, outfile) credentials = service_account.Credentials.from_service_account_file( json_path, scopes=SCOPES) os.remove(json_path) return credentials
def check_thumb_in_request(files, form): missing_image_error = ApiErrors({'thumb': ["This field is obligatory"]}) if 'thumb' in files: if files['thumb'].filename == '': raise missing_image_error elif 'thumbUrl' not in form: raise missing_image_error
def read_thumb(files=None, form=None): if 'thumb' in files: thumb = files['thumb'] filename_parts = thumb.filename.rsplit('.', 1) if len(filename_parts) < 2 \ or filename_parts[1].lower() not in ALLOWED_EXTENSIONS: raise ApiErrors({ 'thumb': [ f"Cette image manque d'une extension {READABLE_EXTENSIONS} ou son format n'est pas autorisé" ] }) return thumb.read() if 'thumbUrl' in form: try: return _fetch_image(form['thumbUrl']) except ValueError as e: logger.error(e) raise ApiErrors( {'thumbUrl': ["Th L'adresse saisie n'est pas valide"]})
def check_password_strength(field_name, field_value): at_least_one_uppercase = '(?=.*?[A-Z])' at_least_one_lowercase = '(?=.*?[a-z])' at_least_one_digit = '(?=.*?[0-9])' min_length = '.{12,}' at_least_one_special_char = '(?=.*?[#~|=;:,+><?!@$%^&*_.-])' regex = '^' \ + at_least_one_uppercase \ + at_least_one_lowercase \ + at_least_one_digit \ + at_least_one_special_char \ + min_length \ + '$' if not re.match(regex, field_value): errors = ApiErrors() errors.add_error( field_name, 'Le mot de passe doit faire au moins 12 caractères et contenir à minima ' '1 majuscule, 1 minuscule, 1 chiffre et 1 caractère spécial parmi _-&?~#|^@=+.$,<>%*!:;' ) raise errors
def check_thumb_quality(thumb: bytes): errors = [] if len(thumb) < MINIMUM_FILE_SIZE: errors.append("L'image doit faire 100 ko minimum") image = Image.open(BytesIO(thumb)) if image.width < 400 or image.height < 400: errors.append("L'image doit faire 400 * 400 px minimum") if len(errors) > 1: errors = ["L'image doit faire 100 ko minimum et 400 * 400 px minimum"] if errors: raise ApiErrors({'thumb': errors})
def validate_change_password_request(json): errors = ApiErrors() if 'oldPassword' not in json: errors.add_error('oldPassword', 'Old password is missing.') raise errors if 'newPassword' not in json: errors.add_error('newPassword', 'New password is missing.') raise errors
def check_new_password_validity(user, old_password, new_password): errors = ApiErrors() if not user.check_password(old_password): errors.add_error('oldPassword', 'Your old password is incorrect.') raise errors if user.check_password(new_password): errors.add_error('newPassword', 'You new password is the same as the old one.') raise errors
def _fetch_image(thumb_url: str) -> bytes: if not thumb_url[0:4] == 'http': raise ValueError('Invalid thumb URL : %s' % thumb_url) try: response = requests.get(thumb_url) except Exception as e: logger.error(e) raise ApiErrors({ 'thumbUrl': ["Impossible de télécharger l'image à cette adresse"] }) content_type = response.headers['Content-type'] is_an_image = content_type.split('/')[0] == 'image' if response.status_code == 200 and is_an_image: return response.content else: raise ValueError( 'Error downloading thumb from url %s (status_code : %s)' % (thumb_url, str(response.status_code)))
def _find_folder_from_name(name, drive_id=None, force_create=False, parent_folder_id=None, service_account_string=None): body = {'mimeType': 'application/vnd.google-apps.folder', 'name': name} if not parent_folder_id: parent_folder_id = drive_id body['parents'] = [parent_folder_id] folders = find_folders_from_name( name, drive_id=drive_id, parent_folder_id=parent_folder_id, service_account_string=service_account_string) folders_count = len(folders) if folders_count == 1: return folders[0] if folders_count > 1: errors = ApiErrors() errors.add_error('name', 'Found several folders for this name') raise errors if force_create: return create_google_service('drive', service_account_string).files() \ .create( body=body, fields='id', supportsAllDrives=True) \ .execute() errors = ApiErrors() errors.add_error('folder', '{} folder was not found.'.format(name)) raise errors
def check_thumb_quality(thumb: bytes): errors = [] if len(thumb) < MINIMUM_FILE_SIZE: errors.append('Picture must have a minimal size of {} ko.'.format( MINIMUM_FILE_SIZE)) image = Image.open(BytesIO(thumb)) print(image.width, image.height) if image.width < MINIMUM_HEIGHT_SIZE or image.height < MINIMUM_WIDTH_SIZE: errors.append('Picture must be at least {} * {} px.'.format( MINIMUM_WIDTH_SIZE, MINIMUM_HEIGHT_SIZE)) if len(errors) > 1: errors = [ 'Picture must have a minimal size of {} ko and at least {} * {} px.' .format(MINIMUM_FILE_SIZE, MINIMUM_WIDTH_SIZE, MINIMUM_HEIGHT_SIZE) ] if errors: raise ApiErrors({'thumb': errors})
def restize_not_found_route_errors(exception): api_errors = ApiErrors() api_errors.add_error('data', 'Not Found') return jsonify([api_errors.errors]), 404
def check_reset_token_validity(user): if datetime.utcnow() > user.resetPasswordTokenValidityLimit: errors = ApiErrors() errors.add_error('token', 'Votre lien de changement de mot de passe est périmé. Veuillez effecture une nouvelle demande.') raise errors
def check_and_read_files_thumb(files=None): if 'thumb' in files: thumb = files['thumb'] if files['thumb'].filename == '': api_errors = ApiErrors() api_errors.add_error('thumb', "You need a name for your thumb file") raise api_errors filename_parts = thumb.filename.rsplit('.', 1) if len(filename_parts) < 2 \ or filename_parts[1].lower() not in ALLOWED_EXTENSIONS: api_errors = ApiErrors() api_errors.add_error( 'thumb', "This thumb needs a (.png, .jpg...) like or its format is not authorized" ) raise api_errors return thumb.read() api_errors = ApiErrors() api_errors.add_error('thumb', "You need to provide a thumb in your request") raise api_errors
def send_401(): api_errors = ApiErrors() api_errors.add_error('global', 'Authentification nécessaire') return jsonify([api_errors.errors]), 401
def invalid_id_for_dehumanize_error(exception): api_errors = ApiErrors() api_errors.add_error('global', 'La page que vous recherchez n\'existe pas') app.logger.error('404 %s' % str(exception)) return jsonify([api_errors.errors]), 404