def burst_pdf(**kwargs): """ A task that creates a sub-folder next to a PDF file and extracts all pages from the PDF as PNG files into the sub-folder. """ from flask_app import app from filesystem_manager import get_abs_path, get_burst_path, get_file_data from filesystem_manager import delete_dir, make_dirs, path_exists from filesystem_sync import delete_folder from imagemagick import imagemagick_burst_pdf from models import Folder from util import get_file_extension (src,) = _extract_parameters(["src"], **kwargs) burst_folder_rel = get_burst_path(src) # Ensure src is a PDF if get_file_extension(src) not in app.config["PDF_FILE_TYPES"]: app.log.warn("Cannot burst non-PDF file: " + src) return # See if the burst folder already exists (in the database and on disk) db_folder = app.data_engine.get_folder(folder_path=burst_folder_rel) if db_folder is not None and db_folder.status == Folder.STATUS_ACTIVE: # Wipe the folder, old images, data, and uncache the old images delete_folder(db_folder, None, app.data_engine, None, app.log) deleted_ids = app.data_engine.list_image_ids(db_folder) for image_id in deleted_ids: app.image_engine._uncache_image_id(image_id) # See if the burst folder already exists (just on disk) if path_exists(burst_folder_rel, require_directory=True): # Wipe the folder and old images delete_dir(burst_folder_rel, recursive=True) # Create the burst folder and burst pdf_data = get_file_data(src) if pdf_data is not None: make_dirs(burst_folder_rel) burst_folder_abs = get_abs_path(burst_folder_rel) if not imagemagick_burst_pdf(pdf_data, burst_folder_abs, app.config["PDF_BURST_DPI"]): app.log.warn("Failed to burst PDF: " + src) else: app.log.warn("Cannot burst PDF, file not found: " + src)
def create_folder(rel_path, user_account, data_manager, permissions_manager, logger): """ Creates a folder on disk and the associated database record. The folder path cannot be blank and should not already exist. The user account must have Create Folder permission for the parent folder, or alternatively have the file admin system permission. This method creates and commits its own separate database connection so that the operation is atomic. Returns the new folder object. Raises an AlreadyExistsError if the folder path already exists. Raises an OSError if the new folder cannot be created. Raises a ValueError if the folder path is invalid. Raises a DBError for database errors. Raises a SecurityError if the current user does not have sufficient permission to create the folder, or if the folder path is outside of IMAGES_BASE_DIR. """ db_session = data_manager.db_get_session() success = False try: _validate_path_chars(rel_path) rel_path = filepath_normalize(rel_path) rel_path = _secure_folder_path( rel_path, True, app.config['ALLOW_UNICODE_FILENAMES'] ) # Don't allow blank path if strip_seps(rel_path) == '': raise ValueError('Folder path to create cannot be empty') # Check for existing (physical) path if path_exists(rel_path): raise AlreadyExistsError('Path already exists: ' + rel_path) # Check permissions for the (nearest existing) db parent folder if user_account: db_parent_folder = _get_nearest_parent_folder( rel_path, data_manager, db_session ) permissions_manager.ensure_folder_permitted( db_parent_folder, FolderPermission.ACCESS_CREATE_FOLDER, user_account ) # Create the physical folder filesystem_manager.make_dirs(rel_path) # Update the database db_folder = auto_sync_existing_folder( rel_path, data_manager, _db_session=db_session ) # OK! logger.info( 'Disk folder %s created by %s' % (rel_path, user_account.username if user_account else 'System') ) success = True return db_folder finally: # Commit or rollback database try: if success: db_session.commit() else: db_session.rollback() finally: db_session.close()