diff --git a/ckanext/unfold/adapters/_7z.py b/ckanext/unfold/adapters/_7z.py index da6c6a8..77951a7 100644 --- a/ckanext/unfold/adapters/_7z.py +++ b/ckanext/unfold/adapters/_7z.py @@ -17,7 +17,9 @@ log = logging.getLogger(__name__) -def build_directory_tree(filepath: str, remote: Optional[bool] = False): +def build_directory_tree( + filepath: str, resource_view: dict[str, Any], remote: Optional[bool] = False +): try: if remote: file_list = get7zlist_from_url(filepath) diff --git a/ckanext/unfold/adapters/gzip.py b/ckanext/unfold/adapters/gzip.py index 066c148..94cbcca 100644 --- a/ckanext/unfold/adapters/gzip.py +++ b/ckanext/unfold/adapters/gzip.py @@ -8,7 +8,9 @@ import ckanext.unfold.utils as unf_utils -def build_directory_tree(filepath: str, remote: Optional[bool] = False): +def build_directory_tree( + filepath: str, resource_view: dict[str, Any], remote: Optional[bool] = False +): resource = _get_resource(filepath) return [_build_node(resource)] diff --git a/ckanext/unfold/adapters/rar.py b/ckanext/unfold/adapters/rar.py index 10a585e..2ba9223 100644 --- a/ckanext/unfold/adapters/rar.py +++ b/ckanext/unfold/adapters/rar.py @@ -20,17 +20,19 @@ def build_directory_tree( - filepath: str, remote: Optional[bool] = False + filepath: str, resource_view: dict[str, Any], remote: Optional[bool] = False ) -> list[unf_types.Node]: try: if remote: file_list = get_rarlist_from_url(filepath) else: with rarfile.RarFile(filepath) as archive: - if archive.needs_password(): + if archive.needs_password() and not resource_view.get("archive_pass"): raise unf_exception.UnfoldError( "Error. Archive is protected with password" ) + elif archive.needs_password(): + archive.setpassword(resource_view["archive_pass"]) file_list: list[RarInfo] = archive.infolist() except RarError as e: @@ -38,6 +40,11 @@ def build_directory_tree( except requests.RequestException as e: raise unf_exception.UnfoldError(f"Error fetching remote archive: {e}") + if not file_list: + raise unf_exception.UnfoldError( + "Error. The archive is either empty or the password is incorrect." + ) + nodes: list[unf_types.Node] = [] for entry in file_list: diff --git a/ckanext/unfold/adapters/rpm.py b/ckanext/unfold/adapters/rpm.py index f1270db..45e398a 100644 --- a/ckanext/unfold/adapters/rpm.py +++ b/ckanext/unfold/adapters/rpm.py @@ -14,7 +14,9 @@ log = logging.getLogger(__name__) -def build_directory_tree(filepath: str, remote: Optional[bool] = False): +def build_directory_tree( + filepath: str, resource_view: dict[str, Any], remote: Optional[bool] = False +): try: if remote: file_list = get_rpmlist_from_url(filepath) diff --git a/ckanext/unfold/adapters/tar.py b/ckanext/unfold/adapters/tar.py index b7a973d..cfe9a7e 100644 --- a/ckanext/unfold/adapters/tar.py +++ b/ckanext/unfold/adapters/tar.py @@ -19,7 +19,10 @@ def build_directory_tree( - filepath: str, remote: Optional[bool] = False, compression: Optional[str] = None + filepath: str, + resource_view: dict[str, Any], + remote: Optional[bool] = False, + compression: Optional[str] = None, ): mode = "r" if not compression else f"r:{compression}" diff --git a/ckanext/unfold/adapters/zip.py b/ckanext/unfold/adapters/zip.py index 2025f03..382a93d 100644 --- a/ckanext/unfold/adapters/zip.py +++ b/ckanext/unfold/adapters/zip.py @@ -18,7 +18,7 @@ def build_directory_tree( - filepath: str, remote: Optional[bool] = False + filepath: str, resource_view: dict[str, Any], remote: Optional[bool] = False ) -> list[unf_types.Node]: try: if remote: diff --git a/ckanext/unfold/assets/js/unfold-init-jstree.js b/ckanext/unfold/assets/js/unfold-init-jstree.js index bdb0874..19c97b7 100644 --- a/ckanext/unfold/assets/js/unfold-init-jstree.js +++ b/ckanext/unfold/assets/js/unfold-init-jstree.js @@ -4,6 +4,7 @@ ckan.module("unfold-init-jstree", function ($, _) { options: { data: null, resourceId: null, + resourceViewId: null }, initialize: function () { @@ -17,7 +18,7 @@ ckan.module("unfold-init-jstree", function ($, _) { $.ajax({ url: this.sandbox.url("/api/action/get_archive_structure"), - data: { "id": this.options.resourceId }, + data: { "id": this.options.resourceId, "view_id": this.options.resourceViewId }, success: this._onSuccessRequest }); }, diff --git a/ckanext/unfold/logic/action.py b/ckanext/unfold/logic/action.py index 8929244..8da3d96 100644 --- a/ckanext/unfold/logic/action.py +++ b/ckanext/unfold/logic/action.py @@ -3,19 +3,22 @@ import ckanext.unfold.exception as unf_exception import ckanext.unfold.logic.schema as unf_schema -import ckanext.unfold.utils as unf_utils import ckanext.unfold.types as unf_types +import ckanext.unfold.utils as unf_utils @tk.side_effect_free @validate(unf_schema.get_archive_structure) def get_archive_structure(context, data_dict): resource = tk.get_action("resource_show")(context, {"id": data_dict["id"]}) + resource_view = tk.get_action("resource_view_show")( + context, {"id": data_dict["view_id"]} + ) try: return [ n.model_dump() if isinstance(n, unf_types.Node) else n - for n in unf_utils.get_archive_tree(resource) + for n in unf_utils.get_archive_tree(resource, resource_view) ] except unf_exception.UnfoldError as e: return {"error": str(e)} diff --git a/ckanext/unfold/logic/schema.py b/ckanext/unfold/logic/schema.py index 43e57de..865d9ed 100644 --- a/ckanext/unfold/logic/schema.py +++ b/ckanext/unfold/logic/schema.py @@ -9,9 +9,17 @@ @validator_args def get_preview_schema(ignore_empty, unicode_safe, url_validator) -> Schema: - return {"file_url": [ignore_empty, unicode_safe, url_validator]} + return { + "file_url": [ignore_empty, unicode_safe, url_validator], + "archive_pass": [ignore_empty, unicode_safe], + } @validator_args -def get_archive_structure(not_empty, unicode_safe, resource_id_exists) -> Schema: - return {"id": [not_empty, unicode_safe, resource_id_exists]} +def get_archive_structure( + not_empty, unicode_safe, resource_id_exists, resource_view_id_exists +) -> Schema: + return { + "id": [not_empty, unicode_safe, resource_id_exists], + "view_id": [not_empty, unicode_safe, resource_view_id_exists], + } diff --git a/ckanext/unfold/logic/validators.py b/ckanext/unfold/logic/validators.py new file mode 100644 index 0000000..f95a97f --- /dev/null +++ b/ckanext/unfold/logic/validators.py @@ -0,0 +1,16 @@ +from typing import Any + +import ckan.plugins.toolkit as tk +import ckan.types as types + + +def resource_view_id_exists(resource_view_id: str, context: types.Context) -> Any: + """Ensures that the resource_view with a given id exists.""" + + model = context["model"] + session = context["session"] + + if not session.query(model.ResourceView).get(resource_view_id): + raise tk.Invalid("Resource view not found.") + + return resource_view_id diff --git a/ckanext/unfold/plugin.py b/ckanext/unfold/plugin.py index 25aa677..e498879 100644 --- a/ckanext/unfold/plugin.py +++ b/ckanext/unfold/plugin.py @@ -12,6 +12,7 @@ @tk.blanket.actions +@tk.blanket.validators class UnfoldPlugin(plugins.SingletonPlugin): plugins.implements(plugins.IConfigurer) plugins.implements(plugins.IResourceView, inherit=True) diff --git a/ckanext/unfold/templates/unfold_form.html b/ckanext/unfold/templates/unfold_form.html index 6d25247..3752b18 100644 --- a/ckanext/unfold/templates/unfold_form.html +++ b/ckanext/unfold/templates/unfold_form.html @@ -1,10 +1,5 @@ {% import 'macros/form.html' as form %} -{{ form.input( - 'file_url', - id='field-file_url', - label=_('File URL'), - placeholder=_('eg. http://example.com/test.zip (if blank uses resource url)'), - value=data.file_url, - error=errors.file_url) -}} +{{ form.input('file_url', label=_('File URL'), placeholder=_('eg. http://example.com/test.zip (if blank uses resource url)'), value=data.file_url, error=errors.file_url)}} + +{{ form.input('archive_pass', label=_("Password"), id='field-password', type="password", value=data.archive_pass, error=errors.archive_pass) }} diff --git a/ckanext/unfold/templates/unfold_preview.html b/ckanext/unfold/templates/unfold_preview.html index 8fd2586..7cf21fb 100644 --- a/ckanext/unfold/templates/unfold_preview.html +++ b/ckanext/unfold/templates/unfold_preview.html @@ -16,7 +16,7 @@ -