def _status_data(upload_db_data: Upload, upload_workspace: UploadWorkspace) -> dict: return { 'upload_id': upload_db_data.upload_id, 'upload_total_size': upload_workspace.total_upload_size, 'upload_compressed_size': upload_workspace.content_package_size, 'created_datetime': upload_db_data.created_datetime, 'modified_datetime': upload_db_data.modified_datetime, 'start_datetime': upload_db_data.lastupload_start_datetime, 'completion_datetime': upload_db_data.lastupload_completion_datetime, 'files': json.loads(upload_db_data.lastupload_file_summary), 'errors': json.loads(upload_db_data.lastupload_logs), 'upload_status': upload_db_data.lastupload_upload_status, 'workspace_state': upload_db_data.state, 'lock_state': upload_db_data.lock, 'source_format': upload_workspace.source_format, 'checksum': upload_workspace.content_checksum() }
def check_upload_content_exists(upload_id: int) -> Response: """ Verify that the package content exists/is available. Parameters ---------- upload_id : int The unique identifier for upload workspace. Returns ------- Standard Response tuple containing response content, HTTP status, and HTTP headers. """ try: upload_db_data: Optional[Upload] = uploads.retrieve(upload_id) except IOError: logger.error( "%s: ContentExistsCheck: There was a problem connecting " "to database.", upload_id) raise InternalServerError(UPLOAD_DB_CONNECT_ERROR) if upload_db_data is None: raise NotFound(UPLOAD_NOT_FOUND) logger.info("%s: Upload content summary request.", upload_id) upload_workspace = UploadWorkspace(upload_id) # This will potentially build content package if it does not exist checksum = upload_workspace.content_checksum() modified = '' size = 0 # Double check package exists if upload_workspace.content_package_exists: modified = upload_workspace.content_package_modified size = upload_workspace.content_package_size return {}, status.OK, { 'ETag': checksum, 'Content-Length': size, 'Last-Modified': modified } headers = {'ARXIV-OWNER': upload_db_data.owner_user_id, 'ETag': checksum} return {}, status.OK, headers
def get_upload_content(upload_id: int) -> Response: """ Package up files for downloading as a compressed gzipped tar file. Parameters ---------- upload_id : int The unique identifier for upload workspace. Returns ------- Standard Response tuple containing compressed content, HTTP status, and HTTP headers. """ try: upload_db_data: Optional[Upload] = uploads.retrieve(upload_id) except IOError: logger.error( "%s: ContentDownload: There was a problem connecting " "to database.", upload_id) raise InternalServerError(UPLOAD_DB_CONNECT_ERROR) if upload_db_data is None: raise NotFound(UPLOAD_NOT_FOUND) upload_workspace = UploadWorkspace(upload_id) checksum = upload_workspace.content_checksum() try: filepointer = upload_workspace.get_content() except FileNotFoundError as e: raise NotFound("No content in workspace") from e headers = { "Content-disposition": f"filename={filepointer.name}", 'ETag': checksum, 'ARXIV-OWNER': upload_db_data.owner_user_id } return filepointer, status.OK, headers
def client_delete_all_files(upload_id: int) -> Response: """ Delete all files uploaded by client from specified workspace. This request is being received from API so we need to be extra careful. Parameters ---------- upload_id : int The unique identifier for the upload_db_data in question. public_file_path: str relative path of file to be deleted. Returns ------- dict Complete summary of upload processing. int An HTTP status code. dict Some extra headers to add to the response. """ logger.info("%s: Deleting all uploaded files from this workspace.", upload_id) try: # Make sure we have an upload_db_data to work with upload_db_data: Optional[Upload] = uploads.retrieve(upload_id) if upload_db_data is None: # Invalid workspace identifier raise NotFound(UPLOAD_NOT_FOUND) if upload_db_data.state != Upload.ACTIVE: # Do we log anything for these requests raise Forbidden(UPLOAD_NOT_ACTIVE) if upload_db_data.lock == Upload.LOCKED: raise Forbidden(UPLOAD_WORKSPACE_LOCKED) # Create Upload object upload_workspace = UploadWorkspace(upload_id) upload_workspace.client_remove_all_files() except IOError: logger.error("%s: Delete all files request failed ", upload_id) raise InternalServerError(CANT_DELETE_ALL_FILES) except NotFound as nf: logger.info("%s: DeleteAllFiles: '%s'", upload_id, nf) raise except Forbidden as forb: logger.info("%s: Upload failed: '%s'.", upload_id, forb) raise forb except Exception as ue: logger.info( "Unknown error in delete all files. " " Add except clauses for '%s'. DO IT NOW!", ue) raise InternalServerError(UPLOAD_UNKNOWN_ERROR) response_data = _status_data(upload_db_data, upload_workspace) response_data.update({ 'reason': UPLOAD_DELETED_ALL_FILES, 'checksum': upload_workspace.content_checksum() }) # Get rid of pylint error headers = {'ARXIV-OWNER': upload_db_data.owner_user_id} return response_data, status.OK, headers
def client_delete_file(upload_id: int, public_file_path: str) -> Response: """Delete a single file. This request is being received from API so we need to be extra careful. Parameters ---------- upload_id : int The unique identifier for the upload_db_data in question. public_file_path: str relative path of file to be deleted. Returns ------- dict Complete summary of upload processing. int An HTTP status code. dict Some extra headers to add to the response. """ logger.info("%s: Delete file '%s'.", upload_id, public_file_path) try: # Make sure we have an upload_db_data to work with upload_db_data: Optional[Upload] = uploads.retrieve(upload_id) if upload_db_data is None: # Invalid workspace identifier raise NotFound(UPLOAD_NOT_FOUND) if upload_db_data.state != Upload.ACTIVE: # Do we log anything for these requests raise Forbidden(UPLOAD_NOT_ACTIVE) if upload_db_data.lock == Upload.LOCKED: raise Forbidden(UPLOAD_WORKSPACE_LOCKED) # Create Upload object upload_workspace = UploadWorkspace(upload_id) # Call routine that will do the actual work upload_workspace.client_remove_file(public_file_path) except IOError: logger.error("%s: Delete file request failed ", upload_id) raise InternalServerError(CANT_DELETE_FILE) except NotFound as nf: logger.info("%s: DeleteFile: %s", upload_id, nf) raise nf except SecurityError as secerr: logger.info("%s: %s", upload_id, secerr.description) # TODO: Should this be BadRequest or NotFound. I'm leaning towards # NotFound in order to provide as little feedback as posible to client. raise NotFound(UPLOAD_FILE_NOT_FOUND) except Forbidden as forb: logger.info("%s: Delete file forbidden: %s.", upload_id, forb) raise forb except Exception as ue: logger.info( "Unknown error in delete file. " " Add except clauses for '%s'. DO IT NOW!", ue) raise InternalServerError(UPLOAD_UNKNOWN_ERROR) response_data = _status_data(upload_db_data, upload_workspace) response_data.update({ 'reason': UPLOAD_DELETED_FILE, 'checksum': upload_workspace.content_checksum() }) # Get rid of pylint errorT headers = {'ARXIV-OWNER': upload_db_data.owner_user_id} return response_data, status.OK, headers