comfy_middle_seat 4.4.0 → 4.6.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 +32 -1
- data/README.md +56 -2
- data/app/assets/javascripts/comfy/admin/cms/cms_tag_completions.js +3 -3
- data/app/controllers/comfy/admin/cms/tag_usage_controller.rb +20 -0
- data/app/helpers/comfy/admin/cms/tag_usage_helper.rb +21 -0
- data/app/models/comfy/cms/layout.rb +1 -1
- data/app/views/comfy/admin/cms/tag_usage/_source.html.haml +2 -0
- data/app/views/comfy/admin/cms/tag_usage/index.html.haml +54 -0
- data/app/views/layouts/comfy/admin/cms/_left.html.haml +3 -0
- data/config/initializers/comfy_middle_seat.rb +3 -3
- data/config/locales/ar.yml +20 -0
- data/config/locales/ca.yml +20 -0
- data/config/locales/cs.yml +20 -0
- data/config/locales/da.yml +20 -0
- data/config/locales/de.yml +20 -0
- data/config/locales/en.yml +20 -0
- data/config/locales/es.yml +20 -0
- data/config/locales/fi.yml +20 -0
- data/config/locales/fr.yml +20 -0
- data/config/locales/gr.yml +20 -0
- data/config/locales/hr.yml +20 -0
- data/config/locales/it.yml +20 -0
- data/config/locales/ja.yml +20 -0
- data/config/locales/nb.yml +20 -0
- data/config/locales/nl.yml +20 -0
- data/config/locales/pl.yml +20 -0
- data/config/locales/pt-BR.yml +20 -0
- data/config/locales/ru.yml +20 -0
- data/config/locales/sk.yml +20 -0
- data/config/locales/sv.yml +20 -0
- data/config/locales/tr.yml +20 -0
- data/config/locales/uk.yml +20 -0
- data/config/locales/zh-CN.yml +20 -0
- data/config/locales/zh-TW.yml +20 -0
- data/lib/comfy_middle_seat/configuration.rb +3 -3
- data/lib/comfy_middle_seat/content/tag_usage.rb +124 -0
- data/lib/comfy_middle_seat/content/tag_usage_report.rb +83 -0
- data/lib/comfy_middle_seat/content/tags/asset.rb +12 -17
- data/lib/comfy_middle_seat/content/tags/helper.rb +1 -1
- data/lib/comfy_middle_seat/content/tags/mixins/file_content.rb +6 -10
- data/lib/comfy_middle_seat/content/tags/partial.rb +3 -3
- data/lib/comfy_middle_seat/content/tags/template.rb +3 -3
- data/lib/comfy_middle_seat/content.rb +2 -0
- data/lib/comfy_middle_seat/routing.rb +1 -0
- data/lib/comfy_middle_seat/version.rb +1 -1
- data/lib/tasks/cms_tag_usage.rake +32 -0
- metadata +8 -1
data/config/locales/ja.yml
CHANGED
|
@@ -65,6 +65,26 @@ ja:
|
|
|
65
65
|
files: ファイル
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: タグの使用状況
|
|
70
|
+
scope: 未公開のコンテンツを含む、このサイトの保存済みコンテンツすべてが対象です。実行時のレンダリングは行いません。
|
|
71
|
+
multisite: このサイトのみのレポートでは、複数サイト共通の許可リストに必要な情報を網羅できません。
|
|
72
|
+
partial: パーシャル
|
|
73
|
+
helper: ヘルパー
|
|
74
|
+
template: テンプレート
|
|
75
|
+
name: 名前
|
|
76
|
+
status: 現在の状態
|
|
77
|
+
sources: 参照元
|
|
78
|
+
used_in: 使用箇所
|
|
79
|
+
no_results: 該当するタグは見つかりませんでした。
|
|
80
|
+
incomplete: レポートは不完全です。一部のコンテンツを解析できませんでした。以下の警告を確認してください。
|
|
81
|
+
warnings: 解析の警告
|
|
82
|
+
config: 設定候補
|
|
83
|
+
review: 使用前に確認してください。この候補は自動的な許可やセキュリティの承認ではありません。設定は変更されていません。
|
|
84
|
+
explicitly_allowed: 明示的に許可
|
|
85
|
+
allowed_by_default: デフォルトで許可
|
|
86
|
+
blocked: ブロック
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: 検索
|
|
70
90
|
clear: クリア
|
data/config/locales/nb.yml
CHANGED
|
@@ -65,6 +65,26 @@ nb:
|
|
|
65
65
|
files: Filer
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Bruk av tagger
|
|
70
|
+
scope: Alt lagret innhold på dette nettstedet, også upublisert innhold. Ingen rendering under kjøring.
|
|
71
|
+
multisite: Denne rapporten for ett nettsted er ikke uttømmende for globale tillatelseslister på tvers av nettsteder.
|
|
72
|
+
partial: Delvisninger
|
|
73
|
+
helper: Hjelpemetoder
|
|
74
|
+
template: Maler
|
|
75
|
+
name: Navn
|
|
76
|
+
status: Gjeldende status
|
|
77
|
+
sources: Kilder
|
|
78
|
+
used_in: Brukt i
|
|
79
|
+
no_results: Ingen samsvarende tagger funnet.
|
|
80
|
+
incomplete: Rapporten er ufullstendig. Noe innhold kunne ikke analyseres; se advarslene nedenfor.
|
|
81
|
+
warnings: Analyseadvarsler
|
|
82
|
+
config: Foreslått konfigurasjon
|
|
83
|
+
review: Gjennomgå før bruk. Forslaget er ikke automatisk tillatelse eller sikkerhetsgodkjenning. Ingen konfigurasjon er endret.
|
|
84
|
+
explicitly_allowed: Uttrykkelig tillatt
|
|
85
|
+
allowed_by_default: Tillatt som standard
|
|
86
|
+
blocked: Blokkert
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Søk
|
|
70
90
|
clear: Tøm
|
data/config/locales/nl.yml
CHANGED
|
@@ -65,6 +65,26 @@ nl:
|
|
|
65
65
|
files: Bestanden
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Taggebruik
|
|
70
|
+
scope: Alle opgeslagen inhoud van deze site, ook niet-gepubliceerde inhoud. Geen rendering tijdens uitvoering.
|
|
71
|
+
multisite: Dit rapport voor één site is niet volledig voor globale toelatingslijsten voor meerdere sites.
|
|
72
|
+
partial: Deeltemplates
|
|
73
|
+
helper: Hulpmethoden
|
|
74
|
+
template: Templates
|
|
75
|
+
name: Naam
|
|
76
|
+
status: Huidige status
|
|
77
|
+
sources: Bronnen
|
|
78
|
+
used_in: Gebruikt in
|
|
79
|
+
no_results: Geen overeenkomende tags gevonden.
|
|
80
|
+
incomplete: Onvolledig rapport. Sommige inhoud kon niet worden geanalyseerd; bekijk de onderstaande waarschuwingen.
|
|
81
|
+
warnings: Analysewaarschuwingen
|
|
82
|
+
config: Voorgestelde configuratie
|
|
83
|
+
review: Controleer vóór gebruik. Dit voorstel is geen automatische toestemming of beveiligingsgoedkeuring. Er is geen configuratie gewijzigd.
|
|
84
|
+
explicitly_allowed: Expliciet toegestaan
|
|
85
|
+
allowed_by_default: Standaard toegestaan
|
|
86
|
+
blocked: Geblokkeerd
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Zoeken
|
|
70
90
|
clear: Wissen
|
data/config/locales/pl.yml
CHANGED
|
@@ -65,6 +65,26 @@ pl:
|
|
|
65
65
|
files: Pliki
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Użycie znaczników
|
|
70
|
+
scope: Cała zapisana treść tej witryny, także nieopublikowana. Bez renderowania w czasie wykonania.
|
|
71
|
+
multisite: Ten raport jednej witryny nie jest wyczerpujący dla globalnych list dozwolonych elementów wielu witryn.
|
|
72
|
+
partial: Szablony częściowe
|
|
73
|
+
helper: Metody pomocnicze
|
|
74
|
+
template: Szablony
|
|
75
|
+
name: Nazwa
|
|
76
|
+
status: Aktualny stan
|
|
77
|
+
sources: Źródła
|
|
78
|
+
used_in: Użyto w
|
|
79
|
+
no_results: Nie znaleziono pasujących znaczników.
|
|
80
|
+
incomplete: Raport niekompletny. Nie udało się przeanalizować części treści; sprawdź poniższe ostrzeżenia.
|
|
81
|
+
warnings: Ostrzeżenia analizy
|
|
82
|
+
config: Proponowana konfiguracja
|
|
83
|
+
review: Sprawdź przed użyciem. Propozycja nie oznacza automatycznego zezwolenia ani zatwierdzenia bezpieczeństwa. Konfiguracja nie została zmieniona.
|
|
84
|
+
explicitly_allowed: Jawnie dozwolone
|
|
85
|
+
allowed_by_default: Domyślnie dozwolone
|
|
86
|
+
blocked: Zablokowane
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Szukaj
|
|
70
90
|
clear: Wyczyść
|
data/config/locales/pt-BR.yml
CHANGED
|
@@ -65,6 +65,26 @@ pt-BR:
|
|
|
65
65
|
files: Arquivos
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Uso de tags
|
|
70
|
+
scope: Todo o conteúdo salvo deste site, incluindo o não publicado. Sem renderização em tempo de execução.
|
|
71
|
+
multisite: Este relatório de um único site não é exaustivo para listas globais de permissões de vários sites.
|
|
72
|
+
partial: Parciais
|
|
73
|
+
helper: Helpers
|
|
74
|
+
template: Modelos
|
|
75
|
+
name: Nome
|
|
76
|
+
status: Estado atual
|
|
77
|
+
sources: Fontes
|
|
78
|
+
used_in: Usado em
|
|
79
|
+
no_results: Nenhuma tag correspondente encontrada.
|
|
80
|
+
incomplete: Relatório incompleto. Parte do conteúdo não pôde ser analisada; revise os avisos abaixo.
|
|
81
|
+
warnings: Avisos da análise
|
|
82
|
+
config: Configuração proposta
|
|
83
|
+
review: Revise antes de usar. Esta proposta não é uma permissão automática nem uma aprovação de segurança. Nenhuma configuração foi alterada.
|
|
84
|
+
explicitly_allowed: Permitido explicitamente
|
|
85
|
+
allowed_by_default: Permitido por padrão
|
|
86
|
+
blocked: Bloqueado
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Pesquisar
|
|
70
90
|
clear: Limpar
|
data/config/locales/ru.yml
CHANGED
|
@@ -65,6 +65,26 @@ ru:
|
|
|
65
65
|
files: Файлы
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Использование тегов
|
|
70
|
+
scope: Всё сохранённое содержимое этого сайта, включая неопубликованное. Без рендеринга во время выполнения.
|
|
71
|
+
multisite: Этот отчёт по одному сайту не является полным для глобальных списков разрешений нескольких сайтов.
|
|
72
|
+
partial: Частичные шаблоны
|
|
73
|
+
helper: Вспомогательные методы
|
|
74
|
+
template: Шаблоны
|
|
75
|
+
name: Имя
|
|
76
|
+
status: Текущий статус
|
|
77
|
+
sources: Источники
|
|
78
|
+
used_in: Используется в
|
|
79
|
+
no_results: Соответствующие теги не найдены.
|
|
80
|
+
incomplete: Отчёт неполный. Часть содержимого не удалось проанализировать; проверьте предупреждения ниже.
|
|
81
|
+
warnings: Предупреждения анализа
|
|
82
|
+
config: Предлагаемая конфигурация
|
|
83
|
+
review: Проверьте перед использованием. Предложение не является автоматическим разрешением или подтверждением безопасности. Конфигурация не изменена.
|
|
84
|
+
explicitly_allowed: Явно разрешено
|
|
85
|
+
allowed_by_default: Разрешено по умолчанию
|
|
86
|
+
blocked: Заблокировано
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Поиск
|
|
70
90
|
clear: Очистить
|
data/config/locales/sk.yml
CHANGED
|
@@ -65,6 +65,26 @@ sk:
|
|
|
65
65
|
files: Súbory
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Použitie značiek
|
|
70
|
+
scope: Všetok uložený obsah tohto webu vrátane nepublikovaného. Bez vykresľovania počas behu.
|
|
71
|
+
multisite: Tento prehľad jedného webu nie je úplný pre globálne zoznamy povolení viacerých webov.
|
|
72
|
+
partial: Čiastkové šablóny
|
|
73
|
+
helper: Pomocné metódy
|
|
74
|
+
template: Šablóny
|
|
75
|
+
name: Názov
|
|
76
|
+
status: Aktuálny stav
|
|
77
|
+
sources: Zdroje
|
|
78
|
+
used_in: Použité v
|
|
79
|
+
no_results: Nenašli sa žiadne zodpovedajúce značky.
|
|
80
|
+
incomplete: Prehľad nie je úplný. Časť obsahu sa nepodarilo analyzovať; skontrolujte upozornenia nižšie.
|
|
81
|
+
warnings: Upozornenia analýzy
|
|
82
|
+
config: Navrhovaná konfigurácia
|
|
83
|
+
review: Pred použitím skontrolujte. Návrh nie je automatickým povolením ani bezpečnostným schválením. Žiadna konfigurácia nebola zmenená.
|
|
84
|
+
explicitly_allowed: Výslovne povolené
|
|
85
|
+
allowed_by_default: Predvolene povolené
|
|
86
|
+
blocked: Blokované
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Hľadať
|
|
70
90
|
clear: Vyčistiť
|
data/config/locales/sv.yml
CHANGED
|
@@ -65,6 +65,26 @@ sv:
|
|
|
65
65
|
files: Filer
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Tagganvändning
|
|
70
|
+
scope: Allt sparat innehåll på denna webbplats, även opublicerat innehåll. Ingen rendering vid körning.
|
|
71
|
+
multisite: Denna rapport för en webbplats är inte uttömmande för globala tillåtelselistor för flera webbplatser.
|
|
72
|
+
partial: Delvyer
|
|
73
|
+
helper: Hjälpmetoder
|
|
74
|
+
template: Mallar
|
|
75
|
+
name: Namn
|
|
76
|
+
status: Aktuell status
|
|
77
|
+
sources: Källor
|
|
78
|
+
used_in: Används i
|
|
79
|
+
no_results: Inga matchande taggar hittades.
|
|
80
|
+
incomplete: Rapporten är ofullständig. En del innehåll kunde inte analyseras; granska varningarna nedan.
|
|
81
|
+
warnings: Analysvarningar
|
|
82
|
+
config: Föreslagen konfiguration
|
|
83
|
+
review: Granska före användning. Förslaget är inte ett automatiskt tillstånd eller säkerhetsgodkännande. Ingen konfiguration har ändrats.
|
|
84
|
+
explicitly_allowed: Uttryckligen tillåtet
|
|
85
|
+
allowed_by_default: Tillåtet som standard
|
|
86
|
+
blocked: Blockerat
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Sök
|
|
70
90
|
clear: Rensa
|
data/config/locales/tr.yml
CHANGED
|
@@ -65,6 +65,26 @@ tr:
|
|
|
65
65
|
files: Dosyalar
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Etiket kullanımı
|
|
70
|
+
scope: Yayımlanmamış içerik dahil bu sitenin tüm kayıtlı içeriği. Çalışma zamanında işleme yapılmaz.
|
|
71
|
+
multisite: Bu tek site raporu, birden çok sitenin genel izin listeleri için kapsamlı değildir.
|
|
72
|
+
partial: Kısmi şablonlar
|
|
73
|
+
helper: Yardımcı metotlar
|
|
74
|
+
template: Şablonlar
|
|
75
|
+
name: Ad
|
|
76
|
+
status: Geçerli durum
|
|
77
|
+
sources: Kaynaklar
|
|
78
|
+
used_in: Kullanıldığı yerler
|
|
79
|
+
no_results: Eşleşen etiket bulunamadı.
|
|
80
|
+
incomplete: Rapor eksik. Bazı içerikler taranamadı; aşağıdaki uyarıları inceleyin.
|
|
81
|
+
warnings: Tarama uyarıları
|
|
82
|
+
config: Önerilen yapılandırma
|
|
83
|
+
review: Kullanmadan önce inceleyin. Bu öneri otomatik izin veya güvenlik onayı değildir. Hiçbir yapılandırma değiştirilmedi.
|
|
84
|
+
explicitly_allowed: Açıkça izin verilmiş
|
|
85
|
+
allowed_by_default: Varsayılan olarak izin verilmiş
|
|
86
|
+
blocked: Engellenmiş
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Ara
|
|
70
90
|
clear: Temizle
|
data/config/locales/uk.yml
CHANGED
|
@@ -65,6 +65,26 @@ uk:
|
|
|
65
65
|
files: Файли
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: Використання тегів
|
|
70
|
+
scope: Увесь збережений вміст цього сайту, включно з неопублікованим. Без рендерингу під час виконання.
|
|
71
|
+
multisite: Цей звіт для одного сайту не є вичерпним для глобальних списків дозволів кількох сайтів.
|
|
72
|
+
partial: Часткові шаблони
|
|
73
|
+
helper: Допоміжні методи
|
|
74
|
+
template: Шаблони
|
|
75
|
+
name: Назва
|
|
76
|
+
status: Поточний стан
|
|
77
|
+
sources: Джерела
|
|
78
|
+
used_in: Використано в
|
|
79
|
+
no_results: Відповідних тегів не знайдено.
|
|
80
|
+
incomplete: Звіт неповний. Частину вмісту не вдалося проаналізувати; перегляньте попередження нижче.
|
|
81
|
+
warnings: Попередження аналізу
|
|
82
|
+
config: Запропонована конфігурація
|
|
83
|
+
review: Перевірте перед використанням. Пропозиція не є автоматичним дозволом або підтвердженням безпеки. Конфігурацію не змінено.
|
|
84
|
+
explicitly_allowed: Явно дозволено
|
|
85
|
+
allowed_by_default: Дозволено за замовчуванням
|
|
86
|
+
blocked: Заблоковано
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: Пошук
|
|
70
90
|
clear: Очистити
|
data/config/locales/zh-CN.yml
CHANGED
|
@@ -65,6 +65,26 @@ zh-CN:
|
|
|
65
65
|
files: 文件
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: 标签使用情况
|
|
70
|
+
scope: 此站点的所有已保存内容,包括未发布的内容。不进行运行时渲染。
|
|
71
|
+
multisite: 此报告仅涵盖当前站点,不能完整反映多站点全局允许列表的需求。
|
|
72
|
+
partial: 局部模板
|
|
73
|
+
helper: 辅助方法
|
|
74
|
+
template: 模板
|
|
75
|
+
name: 名称
|
|
76
|
+
status: 当前状态
|
|
77
|
+
sources: 来源
|
|
78
|
+
used_in: 使用位置
|
|
79
|
+
no_results: 未找到匹配的标签。
|
|
80
|
+
incomplete: 报告不完整。部分内容无法扫描,请查看下面的警告。
|
|
81
|
+
warnings: 扫描警告
|
|
82
|
+
config: 候选配置
|
|
83
|
+
review: 使用前请审核。此候选配置不代表自动授权或安全批准。未更改任何配置。
|
|
84
|
+
explicitly_allowed: 明确允许
|
|
85
|
+
allowed_by_default: 默认允许
|
|
86
|
+
blocked: 已阻止
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: 搜索
|
|
70
90
|
clear: 清除
|
data/config/locales/zh-TW.yml
CHANGED
|
@@ -65,6 +65,26 @@ zh-TW:
|
|
|
65
65
|
files: 文件
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
tag_usage:
|
|
69
|
+
title: 標籤使用情況
|
|
70
|
+
scope: 此站點的所有已儲存內容,包括未發佈的內容。不進行執行時渲染。
|
|
71
|
+
multisite: 此報告僅涵蓋目前站點,無法完整反映多站點全域允許清單的需求。
|
|
72
|
+
partial: 局部範本
|
|
73
|
+
helper: 輔助方法
|
|
74
|
+
template: 範本
|
|
75
|
+
name: 名稱
|
|
76
|
+
status: 目前狀態
|
|
77
|
+
sources: 來源
|
|
78
|
+
used_in: 使用位置
|
|
79
|
+
no_results: 找不到符合的標籤。
|
|
80
|
+
incomplete: 報告不完整。部分內容無法掃描,請查看下方的警告。
|
|
81
|
+
warnings: 掃描警告
|
|
82
|
+
config: 候選設定
|
|
83
|
+
review: 使用前請審核。此候選設定不代表自動授權或安全核准。未變更任何設定。
|
|
84
|
+
explicitly_allowed: 明確允許
|
|
85
|
+
allowed_by_default: 預設允許
|
|
86
|
+
blocked: 已封鎖
|
|
87
|
+
|
|
68
88
|
search:
|
|
69
89
|
submit: 搜尋
|
|
70
90
|
clear: 清除
|
|
@@ -53,9 +53,9 @@ class ComfyMiddleSeat::Configuration
|
|
|
53
53
|
# @return [Boolean]
|
|
54
54
|
attr_accessor :allow_erb
|
|
55
55
|
|
|
56
|
-
#
|
|
57
|
-
# all helpers are allowed except `eval`, `
|
|
58
|
-
#
|
|
56
|
+
# Allowlist of helper methods available via {{cms:helper}}. With no array configured,
|
|
57
|
+
# all helpers are allowed except `eval`, `class_eval`, `instance_eval`, and `render`.
|
|
58
|
+
# An explicit array allows only its listed names; an empty array blocks all helpers.
|
|
59
59
|
attr_accessor :allowed_helpers
|
|
60
60
|
|
|
61
61
|
# Whitelist of partials paths that can be used via {{cms:partial}} tag. All partials
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Inventory raw CMS content without expanding tags or consulting rendered caches.
|
|
4
|
+
class ComfyMiddleSeat::Content::TagUsage
|
|
5
|
+
BATCH_SIZE = 1000
|
|
6
|
+
KINDS = {
|
|
7
|
+
'partial' => 'partial',
|
|
8
|
+
'render_partial' => 'partial',
|
|
9
|
+
'helper' => 'helper',
|
|
10
|
+
'template' => 'template',
|
|
11
|
+
'render_template' => 'template'
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
def initialize(sites: nil, scope: nil)
|
|
15
|
+
@sites = sites || Comfy::Cms::Site.all
|
|
16
|
+
@scope = scope || (sites.nil? ? 'all_sites' : 'selected_sites')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
@renderer = ComfyMiddleSeat::Content::Renderer.new(nil)
|
|
21
|
+
@entries = {}
|
|
22
|
+
@warnings = []
|
|
23
|
+
@source_count = 0
|
|
24
|
+
@allowlists = %w[partial helper template].to_h do |kind|
|
|
25
|
+
allowed = ComfyMiddleSeat.config.public_send("allowed_#{kind}s")
|
|
26
|
+
next [kind, nil] unless allowed.is_a?(Array)
|
|
27
|
+
|
|
28
|
+
# Only helper rendering stringifies allowlists; view paths use exact membership.
|
|
29
|
+
[kind, kind == 'helper' ? allowed.map(&:to_s) : allowed.dup]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
sites = site_details
|
|
33
|
+
site_ids = sites.map { |site| site[:id] }
|
|
34
|
+
scan_content(Comfy::Cms::Layout.where(site_id: site_ids), 'layout')
|
|
35
|
+
scan_content(Comfy::Cms::Snippet.where(site_id: site_ids), 'snippet')
|
|
36
|
+
scan_fragments(Comfy::Cms::Page.where(site_id: site_ids), 'page')
|
|
37
|
+
scan_fragments(Comfy::Cms::Translation.joins(:page).where(comfy_cms_pages: { site_id: site_ids }), 'translation')
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
scope: @scope,
|
|
41
|
+
sites: sites,
|
|
42
|
+
source_count: @source_count,
|
|
43
|
+
complete: @warnings.empty?,
|
|
44
|
+
entries: @entries.sort_by { |key, _entry| key }.map { |_key, entry| entry.merge(sources: entry[:sources].values) },
|
|
45
|
+
warnings: @warnings
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def site_details
|
|
52
|
+
sites = []
|
|
53
|
+
collect = ->(site) { sites << { id: site.id, identifier: site.identifier, label: site.label } }
|
|
54
|
+
if @sites.respond_to?(:find_each)
|
|
55
|
+
@sites.find_each(batch_size: BATCH_SIZE, &collect)
|
|
56
|
+
else
|
|
57
|
+
@sites.each(&collect)
|
|
58
|
+
end
|
|
59
|
+
sites.uniq { |site| site[:id] }.sort_by { |site| site[:id] }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def scan_content(records, type)
|
|
63
|
+
records.select(:id, :site_id, :label, :content).readonly.find_each(batch_size: BATCH_SIZE) do |record|
|
|
64
|
+
scan(record.content, {
|
|
65
|
+
site_id: record.site_id, type: type, id: record.id,
|
|
66
|
+
label: record.label, field: 'content', page_id: nil
|
|
67
|
+
})
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def scan_fragments(records, type)
|
|
72
|
+
table = records.klass.table_name
|
|
73
|
+
columns = ["#{table}.id", "#{table}.label", 'comfy_cms_pages.site_id']
|
|
74
|
+
columns << "#{table}.page_id" if type == 'translation'
|
|
75
|
+
|
|
76
|
+
# Pluck owner metadata rather than loading pages, their caches or associations.
|
|
77
|
+
records.in_batches(of: BATCH_SIZE) do |batch|
|
|
78
|
+
sources = batch.pluck(*columns).to_h do |id, label, site_id, page_id|
|
|
79
|
+
[id, { site_id: site_id, type: type, id: id, label: label, page_id: page_id }]
|
|
80
|
+
end
|
|
81
|
+
fragments = Comfy::Cms::Fragment.where(record_type: records.klass.polymorphic_name, record_id: sources.keys)
|
|
82
|
+
fragments.select(:id, :record_id, :identifier, :content).readonly.find_each(batch_size: BATCH_SIZE) do |fragment|
|
|
83
|
+
content = fragment.content
|
|
84
|
+
next unless content.is_a?(String)
|
|
85
|
+
|
|
86
|
+
scan(content, sources.fetch(fragment.record_id).merge(field: fragment.identifier))
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def scan(content, source)
|
|
92
|
+
@source_count += 1
|
|
93
|
+
@renderer.tokenize(content).each do |token|
|
|
94
|
+
next unless token.is_a?(Hash) && (kind = KINDS[token[:tag_class]])
|
|
95
|
+
|
|
96
|
+
scan_token(token, kind, source)
|
|
97
|
+
end
|
|
98
|
+
rescue ComfyMiddleSeat::Content::Renderer::SyntaxError => e
|
|
99
|
+
@warnings << { source: source, message: "Cannot tokenize source: #{e.message}" }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def scan_token(token, kind, source)
|
|
103
|
+
name = ComfyMiddleSeat::Content::ParamsParser.new(token[:tag_params]).params.first
|
|
104
|
+
unless name.is_a?(String) && name.present?
|
|
105
|
+
@warnings << { source: source, message: "Missing, blank or non-string name in #{token[:source]}" }
|
|
106
|
+
return
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
entry = @entries[[kind, name]] ||= { kind: kind, name: name, status: status(kind, name), sources: {} }
|
|
110
|
+
entry[:sources][source] = source
|
|
111
|
+
rescue ComfyMiddleSeat::Content::ParamsParser::Error => e
|
|
112
|
+
@warnings << { source: source, message: "Cannot parse #{token[:source]}: #{e.message}" }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def status(kind, name)
|
|
116
|
+
if (allowed = @allowlists[kind])
|
|
117
|
+
allowed.include?(name) ? 'explicitly_allowed' : 'blocked'
|
|
118
|
+
elsif kind == 'helper' && ComfyMiddleSeat::Content::Tags::Helper::BLACKLIST.include?(name)
|
|
119
|
+
'blocked'
|
|
120
|
+
else
|
|
121
|
+
'allowed_by_default'
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
class ComfyMiddleSeat::Content::TagUsageReport
|
|
6
|
+
KINDS = %w[partial helper template].freeze
|
|
7
|
+
STATUSES = {
|
|
8
|
+
'explicitly_allowed' => 'Explicitly allowed',
|
|
9
|
+
'allowed_by_default' => 'Allowed by default',
|
|
10
|
+
'blocked' => 'Blocked'
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
def initialize(report)
|
|
14
|
+
@report = report
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def json
|
|
18
|
+
JSON.pretty_generate(@report)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def text
|
|
22
|
+
lines = [
|
|
23
|
+
"Tag usage — #{scope}",
|
|
24
|
+
"Sites: #{@report[:sites].map { |site| site[:identifier].inspect }.join(', ')}",
|
|
25
|
+
"Sources scanned: #{@report[:source_count]}",
|
|
26
|
+
@report[:complete] ? 'Scan complete.' : 'Scan incomplete; review warnings.',
|
|
27
|
+
'Counts are saved source fields, not runtime executions.'
|
|
28
|
+
]
|
|
29
|
+
KINDS.each do |kind|
|
|
30
|
+
lines << "\n#{kind.capitalize}s"
|
|
31
|
+
entries = entries_for(kind)
|
|
32
|
+
lines << ' No matching tags found.' if entries.empty?
|
|
33
|
+
entries.each do |entry|
|
|
34
|
+
lines << " #{entry[:name].inspect} — #{STATUSES.fetch(entry[:status])} — #{entry[:sources].size} source(s)"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
"#{lines.join("\n")}\n"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def config
|
|
41
|
+
lines = [
|
|
42
|
+
'# Candidate allowlists only. Review every name before applying.',
|
|
43
|
+
'# Discovery is not security approval; blocked names are included.',
|
|
44
|
+
'# Replacing allowlists blocks omitted names, including existing approved uses.',
|
|
45
|
+
"# Scope: #{scope}. Sites: #{@report[:sites].map { |site| site[:identifier].inspect }.join(', ')}"
|
|
46
|
+
]
|
|
47
|
+
if @report[:scope] != 'all_sites'
|
|
48
|
+
lines << '# Site-filtered report: NOT a complete application-wide allowlist.'
|
|
49
|
+
end
|
|
50
|
+
lines << '# INCOMPLETE SCAN: resolve warnings before using these lists.' unless @report[:complete]
|
|
51
|
+
lines << 'ComfyMiddleSeat.configure do |config|'
|
|
52
|
+
KINDS.each do |kind|
|
|
53
|
+
names = entries_for(kind).map { |entry| entry[:name] }.uniq.sort
|
|
54
|
+
if names.empty?
|
|
55
|
+
lines << " config.allowed_#{kind}s = []"
|
|
56
|
+
else
|
|
57
|
+
lines << " config.allowed_#{kind}s = ["
|
|
58
|
+
names.each { |name| lines << " #{name.inspect}," }
|
|
59
|
+
lines << ' ]'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
lines << 'end'
|
|
63
|
+
"#{lines.join("\n")}\n"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def warnings
|
|
67
|
+
@report[:warnings].map do |warning|
|
|
68
|
+
source = warning[:source]
|
|
69
|
+
location = "site #{source[:site_id]}, #{source[:type]} #{source[:id]}, field #{source[:field].inspect}"
|
|
70
|
+
"Warning (#{location}): #{warning[:message].inspect}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def scope
|
|
77
|
+
@report[:scope] == 'all_sites' ? 'all sites' : 'selected sites'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def entries_for(kind)
|
|
81
|
+
@report[:entries].select { |entry| entry[:kind] == kind }.sort_by { |entry| entry[:name] }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -30,28 +30,23 @@ class ComfyMiddleSeat::Content::Tags::Asset < ComfyMiddleSeat::Content::Tag
|
|
|
30
30
|
def content
|
|
31
31
|
return '' unless layout
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
end
|
|
33
|
+
url_helpers = Rails.application.routes.url_helpers
|
|
34
|
+
options = { site_id: context.site.id, identifier: layout.identifier, cache_buster: layout.cache_buster, format: @type }
|
|
35
|
+
helpers = ActionController::Base.helpers
|
|
37
36
|
|
|
37
|
+
# These are CMS endpoints, not pipeline assets. Use HTML builders to avoid
|
|
38
|
+
# adding asset-host prefixes or applying asset-pipeline settings to the URL.
|
|
38
39
|
case @type
|
|
39
40
|
when 'css'
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
out = "<link href='#{out}' media='screen' rel='stylesheet' type='text/css' />"
|
|
43
|
-
end
|
|
44
|
-
out
|
|
41
|
+
path = url_helpers.comfy_cms_render_css_path(**options)
|
|
42
|
+
@as == 'tag' ? helpers.tag.link(href: path, media: 'screen', rel: 'stylesheet', type: 'text/css') : path
|
|
45
43
|
when 'js'
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
out = "<script src='#{out}' type='text/javascript'></script>"
|
|
49
|
-
end
|
|
50
|
-
out
|
|
44
|
+
path = url_helpers.comfy_cms_render_js_path(**options)
|
|
45
|
+
@as == 'tag' ? helpers.content_tag(:script, '', src: path, type: 'text/javascript') : path
|
|
51
46
|
end
|
|
52
47
|
end
|
|
53
48
|
end
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
%i[asset layout_asset].each do |name|
|
|
51
|
+
ComfyMiddleSeat::Content::Renderer.register_tag(name, ComfyMiddleSeat::Content::Tags::Asset)
|
|
52
|
+
end
|
|
@@ -41,7 +41,7 @@ class ComfyMiddleSeat::Content::Tags::Helper < ComfyMiddleSeat::Content::Tag
|
|
|
41
41
|
def render
|
|
42
42
|
whitelist = ComfyMiddleSeat.config.allowed_helpers
|
|
43
43
|
if whitelist.is_a?(Array)
|
|
44
|
-
content if whitelist.map
|
|
44
|
+
content if whitelist.map(&:to_s).member?(method_name)
|
|
45
45
|
else
|
|
46
46
|
content unless BLACKLIST.member?(method_name)
|
|
47
47
|
end
|
|
@@ -24,22 +24,18 @@ module ComfyMiddleSeat::Content::Tags::Mixins
|
|
|
24
24
|
url_helpers.rails_blob_path(file, only_path: true)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
helpers = ActionController::Base.helpers
|
|
28
|
+
|
|
29
|
+
# Blob and variant URLs are not pipeline assets; HTML builders keep them
|
|
30
|
+
# relative instead of applying image_tag's asset-host settings.
|
|
27
31
|
case as
|
|
28
32
|
when 'link'
|
|
29
|
-
|
|
33
|
+
helpers.content_tag(:a, label, href: attachment_url, class: @class.presence, target: '_blank', rel: 'noopener')
|
|
30
34
|
when 'image'
|
|
31
|
-
|
|
35
|
+
helpers.tag.img(src: attachment_url, class: @class.presence, alt: label, title: label)
|
|
32
36
|
else
|
|
33
37
|
attachment_url
|
|
34
38
|
end
|
|
35
39
|
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def html_class_attribute
|
|
40
|
-
return if @class.blank?
|
|
41
|
-
|
|
42
|
-
" class='#{@class}'"
|
|
43
|
-
end
|
|
44
40
|
end
|
|
45
41
|
end
|
|
@@ -42,6 +42,6 @@ class ComfyMiddleSeat::Content::Tags::Partial < ComfyMiddleSeat::Content::Tag
|
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
%i[partial render_partial].each do |name|
|
|
46
|
+
ComfyMiddleSeat::Content::Renderer.register_tag(name, ComfyMiddleSeat::Content::Tags::Partial)
|
|
47
|
+
end
|
|
@@ -37,6 +37,6 @@ class ComfyMiddleSeat::Content::Tags::Template < ComfyMiddleSeat::Content::Tag
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
%i[template render_template].each do |name|
|
|
41
|
+
ComfyMiddleSeat::Content::Renderer.register_tag(name, ComfyMiddleSeat::Content::Tags::Template)
|
|
42
|
+
end
|