Ejemplo n.º 1
0
    def patch(self, res_id):
        body = json.loads(self.request.body.decode('utf-8'))
        local_data = ResourceLocalData(res_id)
        hs_data = ResourceHydroShareData(resource_manager.hs_api_conn, res_id)
        file_operations = body['operations']

        results = []
        success_count = 0
        failure_count = 0

        for operation in file_operations:
            method = operation['method']  # 'copy' or 'move'
            src_uri = operation['source']
            dest_uri = operation['destination']

            # Split paths into filesystem prefix ('hs' or 'local') and path
            # relative to the resource root on
            # that filesystem
            src_fs, src_path = src_uri.split(':')
            dest_fs, dest_path = dest_uri.split(':')

            # If this operation involves HydroShare, make sure we're
            # authenticated
            if ((src_path == HS_PREFIX or dest_fs == HS_PREFIX)
                    and not resource_manager.is_authenticated()):
                results.append({
                    'success': False,
                    'error': HYDROSHARE_AUTHENTICATION_ERROR,
                })
                failure_count += 1
                continue

            # Remove the leading forward slashes
            src_path = src_path[1:]
            dest_path = dest_path[1:]

            # Exactly what operation we perform depends on where the source
            # and destination files/folders are
            # Move/copy within HydroShare
            if src_fs == HS_PREFIX and dest_fs == HS_PREFIX:
                if method == MOVE:  # Move or rename
                    try:
                        hs_data.rename_or_move_file(Path(src_path),
                                                    Path(dest_path))
                        results.append({'success': True})
                        success_count += 1
                    except FileExistsError:
                        results.append({
                            'success': False,
                            'error': {
                                'type':
                                'FileOrFolderExists',
                                'message': (f'The file {dest_path} already '
                                            'exists in HydroShare.'),
                            },
                        })
                        failure_count += 1
                else:  # TODO: Copy (https://github.com/hydroshare/hydroshare_jupyter_sync/issues/42)
                    # The frontend never requests this, but if one were to
                    # add such functionality, you'd handle it here
                    raise NotImplementedError('Copy within HydroShare '
                                              'not implemented')
            # Move/copy within the local filesystem
            elif src_fs == LOCAL_PREFIX and dest_fs == LOCAL_PREFIX:
                if method == MOVE:  # Move or rename
                    ResourceLocalData(res_id).rename_or_move_item(
                        src_path, dest_path)
                    results.append({'success': True})
                    success_count += 1
                else:  # TODO: Copy (https://github.com/hydroshare/hydroshare_jupyter_sync/issues/42)
                    # The frontend never requests this, but if one were to
                    # add such functionality, you'd handle it here
                    raise NotImplementedError('Copy within the local '
                                              'filesystem not implemented yet')
            # Move/copy from the local filesystem to HydroShare
            elif src_fs == LOCAL_PREFIX and dest_fs == HS_PREFIX:
                # Transfer the file regardless of if we're moving or copying
                error = hs_data.upload_from_local(local_data, Path(src_path),
                                                  Path(dest_path))
                if not error and method == MOVE:
                    # Delete the local copy of the file
                    error = (ResourceLocalData(res_id).delete_file_or_folder(
                        src_path))
                results.append({
                    'success': error is None,
                    'error': error,
                })
                if error:
                    failure_count += 1
                else:
                    success_count += 1
            # Move/copy from HydroShare to the local filesystem
            elif src_fs == HS_PREFIX and dest_fs == LOCAL_PREFIX:
                # Transfer the file regardless of if we're moving or copying
                hs_data.download_to_local(local_data, Path(src_path),
                                          Path(dest_path))
                if method == MOVE:
                    # Delete the HS copy of the file
                    hs_data.delete_file_or_folder(src_path)
                results.append({'success': True})
                success_count += 1
            else:
                msg = f'"source" prefix "{src_fs}" and/or destination ' \
                      f'prefix "{dest_fs} not recognized. Valid options' \
                      f' are "hs" and "local"'
                logging.warning(msg)
                results.append({
                    'success': False,
                    'error': 'UnrecognizedPathPrefix',
                    'message': msg,
                })
                failure_count += 1

        self.write({
            'results': results,
            'successCount': success_count,
            'failureCount': failure_count,
        })
Ejemplo n.º 2
0
    def delete(self, res_id):
        if not resource_manager.is_authenticated():
            self.write({
                'success': False,
                'error': HYDROSHARE_AUTHENTICATION_ERROR,
            })
            return

        data = json.loads(self.request.body.decode('utf-8'))
        file_and_folder_paths = data.get('files')
        if file_and_folder_paths is None:
            self.set_status(400)  # Bad Request
            self.write('Could not find "files" in request body.')
            return

        hs_data = ResourceHydroShareData(resource_manager.hs_api_conn, res_id)
        success_count = 0
        failure_count = 0

        # Keep track of the folders that have been deleted so we don't try to
        # delete child files that have already
        # been deleted
        deleted_folders = []

        results = []
        for item_path in file_and_folder_paths:
            # Remove any leading /
            if item_path.startswith('/'):
                item_path = item_path[1:]
            try:
                for deleted_folder in deleted_folders:
                    # Check if this file is in a folder that was deleted (a
                    # slash is appended to ensure that a file in,
                    # say, '/My data 2' is not skipped because '/My data'
                    # was deleted)
                    if item_path.startswith(deleted_folder + '/'):
                        # We can skip deleting this file because it was already
                        # deleted with its parent folder
                        break
                else:  # Only runs if the break statement above is never hit
                    # (yes, the indentation is right here)
                    # Try to delete this item
                    deleted_type = hs_data.delete_file_or_folder(item_path)
                    if deleted_type == 'folder':
                        deleted_folders.append(item_path)
                success_count += 1
                results.append({'success': True})
            except HSExceptions.HydroShareNotFound:
                results.append({
                    'success': False,
                    'error': {
                        'type': 'NotFoundError',
                        'message': f'Could not find {item_path} in '
                        'HydroShare.',
                    },
                })
            except HSExceptions.HydroShareNotAuthorized:
                results.append({
                    'success': False,
                    'error': {
                        'type':
                        'NotAuthorizedError',
                        'message': (f'Could not delete {item_path}. Do you '
                                    'have write access to the resource?'),
                    },
                })
            except Exception as e:
                logging.error(e)
                results.append({
                    'success': False,
                    'error': {
                        'type':
                        'UnknownError',
                        'message': (f'An unknown error occurred when'
                                    ' attempting to delete {item_path}.')
                    }
                })
                failure_count += 1

        self.write({
            'results': results,
            'successCount': success_count,
            'failureCount': failure_count,
        })