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 delete_folder(db_folder, user_account, data_manager, permissions_manager, logger): """ Recursively deletes a disk folder, it's sub-folders and images, adds image deletion history, and marks as deleted all the associated database records. This method may therefore take a long time. The user account must have Delete Folder permission for the containing folder, or alternatively have the file admin system permission. The root folder cannot be deleted. This method creates and commits its own separate database connection in an attempt to keep the operation is as atomic as possible. Note however that if there is an error deleting the folder tree (in the database or on disk), operations already performed are not rolled back, and the database may become out of sync with the file system. Returns the updated folder object, including all affected sub-folders. Raises a ValueError if the source folder is the root folder. Raises an OSError on error deleting disk files or folders. Raises a DBError for database errors. Raises a SecurityError if the current user does not have sufficient permission to perform the delete. """ db_session = data_manager.db_get_session() success = False try: # Connect db_folder to our database session db_folder = data_manager.get_folder(db_folder.id, _db_session=db_session) if not db_folder: raise DoesNotExistError('Folder ID %d does not exist' % db_folder.id) # Don't allow deletion of root folder if db_folder.is_root(): raise ValueError('Cannot delete the root folder') # Require Delete Folder permission on the parent folder if user_account: permissions_manager.ensure_folder_permitted( db_folder.parent, FolderPermission.ACCESS_DELETE_FOLDER, user_account ) logger.info( 'Disk folder %s is being deleted by %s' % (db_folder.path, user_account.username if user_account else 'System') ) # Delete the disk folder first, as this is the most likely thing to fail. # Note that this might involve deleting files and directories we haven't # got database entries for (but that doesn't matter). filesystem_manager.delete_dir(db_folder.path, recursive=True) # Now delete all the data data_manager.delete_folder( db_folder, purge=False, history_user=user_account, history_info='Folder deleted by user', _db_session=db_session, _commit=False ) # OK! logger.info( 'Disk folder %s successfully deleted by %s' % (db_folder.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()