shrine-zip-guard 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +43 -12
- data/lib/shrine/plugins/zip_guard.rb +20 -6
- data/lib/shrine-zip-guard/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9359699bdaf1bf53ba7b23a7c271880166360df60bf26d78ef5b874cd8e605e2
|
|
4
|
+
data.tar.gz: d353357a3022c8f981501e735ca40f1a3264cdb8bc0d42c5093be2a369609d81
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0c170879388c9bb5c29a50d25d74a3ce50718f30ae315b318151333b4c5e9424213ab6172254bf63302ff94ea32c456006ba4cd4334e3be3659998ed0578595c
|
|
7
|
+
data.tar.gz: 82c23d6223bfe1c618471cf62c06b44d86a93f17779bf149bc1272b120cfc9bed557927416ca47a1b9adc3313f99bbcb5e837d0ed9665aa581da01680adbe47d
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.2.0] - 2026-08-06
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Per-uploader custom I18n messages via `shrine.zip_guard.errors.<uploader_name>`.
|
|
9
|
+
- Custom messages are supported for `password_protected`, `missing_file`, and `processing_failed` keys.
|
|
10
|
+
- `error_message_key` helper that resolves a custom key based on the uploader class name.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Custom message lookup no longer depends on ActiveSupport `String#underscore`.
|
|
14
|
+
|
|
5
15
|
## [0.1.0] - 2026-08-06
|
|
6
16
|
|
|
7
17
|
### Added
|
data/README.md
CHANGED
|
@@ -30,18 +30,28 @@ the plugin with `required_files`:
|
|
|
30
30
|
```ruby
|
|
31
31
|
class XmlUploader < Shrine
|
|
32
32
|
plugin :derivatives
|
|
33
|
-
plugin :zip_guard, required_files: ["
|
|
33
|
+
plugin :zip_guard, required_files: ["*.xml"]
|
|
34
34
|
end
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
This
|
|
38
|
-
|
|
37
|
+
This checks that the ZIP is not password-protected and that it contains at least
|
|
38
|
+
one file matching each glob pattern. Patterns are matched against the root of the
|
|
39
|
+
archive only. If you want to allow nested files, use a recursive pattern:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
plugin :zip_guard, required_files: ["**/*.xml"]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For a specific subdirectory, include the path in the pattern:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
plugin :zip_guard, required_files: ["data/*.xml"]
|
|
49
|
+
```
|
|
39
50
|
|
|
40
51
|
### Custom processing with `with_zip`
|
|
41
52
|
|
|
42
|
-
If you need to run your own logic (for example extracting files
|
|
43
|
-
specific paths
|
|
44
|
-
your `Attacher.derivatives` block:
|
|
53
|
+
If you need to run your own logic (for example extracting files or checking
|
|
54
|
+
specific paths), use the `with_zip` helper inside your `Attacher.derivatives` block:
|
|
45
55
|
|
|
46
56
|
```ruby
|
|
47
57
|
class XmlUploader < Shrine
|
|
@@ -49,12 +59,9 @@ class XmlUploader < Shrine
|
|
|
49
59
|
plugin :zip_guard
|
|
50
60
|
|
|
51
61
|
Attacher.derivatives do |original|
|
|
52
|
-
Shrine::Plugins::ZipGuard.with_zip(original, required_files: ["
|
|
62
|
+
Shrine::Plugins::ZipGuard.with_zip(original, required_files: ["*.xml"]) do |zip_file|
|
|
53
63
|
xmls = zip_file.glob("*.xml")
|
|
54
64
|
|
|
55
|
-
# Your custom rule — for example requiring the file to be at the root level
|
|
56
|
-
raise ZipUploadErrors::NestedFileError if xmls.empty? && zip_file.glob("**/*.xml").any?
|
|
57
|
-
|
|
58
65
|
if xmls.size == 1
|
|
59
66
|
extracted = Tempfile.new(["extracted", ".xml"], binmode: true)
|
|
60
67
|
extracted.write(xmls.first.get_input_stream.read)
|
|
@@ -68,10 +75,13 @@ class XmlUploader < Shrine
|
|
|
68
75
|
end
|
|
69
76
|
```
|
|
70
77
|
|
|
78
|
+
Note that `with_zip` performs its own `required_files` check, so you should not also
|
|
79
|
+
pass `required_files` to the plugin when you provide a custom `derivatives` block.
|
|
80
|
+
|
|
71
81
|
## Error messages
|
|
72
82
|
|
|
73
83
|
All user-facing errors are translated via I18n. The gem ships with English
|
|
74
|
-
defaults
|
|
84
|
+
defaults under the `shrine.zip_guard` key:
|
|
75
85
|
|
|
76
86
|
```yaml
|
|
77
87
|
en:
|
|
@@ -82,6 +92,27 @@ en:
|
|
|
82
92
|
processing_failed: "File could not be processed. Please try again or contact support."
|
|
83
93
|
```
|
|
84
94
|
|
|
95
|
+
### Per-uploader custom messages
|
|
96
|
+
|
|
97
|
+
You can override any message for a specific uploader by adding a key under
|
|
98
|
+
`shrine.zip_guard.errors.<uploader_name>`:
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
en:
|
|
102
|
+
shrine:
|
|
103
|
+
zip_guard:
|
|
104
|
+
missing_file: "Archive does not contain required file matching '%{pattern}'."
|
|
105
|
+
errors:
|
|
106
|
+
digital_box_rd_uploader:
|
|
107
|
+
missing_file: "XML file must be at the root level of the ZIP archive."
|
|
108
|
+
password_protected: "This ZIP is password protected."
|
|
109
|
+
processing_failed: "Could not process this XML ZIP."
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If the per-uploader key exists, it is used; otherwise the default key is used.
|
|
113
|
+
The class name is converted with `underscore`, so `MyUploaders::XmlUploader`
|
|
114
|
+
would become `my_uploaders/xml_uploader`.
|
|
115
|
+
|
|
85
116
|
## Custom fallback for unexpected errors
|
|
86
117
|
|
|
87
118
|
By default, unexpected `ZipGuard::Error` subclasses are reported to the Rails error
|
|
@@ -90,7 +121,7 @@ reporter (if available) and a generic `processing_failed` message is added to
|
|
|
90
121
|
|
|
91
122
|
```ruby
|
|
92
123
|
plugin :zip_guard,
|
|
93
|
-
required_files: ["
|
|
124
|
+
required_files: ["*.xml"],
|
|
94
125
|
fallback: lambda { |error, attacher|
|
|
95
126
|
Sentry.capture_exception(error)
|
|
96
127
|
attacher.errors << "Custom processing error: #{error.message}"
|
|
@@ -48,18 +48,32 @@ class Shrine
|
|
|
48
48
|
def create_derivatives(*args, **options, &)
|
|
49
49
|
super
|
|
50
50
|
rescue ZipGuard::EncryptedZipError
|
|
51
|
-
errors << I18n.t("
|
|
52
|
-
{}
|
|
51
|
+
errors << I18n.t(error_message_key("password_protected"))
|
|
53
52
|
rescue ZipGuard::MissingFileError => e
|
|
54
|
-
errors << I18n.t("
|
|
55
|
-
{}
|
|
53
|
+
errors << I18n.t(error_message_key("missing_file"), pattern: e.pattern)
|
|
56
54
|
rescue ZipGuard::Error => e
|
|
57
55
|
handle_zip_guard_error(e)
|
|
58
|
-
{}
|
|
59
56
|
end
|
|
60
57
|
|
|
61
58
|
private
|
|
62
59
|
|
|
60
|
+
def error_message_key(base_key)
|
|
61
|
+
uploader_name = shrine_class.name
|
|
62
|
+
return "shrine.zip_guard.#{base_key}" unless uploader_name
|
|
63
|
+
|
|
64
|
+
custom_key = "shrine.zip_guard.errors.#{underscore(uploader_name)}.#{base_key}"
|
|
65
|
+
I18n.t(custom_key, default: nil) ? custom_key : "shrine.zip_guard.#{base_key}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def underscore(class_name)
|
|
69
|
+
class_name
|
|
70
|
+
.gsub("::", "/")
|
|
71
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
72
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
73
|
+
.tr("-", "_")
|
|
74
|
+
.downcase
|
|
75
|
+
end
|
|
76
|
+
|
|
63
77
|
def handle_zip_guard_error(error)
|
|
64
78
|
fallback = shrine_class.opts[:zip_guard][:fallback]
|
|
65
79
|
|
|
@@ -67,7 +81,7 @@ class Shrine
|
|
|
67
81
|
fallback.call(error, self)
|
|
68
82
|
else
|
|
69
83
|
report_fallback(error)
|
|
70
|
-
errors << I18n.t("
|
|
84
|
+
errors << I18n.t(error_message_key("processing_failed"))
|
|
71
85
|
end
|
|
72
86
|
end
|
|
73
87
|
|