active_storage_validations 4.0.0 → 4.1.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/README.md +50 -2
- data/config/locales/da.yml +2 -0
- data/config/locales/de.yml +2 -0
- data/config/locales/en-GB.yml +2 -0
- data/config/locales/en.yml +2 -0
- data/config/locales/es.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/it.yml +2 -0
- data/config/locales/ja.yml +2 -0
- data/config/locales/nl.yml +2 -0
- data/config/locales/pl.yml +2 -0
- data/config/locales/pt-BR.yml +2 -0
- data/config/locales/ru.yml +2 -0
- data/config/locales/sv.yml +2 -0
- data/config/locales/tr.yml +2 -0
- data/config/locales/uk.yml +2 -0
- data/config/locales/vi.yml +2 -0
- data/config/locales/zh-CN.yml +2 -0
- data/lib/active_storage_validations/matchers/with_audio_validator_matcher.rb +114 -0
- data/lib/active_storage_validations/matchers.rb +1 -0
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations/with_audio_validator.rb +37 -0
- data/lib/active_storage_validations.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 24d8643d1f970252124d4429ca9bc15b222ef203cdcae93427a0860c7190c370
|
|
4
|
+
data.tar.gz: 62a74e517b40b32dba39c0529f0d4e4529d615a11decdebf8ec338505c082435
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8fa701638b13eea05351e5a76847d144e93ec83b4e14a8d5b5e23ae71944eabd092704c723fcb81e9c44a3fb909ab6431be680390ee414f13002af671792ca1
|
|
7
|
+
data.tar.gz: 82af6984104d830cd7eda7ffdb557f3bb997d8bb59fbef6edc85e0830c3a4397209d4ab31f6427f5945fe392935fefe7c49dc6cabd87c840a34592e8b827f300
|
data/README.md
CHANGED
|
@@ -31,6 +31,7 @@ This gem is doing it right for you! Just use `validates :avatar, attached: true,
|
|
|
31
31
|
- [Total size](#total-size)
|
|
32
32
|
- [Dimension](#dimension)
|
|
33
33
|
- [Duration](#duration)
|
|
34
|
+
- [With audio](#with-audio)
|
|
34
35
|
- [Aspect ratio](#aspect-ratio)
|
|
35
36
|
- [Processable file](#processable-file)
|
|
36
37
|
- [Pages](#pages)
|
|
@@ -76,7 +77,7 @@ We recommend **libvips** (`ruby-vips` + `config.active_storage.variant_processor
|
|
|
76
77
|
|
|
77
78
|
### Using video and audio metadata validators
|
|
78
79
|
|
|
79
|
-
To use the video and audio metadata validators (`dimension`, `aspect_ratio`, `processable_file` and `
|
|
80
|
+
To use the video and audio metadata validators (`dimension`, `aspect_ratio`, `processable_file`, `duration` and `with_audio`), you will not need to add any gems. However you will need to have the `ffmpeg` command-line tool installed on your system (once again, be sure to have it installed both on your local and in your CI / production environments).
|
|
80
81
|
|
|
81
82
|
### Using pdf metadata validators
|
|
82
83
|
|
|
@@ -115,7 +116,7 @@ end
|
|
|
115
116
|
# end
|
|
116
117
|
```
|
|
117
118
|
|
|
118
|
-
`command_timeout` bounds metadata analysis used by `dimension`, `aspect_ratio`, `duration`, `pages`, `processable_file`, and `content_type` (with `spoofing_protection`). When a command times out, analysis fails closed and the validator adds its usual error (`file_not_processable` / `media_metadata_missing` / content-type errors) — there is no separate timeout error message.
|
|
119
|
+
`command_timeout` bounds metadata analysis used by `dimension`, `aspect_ratio`, `duration`, `with_audio`, `pages`, `processable_file`, and `content_type` (with `spoofing_protection`). When a command times out, analysis fails closed and the validator adds its usual error (`file_not_processable` / `media_metadata_missing` / `audio_missing` / content-type errors) — there is no separate timeout error message.
|
|
119
120
|
|
|
120
121
|
The 10s default is enough for typical uploads. Raise it (or set `nil`) if you analyze very large videos/PDFs, especially on slow or network storage — otherwise those files can start failing validation after upgrade. See [upgrade to 4.x](docs/upgrade_to_4.md#analyzer-command-timeout).
|
|
121
122
|
|
|
@@ -140,6 +141,7 @@ Notes:
|
|
|
140
141
|
- [Total size](#total-size): validates total file size for several files
|
|
141
142
|
- [Dimension](#dimension): validates image / video dimensions
|
|
142
143
|
- [Duration](#duration): validates video / audio duration
|
|
144
|
+
- [With audio](#with-audio): validates whether a video contains an audio track
|
|
143
145
|
- [Aspect ratio](#aspect-ratio): validates image / video aspect ratio
|
|
144
146
|
- [Processable file](#processable-file): validates if a file can be processed
|
|
145
147
|
- [Pages](#pages): validates pdf number of pages
|
|
@@ -644,6 +646,47 @@ The `duration` validator error messages expose 4 values that you can use:
|
|
|
644
646
|
|
|
645
647
|
---
|
|
646
648
|
|
|
649
|
+
### With audio
|
|
650
|
+
|
|
651
|
+
Validates whether attached video files contain an audio track.
|
|
652
|
+
(be sure to have the right dependencies installed as mentioned in [Using video and audio metadata validators](#using-video-and-audio-metadata-validators))
|
|
653
|
+
|
|
654
|
+
#### Options
|
|
655
|
+
|
|
656
|
+
The `with_audio` validator supports:
|
|
657
|
+
- `with`: `true` requires an audio track and `false` rejects one
|
|
658
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) for this validation
|
|
659
|
+
|
|
660
|
+
#### Examples
|
|
661
|
+
|
|
662
|
+
Use it like this:
|
|
663
|
+
```ruby
|
|
664
|
+
class User < ApplicationRecord
|
|
665
|
+
has_one_attached :video
|
|
666
|
+
has_one_attached :silent_video
|
|
667
|
+
|
|
668
|
+
validates :video, with_audio: true
|
|
669
|
+
validates :silent_video, with_audio: { with: false }
|
|
670
|
+
validates :video, with_audio: { timeout: 5.seconds }
|
|
671
|
+
end
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Rails treats a bare `with_audio: false` as a disabled validator. Use the hash form `with_audio: { with: false }` to reject videos that contain audio.
|
|
675
|
+
|
|
676
|
+
#### Error messages (I18n)
|
|
677
|
+
|
|
678
|
+
```yml
|
|
679
|
+
en:
|
|
680
|
+
errors:
|
|
681
|
+
messages:
|
|
682
|
+
audio_missing: "must have an audio track"
|
|
683
|
+
audio_present: "must not have an audio track"
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
The `with_audio` validator error message exposes the `filename` value containing the current file name.
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
647
690
|
### Aspect ratio
|
|
648
691
|
|
|
649
692
|
Validates the aspect ratio of the attached image / video files.
|
|
@@ -895,6 +938,10 @@ describe User do
|
|
|
895
938
|
it { is_expected.to validate_duration_of(:introduction).between(100..500.seconds) }
|
|
896
939
|
it { is_expected.to validate_duration_of(:avatar).equal_to(5.minutes) }
|
|
897
940
|
|
|
941
|
+
# with_audio
|
|
942
|
+
it { is_expected.to validate_with_audio_of(:video) }
|
|
943
|
+
it { is_expected.to validate_with_audio_of(:silent_video).without_audio }
|
|
944
|
+
|
|
898
945
|
# pages:
|
|
899
946
|
# #less_than, #less_than_or_equal_to, #greater_than, #greater_than_or_equal_to, #between, #equal_to
|
|
900
947
|
it { is_expected.to validate_pages_of(:contract).less_than(50) }
|
|
@@ -927,6 +974,7 @@ describe User do
|
|
|
927
974
|
|
|
928
975
|
# :timeout (analyzer command timeout — metadata validators + content_type with spoofing)
|
|
929
976
|
it { is_expected.to validate_duration_of(:video).less_than(5.minutes).timeout(30.seconds) }
|
|
977
|
+
it { is_expected.to validate_with_audio_of(:video).timeout(5.seconds) }
|
|
930
978
|
it { is_expected.to validate_processable_file_of(:avatar).timeout(5.seconds) }
|
|
931
979
|
end
|
|
932
980
|
```
|
data/config/locales/da.yml
CHANGED
|
@@ -55,6 +55,8 @@ da:
|
|
|
55
55
|
aspect_ratio_not_x_y: "skal være %{authorized_aspect_ratios} (nuværende fil er %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "har et ugyldigt aspektforhold (gyldige aspektforhold er %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "identificeres ikke som en gyldig mediefil"
|
|
58
|
+
audio_missing: "skal have et lydspor"
|
|
59
|
+
audio_present: "må ikke have et lydspor"
|
|
58
60
|
pages_not_less_than: "sideantal skal være mindre end %{max} (aktuelt sideantal er %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "sideantal skal være mindre end eller lig med %{max} (aktuelt sideantal er %{pages})"
|
|
60
62
|
pages_not_greater_than: "sideantal skal være større end %{min} (aktuelt sideantal er %{pages})"
|
data/config/locales/de.yml
CHANGED
|
@@ -55,6 +55,8 @@ de:
|
|
|
55
55
|
aspect_ratio_not_x_y: "muss %{authorized_aspect_ratios} sein (aktuelle Datei ist %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "hat ein ungültiges Seitenverhältnis (gültige Seitenverhältnisse sind %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "wird nicht als gültige Mediendatei identifiziert"
|
|
58
|
+
audio_missing: "muss eine Audiospur enthalten"
|
|
59
|
+
audio_present: "darf keine Audiospur enthalten"
|
|
58
60
|
pages_not_less_than: "Die Seitenanzahl muss kleiner als %{max} sein (die aktuelle Seitenanzahl beträgt %{pages})."
|
|
59
61
|
pages_not_less_than_or_equal_to: "Die Seitenanzahl muss kleiner oder gleich %{max} sein (die aktuelle Seitenanzahl beträgt %{pages})."
|
|
60
62
|
pages_not_greater_than: "Die Seitenanzahl muss größer als %{min} sein (die aktuelle Seitenanzahl beträgt %{pages})."
|
data/config/locales/en-GB.yml
CHANGED
|
@@ -55,6 +55,8 @@ en-GB:
|
|
|
55
55
|
aspect_ratio_not_x_y: "must be %{authorized_aspect_ratios} (current file is %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "has an invalid aspect ratio (valid aspect ratios are %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "is not identified as a valid media file"
|
|
58
|
+
audio_missing: "must have an audio track"
|
|
59
|
+
audio_present: "must not have an audio track"
|
|
58
60
|
pages_not_less_than: "page count must be less than %{max} (current page count is %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "page count must be less than or equal to %{max} (current page count is %{pages})"
|
|
60
62
|
pages_not_greater_than: "page count must be greater than %{min} (current page count is %{pages})"
|
data/config/locales/en.yml
CHANGED
|
@@ -55,6 +55,8 @@ en:
|
|
|
55
55
|
aspect_ratio_not_x_y: "must be %{authorized_aspect_ratios} (current file is %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "has an invalid aspect ratio (valid aspect ratios are %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "is not identified as a valid media file"
|
|
58
|
+
audio_missing: "must have an audio track"
|
|
59
|
+
audio_present: "must not have an audio track"
|
|
58
60
|
pages_not_less_than: "page count must be less than %{max} (current page count is %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "page count must be less than or equal to %{max} (current page count is %{pages})"
|
|
60
62
|
pages_not_greater_than: "page count must be greater than %{min} (current page count is %{pages})"
|
data/config/locales/es.yml
CHANGED
|
@@ -55,6 +55,8 @@ es:
|
|
|
55
55
|
aspect_ratio_not_x_y: "debe ser %{authorized_aspect_ratios} (el archivo actual es %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "tiene una relación de aspecto inválida (las relaciones de aspecto válidas son %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "no se identifica como un archivo multimedia válido"
|
|
58
|
+
audio_missing: "debe tener una pista de audio"
|
|
59
|
+
audio_present: "no debe tener una pista de audio"
|
|
58
60
|
pages_not_less_than: "el número de páginas debe ser menor que %{max} (el número actual de páginas es %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "el número de páginas debe ser menor o igual que %{max} (el número actual de páginas es %{pages})"
|
|
60
62
|
pages_not_greater_than: "el número de páginas debe ser mayor que %{min} (el número actual de páginas es %{pages})"
|
data/config/locales/fr.yml
CHANGED
|
@@ -55,6 +55,8 @@ fr:
|
|
|
55
55
|
aspect_ratio_not_x_y: "doit être %{authorized_aspect_ratios} (le fichier actuel est %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "a un rapport d'aspect invalide (les rapports d'aspect valides sont %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "n'est pas identifié comme un fichier média valide"
|
|
58
|
+
audio_missing: "doit contenir une piste audio"
|
|
59
|
+
audio_present: "ne doit pas contenir de piste audio"
|
|
58
60
|
pages_not_less_than: "le nombre de pages doit être inférieur à %{max} (le nombre actuel est de %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "le nombre de pages doit être inférieur ou égal à %{max} (le nombre actuel est de %{pages})"
|
|
60
62
|
pages_not_greater_than: "le nombre de pages doit être supérieur à %{min} (le nombre actuel est de %{pages})"
|
data/config/locales/it.yml
CHANGED
|
@@ -55,6 +55,8 @@ it:
|
|
|
55
55
|
aspect_ratio_not_x_y: "deve essere %{authorized_aspect_ratios} (il file corrente è %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "ha un formato non valido (i rapporti di aspetto validi sono %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "non è identificato come file multimediale valido"
|
|
58
|
+
audio_missing: "deve contenere una traccia audio"
|
|
59
|
+
audio_present: "non deve contenere una traccia audio"
|
|
58
60
|
pages_not_less_than: "il numero di pagine deve essere inferiore a %{max} (il numero di pagine corrente è %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "il numero di pagine deve essere inferiore o uguale a %{max} (il numero di pagine corrente è %{pages})"
|
|
60
62
|
pages_not_greater_than: "il numero di pagine deve essere maggiore di %{min} (il numero di pagine corrente è %{pages})"
|
data/config/locales/ja.yml
CHANGED
|
@@ -55,6 +55,8 @@ ja:
|
|
|
55
55
|
aspect_ratio_not_x_y: "のアスペクト比は%{authorized_aspect_ratios}にしてください (添付されたメディアの解像度は%{width}x%{height})"
|
|
56
56
|
aspect_ratio_invalid: "のアスペクト比を検出できません (許可されたアスペクト比は%{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "のメディアを処理できません"
|
|
58
|
+
audio_missing: "には音声トラックが必要です"
|
|
59
|
+
audio_present: "に音声トラックを含めることはできません"
|
|
58
60
|
pages_not_less_than: "のページ数は%{max}未満にしてください (添付されたファイルは%{pages}ページ)"
|
|
59
61
|
pages_not_less_than_or_equal_to: "のページ数は%{max}以下にしてください (添付されたファイルは%{pages}ページ)"
|
|
60
62
|
pages_not_greater_than: "のページ数は%{min}より大きくしてください (添付されたファイルは%{pages}ページ)"
|
data/config/locales/nl.yml
CHANGED
|
@@ -55,6 +55,8 @@ nl:
|
|
|
55
55
|
aspect_ratio_not_x_y: "moet %{authorized_aspect_ratios} zijn (huidig bestand is %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "heeft een ongeldige beeldverhouding (geldige beeldverhoudingen zijn %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "wordt niet geïdentificeerd als een geldig mediabestand"
|
|
58
|
+
audio_missing: "moet een audiotrack bevatten"
|
|
59
|
+
audio_present: "mag geen audiotrack bevatten"
|
|
58
60
|
pages_not_less_than: "het aantal pagina's moet kleiner zijn dan %{max} (het huidige aantal pagina's is %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "het aantal pagina's moet kleiner zijn dan of gelijk zijn aan %{max} (het huidige aantal pagina's is %{pages})"
|
|
60
62
|
pages_not_greater_than: "het aantal pagina's moet groter zijn dan %{min} (het huidige aantal pagina's is %{pages})"
|
data/config/locales/pl.yml
CHANGED
|
@@ -55,6 +55,8 @@ pl:
|
|
|
55
55
|
aspect_ratio_not_x_y: "musi być %{authorized_aspect_ratios} (bieżący plik to %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "ma nieprawidłowy współczynnik kształtu (ważne współczynniki kształtu wynoszą %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "nie jest identyfikowany jako prawidłowy plik multimedialny"
|
|
58
|
+
audio_missing: "musi zawierać ścieżkę dźwiękową"
|
|
59
|
+
audio_present: "nie może zawierać ścieżki dźwiękowej"
|
|
58
60
|
pages_not_less_than: "liczba stron musi być mniejsza niż %{max} (bieżąca liczba stron to %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "liczba stron musi być mniejsza lub równa %{max} (bieżąca liczba stron to %{pages})"
|
|
60
62
|
pages_not_greater_than: "liczba stron musi być większa niż %{min} (bieżąca liczba stron to %{pages})"
|
data/config/locales/pt-BR.yml
CHANGED
|
@@ -55,6 +55,8 @@ pt-BR:
|
|
|
55
55
|
aspect_ratio_not_x_y: "deve ser %{authorized_aspect_ratios} (o arquivo atual é %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "tem uma proporção inválida (as proporções válidas são %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "não é identificado como um arquivo de mídia válido"
|
|
58
|
+
audio_missing: "deve ter uma faixa de áudio"
|
|
59
|
+
audio_present: "não deve ter uma faixa de áudio"
|
|
58
60
|
pages_not_less_than: "a contagem de páginas deve ser menor que %{max} (a contagem atual de páginas é %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "a contagem de páginas deve ser menor ou igual a %{max} (a contagem atual de páginas é %{pages})"
|
|
60
62
|
pages_not_greater_than: "a contagem de páginas deve ser maior que %{min} (a contagem atual de páginas é %{pages})"
|
data/config/locales/ru.yml
CHANGED
|
@@ -55,6 +55,8 @@ ru:
|
|
|
55
55
|
aspect_ratio_not_x_y: "должно быть %{authorized_aspect_ratios} (текущий файл %{width}x%{height} пикселей)"
|
|
56
56
|
aspect_ratio_invalid: "имеет недействительное соотношение сторон (действительные соотношения сторон %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "не идентифицируется как действительный медиафайл"
|
|
58
|
+
audio_missing: "должен содержать аудиодорожку"
|
|
59
|
+
audio_present: "не должен содержать аудиодорожку"
|
|
58
60
|
pages_not_less_than: "количество страниц должно быть меньше %{max} (текущее количество страниц %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "количество страниц должно быть меньше или равно %{max} (текущее количество страниц %{pages})"
|
|
60
62
|
pages_not_greater_than: "количество страниц должно быть больше %{min} (текущее количество страниц %{pages})"
|
data/config/locales/sv.yml
CHANGED
|
@@ -55,6 +55,8 @@ sv:
|
|
|
55
55
|
aspect_ratio_not_x_y: "måste vara% { authorized_aspect_ratios } (nuvarande fil är %{width}x%{height} pixlar)"
|
|
56
56
|
aspect_ratio_invalid: "har ett ogiltigt bildförhållande (giltiga bildförhållanden är %{förväntat_aspect_ratios})"
|
|
57
57
|
file_not_processable: "identifieras inte som en giltig mediefil"
|
|
58
|
+
audio_missing: "måste innehålla ett ljudspår"
|
|
59
|
+
audio_present: "får inte innehålla ett ljudspår"
|
|
58
60
|
pages_not_less_than: "sidantal måste vara mindre än %{max} (nuvarande sidantal är %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "sidantal måste vara mindre än eller lika med %{max} (nuvarande antal sidor är %{pages})"
|
|
60
62
|
pages_not_greater_than: "sidantal måste vara större än %{min} (nuvarande sidantal är %{pages})"
|
data/config/locales/tr.yml
CHANGED
|
@@ -55,6 +55,8 @@ tr:
|
|
|
55
55
|
aspect_ratio_not_x_y: "%{authorized_aspect_ratios} olmalıdır (geçerli dosya %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "geçersiz bir en boy oranına sahiptir (geçerli en boy oranları %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "geçerli bir medya dosyası olarak tanımlanmadı"
|
|
58
|
+
audio_missing: "bir ses parçası içermelidir"
|
|
59
|
+
audio_present: "bir ses parçası içermemelidir"
|
|
58
60
|
pages_not_less_than: "sayfa sayısı %{max} değerinden az olmalıdır (geçerli sayfa sayısı %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "sayfa sayısı %{max} değerinden az veya eşit olmalıdır (geçerli sayfa sayısı %{pages})"
|
|
60
62
|
pages_not_greater_than: "sayfa sayısı %{min} değerinden fazla olmalıdır (geçerli sayfa sayısı %{pages})"
|
data/config/locales/uk.yml
CHANGED
|
@@ -55,6 +55,8 @@ uk:
|
|
|
55
55
|
aspect_ratio_not_x_y: "повинен бути %{authorized_aspect_ratios} (поточний файл становить %{width}x%{height} пікселям)"
|
|
56
56
|
aspect_ratio_invalid: "має недійсне співвідношення сторін (дійсні співвідношення сторін %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "не ідентифікується як дійсний медіа-файл"
|
|
58
|
+
audio_missing: "має містити аудіодоріжку"
|
|
59
|
+
audio_present: "не має містити аудіодоріжку"
|
|
58
60
|
pages_not_less_than: "кількість сторінок має бути менше %{max} (поточна кількість сторінок %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "кількість сторінок має бути меншою або дорівнювати %{max} (поточна кількість сторінок становить %{pages})"
|
|
60
62
|
pages_not_greater_than: "кількість сторінок має бути більшою за %{min} (поточна кількість сторінок становить %{pages})"
|
data/config/locales/vi.yml
CHANGED
|
@@ -55,6 +55,8 @@ vi:
|
|
|
55
55
|
aspect_ratio_not_x_y: "phải là %{authorized_aspect_ratios} (tệp hiện tại là %{width}x%{height}px)"
|
|
56
56
|
aspect_ratio_invalid: "có tỷ lệ khung hình không hợp lệ (tỷ lệ khung hình hợp lệ là %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "không được xác định là tệp phương tiện hợp lệ"
|
|
58
|
+
audio_missing: "phải có một bản âm thanh"
|
|
59
|
+
audio_present: "không được chứa bản âm thanh"
|
|
58
60
|
pages_not_less_than: "số trang phải nhỏ hơn %{max} (số trang hiện tại là %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "số trang phải nhỏ hơn hoặc bằng %{max} (số trang hiện tại là %{pages})"
|
|
60
62
|
pages_not_greater_than: "số trang phải lớn hơn %{min} (số trang hiện tại là %{pages})"
|
data/config/locales/zh-CN.yml
CHANGED
|
@@ -55,6 +55,8 @@ zh-CN:
|
|
|
55
55
|
aspect_ratio_not_x_y: "必须为 %{authorized_aspect_ratios}(当前文件为 %{width} x%{height} 像素)"
|
|
56
56
|
aspect_ratio_invalid: "具有无效的长宽比(有效长宽比为 %{authorized_aspect_ratios})"
|
|
57
57
|
file_not_processable: "未标识为有效的媒体文件"
|
|
58
|
+
audio_missing: "必须包含音轨"
|
|
59
|
+
audio_present: "不得包含音轨"
|
|
58
60
|
pages_not_less_than: "页数必须小于 %{max}(当前页数为 %{pages})"
|
|
59
61
|
pages_not_less_than_or_equal_to: "页数必须小于或等于 %{max}(当前页数为 %{pages})"
|
|
60
62
|
pages_not_greater_than: "页数必须大于 %{min}(当前页数为 %{pages})"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "shared/asv_active_storageable"
|
|
4
|
+
require_relative "shared/asv_allow_blankable"
|
|
5
|
+
require_relative "shared/asv_attachable"
|
|
6
|
+
require_relative "shared/asv_contextable"
|
|
7
|
+
require_relative "shared/asv_except_onable"
|
|
8
|
+
require_relative "shared/asv_messageable"
|
|
9
|
+
require_relative "shared/asv_rspecable"
|
|
10
|
+
require_relative "shared/asv_timeoutable"
|
|
11
|
+
require_relative "shared/asv_validatable"
|
|
12
|
+
|
|
13
|
+
module ActiveStorageValidations
|
|
14
|
+
module Matchers
|
|
15
|
+
def validate_with_audio_of(attribute_name)
|
|
16
|
+
WithAudioValidatorMatcher.new(attribute_name)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class WithAudioValidatorMatcher
|
|
20
|
+
include ASVActiveStorageable
|
|
21
|
+
include ASVAllowBlankable
|
|
22
|
+
include ASVAttachable
|
|
23
|
+
include ASVContextable
|
|
24
|
+
include ASVExceptOnable
|
|
25
|
+
include ASVMessageable
|
|
26
|
+
include ASVRspecable
|
|
27
|
+
include ASVTimeoutable
|
|
28
|
+
include ASVValidatable
|
|
29
|
+
|
|
30
|
+
def initialize(attribute_name)
|
|
31
|
+
initialize_allow_blankable
|
|
32
|
+
initialize_contextable
|
|
33
|
+
initialize_except_onable
|
|
34
|
+
initialize_messageable
|
|
35
|
+
initialize_rspecable
|
|
36
|
+
initialize_timeoutable
|
|
37
|
+
@attribute_name = attribute_name
|
|
38
|
+
@expected_audio = true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def description
|
|
42
|
+
"validate that :#{@attribute_name} #{audio_expectation}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def failure_message
|
|
46
|
+
"is expected to validate that :#{@attribute_name} #{audio_expectation}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def without_audio
|
|
50
|
+
@expected_audio = false
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def matches?(subject)
|
|
55
|
+
@subject = subject.is_a?(Class) ? subject.new : subject
|
|
56
|
+
|
|
57
|
+
is_a_valid_active_storage_attribute? &&
|
|
58
|
+
is_context_valid? &&
|
|
59
|
+
is_except_on_valid? &&
|
|
60
|
+
is_allowing_blank? &&
|
|
61
|
+
is_timeout_valid? &&
|
|
62
|
+
is_custom_message_valid? &&
|
|
63
|
+
is_valid_with_expected_audio? &&
|
|
64
|
+
is_invalid_with_unexpected_audio?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def audio_expectation
|
|
70
|
+
@expected_audio ? "has an audio track" : "has no audio track"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def is_valid_with_expected_audio?
|
|
74
|
+
validation_passes_with_audio?(@expected_audio)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def is_invalid_with_unexpected_audio?
|
|
78
|
+
!validation_passes_with_audio?(!@expected_audio)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def is_custom_message_valid?
|
|
82
|
+
return true unless @custom_message
|
|
83
|
+
|
|
84
|
+
with_audio_metadata(false) do
|
|
85
|
+
attach_file(video_file)
|
|
86
|
+
validate
|
|
87
|
+
detach_file
|
|
88
|
+
has_an_error_message_which_is_custom_message?
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def validation_passes_with_audio?(audio)
|
|
93
|
+
with_audio_metadata(audio) do
|
|
94
|
+
attach_file(video_file)
|
|
95
|
+
validate
|
|
96
|
+
detach_file
|
|
97
|
+
is_valid?
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def with_audio_metadata(audio, &block)
|
|
102
|
+
Matchers.mock_metadata(io, { audio: audio }, &block)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def video_file
|
|
106
|
+
{
|
|
107
|
+
io: io,
|
|
108
|
+
filename: "test.mp4",
|
|
109
|
+
content_type: "video/mp4"
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -7,6 +7,7 @@ require "active_storage_validations/matchers/limit_validator_matcher"
|
|
|
7
7
|
require "active_storage_validations/matchers/content_type_validator_matcher"
|
|
8
8
|
require "active_storage_validations/matchers/dimension_validator_matcher"
|
|
9
9
|
require "active_storage_validations/matchers/duration_validator_matcher"
|
|
10
|
+
require "active_storage_validations/matchers/with_audio_validator_matcher"
|
|
10
11
|
require "active_storage_validations/matchers/size_validator_matcher"
|
|
11
12
|
require "active_storage_validations/matchers/total_size_validator_matcher"
|
|
12
13
|
require "active_storage_validations/matchers/pages_validator_matcher"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "shared/asv_active_storageable"
|
|
4
|
+
require_relative "shared/asv_analyzable"
|
|
5
|
+
require_relative "shared/asv_attachable"
|
|
6
|
+
require_relative "shared/asv_errorable"
|
|
7
|
+
require_relative "shared/asv_symbolizable"
|
|
8
|
+
|
|
9
|
+
module ActiveStorageValidations
|
|
10
|
+
class WithAudioValidator < ActiveModel::EachValidator # :nodoc
|
|
11
|
+
include ASVActiveStorageable
|
|
12
|
+
include ASVAnalyzable
|
|
13
|
+
include ASVAttachable
|
|
14
|
+
include ASVErrorable
|
|
15
|
+
include ASVSymbolizable
|
|
16
|
+
|
|
17
|
+
ERROR_TYPES = %i[audio_missing audio_present].freeze
|
|
18
|
+
METADATA_KEYS = %i[audio].freeze
|
|
19
|
+
|
|
20
|
+
def validate_each(record, attribute, _value)
|
|
21
|
+
return if no_attachments?(record, attribute)
|
|
22
|
+
|
|
23
|
+
validate_changed_files_from_metadata(record, attribute, METADATA_KEYS)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def is_valid?(record, attribute, attachable, metadata)
|
|
29
|
+
expected_audio = options.fetch(:with, true)
|
|
30
|
+
return if metadata&.fetch(:audio, false) == expected_audio
|
|
31
|
+
|
|
32
|
+
errors_options = initialize_error_options(options, attachable)
|
|
33
|
+
error_type = expected_audio ? :audio_missing : :audio_present
|
|
34
|
+
add_error(record, attribute, error_type, **errors_options)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -41,6 +41,7 @@ require "active_storage_validations/content_type_validator"
|
|
|
41
41
|
require "active_storage_validations/limit_validator"
|
|
42
42
|
require "active_storage_validations/dimension_validator"
|
|
43
43
|
require "active_storage_validations/duration_validator"
|
|
44
|
+
require "active_storage_validations/with_audio_validator"
|
|
44
45
|
require "active_storage_validations/aspect_ratio_validator"
|
|
45
46
|
require "active_storage_validations/processable_file_validator"
|
|
46
47
|
require "active_storage_validations/size_validator"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: active_storage_validations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Igor Kasyanchuk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activejob
|
|
@@ -265,6 +265,7 @@ files:
|
|
|
265
265
|
- lib/active_storage_validations/matchers/shared/asv_validatable.rb
|
|
266
266
|
- lib/active_storage_validations/matchers/size_validator_matcher.rb
|
|
267
267
|
- lib/active_storage_validations/matchers/total_size_validator_matcher.rb
|
|
268
|
+
- lib/active_storage_validations/matchers/with_audio_validator_matcher.rb
|
|
268
269
|
- lib/active_storage_validations/pages_validator.rb
|
|
269
270
|
- lib/active_storage_validations/processable_file_validator.rb
|
|
270
271
|
- lib/active_storage_validations/railtie.rb
|
|
@@ -279,6 +280,7 @@ files:
|
|
|
279
280
|
- lib/active_storage_validations/size_validator.rb
|
|
280
281
|
- lib/active_storage_validations/total_size_validator.rb
|
|
281
282
|
- lib/active_storage_validations/version.rb
|
|
283
|
+
- lib/active_storage_validations/with_audio_validator.rb
|
|
282
284
|
homepage: https://github.com/igorkasyanchuk/active_storage_validations
|
|
283
285
|
licenses:
|
|
284
286
|
- MIT
|