Skip to content

Commit

Permalink
feature: add pass support for rar archive
Browse files Browse the repository at this point in the history
  • Loading branch information
mutantsan committed Oct 5, 2023
1 parent 2cb552f commit 581bf8b
Show file tree
Hide file tree
Showing 15 changed files with 71 additions and 34 deletions.
4 changes: 3 additions & 1 deletion ckanext/unfold/adapters/_7z.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion ckanext/unfold/adapters/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)]

Expand Down
11 changes: 9 additions & 2 deletions ckanext/unfold/adapters/rar.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,31 @@


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:
raise unf_exception.UnfoldError(f"Error openning archive: {e}")
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:
Expand Down
4 changes: 3 additions & 1 deletion ckanext/unfold/adapters/rpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion ckanext/unfold/adapters/tar.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

Expand Down
2 changes: 1 addition & 1 deletion ckanext/unfold/adapters/zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion ckanext/unfold/assets/js/unfold-init-jstree.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ckan.module("unfold-init-jstree", function ($, _) {
options: {
data: null,
resourceId: null,
resourceViewId: null
},

initialize: function () {
Expand All @@ -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
});
},
Expand Down
7 changes: 5 additions & 2 deletions ckanext/unfold/logic/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
14 changes: 11 additions & 3 deletions ckanext/unfold/logic/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -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],
}
16 changes: 16 additions & 0 deletions ckanext/unfold/logic/validators.py
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions ckanext/unfold/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


@tk.blanket.actions
@tk.blanket.validators
class UnfoldPlugin(plugins.SingletonPlugin):
plugins.implements(plugins.IConfigurer)
plugins.implements(plugins.IResourceView, inherit=True)
Expand Down
11 changes: 3 additions & 8 deletions ckanext/unfold/templates/unfold_form.html
Original file line number Diff line number Diff line change
@@ -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) }}
2 changes: 1 addition & 1 deletion ckanext/unfold/templates/unfold_preview.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</div>
</div>

<div id="archive-tree" data-module="unfold-init-jstree" data-module-resource-id="{{ resource.id }}">
<div id="archive-tree" data-module="unfold-init-jstree" data-module-resource-id="{{ resource.id }}" data-module-resource-view-id="{{ resource_view.id }}" >
<div class="archive-tree--spinner">
<img src="{{ h.url_for_static('/spinner.gif') }}" width="20">
{{ _("The archive tree is currently being initialized. Please wait...") }}
Expand Down
2 changes: 1 addition & 1 deletion ckanext/unfold/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Any, Optional, Dict
from typing import Any, Dict, Optional

from pydantic import BaseModel, Field

Expand Down
19 changes: 8 additions & 11 deletions ckanext/unfold/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import logging
import math
import pathlib
from typing import Any, Optional
from typing import Any

import ckan.lib.uploader as uploader
from ckan.lib.redis import connect_to_redis
Expand Down Expand Up @@ -124,7 +124,7 @@ def delete_archive_structure(resource_id: str) -> None:


def get_archive_tree(
resource: dict[str, Any]
resource: dict[str, Any], resource_view: dict[str, Any]
) -> list[unf_types.Node] | list[dict[str, Any]]:
remote = False

Expand All @@ -141,16 +141,13 @@ def get_archive_tree(
tree = get_archive_structure(resource["id"])

if not tree:
tree = parse_archive(resource["format"].lower(), filepath, remote)
save_archive_structure(tree, resource["id"])
res_format = resource["format"].lower()

return tree
if res_format not in unf_adapters.ADAPTERS:
raise TypeError(f"No adapter for `{res_format}` archives")

tree = unf_adapters.ADAPTERS[res_format](filepath, resource_view, remote=remote)

def parse_archive(
fmt: str, filepath: str, remote: Optional[bool] = False
) -> list[unf_types.Node]:
if fmt not in unf_adapters.ADAPTERS:
raise TypeError(f"No adapter for `{fmt}` archives")
save_archive_structure(tree, resource["id"])

return unf_adapters.ADAPTERS[fmt](filepath, remote=remote)
return tree

0 comments on commit 581bf8b

Please sign in to comment.