diff --git a/Procfile.dev b/Procfile.dev
index 5c7ab2e..8cec4c8 100644
--- a/Procfile.dev
+++ b/Procfile.dev
@@ -1,3 +1,3 @@
web: RUBY_DEBUG_OPEN=true bin/rails server -b 0
-js: yarn build --watch
+js: yarn build --watch=forever
css: yarn watch:css
diff --git a/README.md b/README.md
index 4f83e3b..ec40b05 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,7 @@
`rails new -n a11yist -d sqlite3 --skip-action-mailbox --css bootstrap --js esbuild .`
+
+## Installation
+
+To [install](readme)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7a1bd32..41d97ec 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -25,10 +25,6 @@ class ApplicationController < ActionController::Base
label: Project.model_name.human(count: 2),
icon: :'folder',
path: :projects },
- # {
- # label: Report.model_name.human(count: 2),
- # icon: :'journal-text',
- # path: :reports },
{
label: I18n.t("backoffice"),
icon: :gear,
@@ -36,7 +32,8 @@ class ApplicationController < ActionController::Base
active: %w[backoffice checklists checks links link_categories].include?(controller_name) },
{
label: "Konto",
- path: profile_path
+ path: profile_path,
+ icon: "person-circle"
}
]
else
diff --git a/app/controllers/checks_controller.rb b/app/controllers/checks_controller.rb
index 303415e..f1c1e3e 100644
--- a/app/controllers/checks_controller.rb
+++ b/app/controllers/checks_controller.rb
@@ -81,7 +81,7 @@ class ChecksController < ApplicationController
# Only allow a list of trusted parameters through.
def check_params
- params.require(:check).permit(:principle_id,
+ params.require(:check).permit(:guideline_id,
:number,
:name_de,
:name_en,
diff --git a/app/controllers/concerns/backoffice_menu.rb b/app/controllers/concerns/backoffice_menu.rb
index e2f72fb..9ab5278 100644
--- a/app/controllers/concerns/backoffice_menu.rb
+++ b/app/controllers/concerns/backoffice_menu.rb
@@ -5,6 +5,7 @@ module BackofficeMenu
[
{ label: "Einstellungen", icon: :sliders, path: :backoffice },
{ label: Checklist.model_name.human(count: 2), icon: :'list-check', path: :checklists },
+ { label: Guideline.model_name.human(count: 2), icon: :'rulers', path: :guidelines },
{ label: Check.model_name.human(count: 2), icon: :check2, path: :checks },
{ label: Link.model_name.human(count: 2), icon: :link, path: :links },
{ label: LinkCategory.model_name.human(count: 2), icon: :folder, path: :link_categories } ]
diff --git a/app/controllers/guidelines_controller.rb b/app/controllers/guidelines_controller.rb
new file mode 100644
index 0000000..e69449d
--- /dev/null
+++ b/app/controllers/guidelines_controller.rb
@@ -0,0 +1,58 @@
+class GuidelinesController < BackofficeController
+ before_action :set_guideline, only: %i[ show edit update destroy ]
+
+ # GET /guidelines
+ def index
+ @guidelines = Guideline.all
+ end
+
+ # GET /guidelines/1
+ def show
+ end
+
+ # GET /guidelines/new
+ def new
+ @guideline = Guideline.new
+ end
+
+ # GET /guidelines/1/edit
+ def edit
+ end
+
+ # POST /guidelines
+ def create
+ @guideline = Guideline.new(guideline_params)
+
+ if @guideline.save
+ redirect_to @guideline, notice: "Guideline was successfully created."
+ else
+ render :new, status: :unprocessable_entity
+ end
+ end
+
+ # PATCH/PUT /guidelines/1
+ def update
+ if @guideline.update(guideline_params)
+ redirect_to @guideline, notice: "Guideline was successfully updated.", status: :see_other
+ else
+ render :edit, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /guidelines/1
+ def destroy
+ @guideline.destroy!
+ redirect_to guidelines_url, notice: "Guideline was successfully destroyed.", status: :see_other
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_guideline
+ @guideline = Guideline.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def guideline_params
+ params.require(:guideline).permit(:principle_id, :number, :name_de, :name_en, :description_de, :description_en)
+ end
+end
diff --git a/app/javascript/controllers/toast_controller.js b/app/javascript/controllers/toast_controller.js
index 55d8ea1..e8b23e8 100644
--- a/app/javascript/controllers/toast_controller.js
+++ b/app/javascript/controllers/toast_controller.js
@@ -4,7 +4,11 @@ import * as bootstrap from "bootstrap"
// Connects to data-controller="toast"
export default class extends Controller {
connect() {
- const toastBootstrap = bootstrap.Toast.getOrCreateInstance(this.element)
- toastBootstrap.show()
+ const shownKey = `toastsShown[${this.element.getAttribute("data-ts")}]`
+ if(!window.sessionStorage.getItem(shownKey)) {
+ window.sessionStorage.setItem(shownKey, Date.now());
+ const toastBootstrap = bootstrap.Toast.getOrCreateInstance(this.element)
+ toastBootstrap.show()
+ }
}
}
diff --git a/app/models/check.rb b/app/models/check.rb
index a201aa8..a60d5e2 100644
--- a/app/models/check.rb
+++ b/app/models/check.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Check < ApplicationRecord
- belongs_to :principle
+ belongs_to :guideline
has_and_belongs_to_many :links
has_and_belongs_to_many :standards
@@ -51,9 +51,9 @@ class Check < ApplicationRecord
:standard_text,
:powerpoint_text
- validates :number, uniqueness: true, presence: true
+ validates :number, uniqueness: { scope: :guideline_id }, presence: true
- before_validation { self.number = self.class.maximum(:id).to_i + 1 unless self.number.present? }
+ # before_validation { self.number = self.class.maximum(:id).to_i + 1 unless self.number.present? }
scope(:search, lambda { |terms|
# TODO: Search only fields for current locale.
@@ -129,4 +129,20 @@ class Check < ApplicationRecord
def external_number
[ external_number_1, external_number_2, external_number_3 ].compact_blank.join(".")
end
+
+ def external_number
+ [
+ guideline.principle.id,
+ guideline.number,
+ number
+ ].compact.join(".")
+ end
+
+ def full_number
+ external_number
+ end
+
+ def to_s
+ display_label
+ end
end
diff --git a/app/models/guideline.rb b/app/models/guideline.rb
new file mode 100644
index 0000000..baeac74
--- /dev/null
+++ b/app/models/guideline.rb
@@ -0,0 +1,18 @@
+class Guideline < ApplicationRecord
+ belongs_to :principle
+
+ has_many :checks
+
+ has_rich_text :description_de
+ has_rich_text :description_en
+
+ translates_attributes :name, :description
+
+ def to_s
+ "#{full_number} #{t_name}"
+ end
+
+ def full_number
+ [ principle.id, number ].join(".")
+ end
+end
diff --git a/app/models/report.rb b/app/models/report.rb
index 68a36ab..df65fc4 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -21,4 +21,8 @@ class Report < ApplicationRecord
success_criteria: export_success_criteria
}
end
+
+ def test
+ 139
+ end
end
diff --git a/app/views/backoffice/show.html.erb b/app/views/backoffice/show.html.erb
index c16d394..8bcbd75 100644
--- a/app/views/backoffice/show.html.erb
+++ b/app/views/backoffice/show.html.erb
@@ -7,6 +7,12 @@
<%= link_to Checklist.model_name.human(count: Checklist.count), :checklists %>
+
+
+<%= Guideline.count %>
+<%= link_to Guideline.model_name.human(count: Guideline.count), :guidelines %>
+
+
<%= Check.count %>
@@ -27,4 +33,4 @@
<%= link_to "ZIP Backup herunterladen", admin_backup_url(format: :zip), class: " ", data: { turbo_prefetch: false, frame: "_top", turbo: false } %>
-
\ No newline at end of file
+
diff --git a/app/views/checks/_check.html.slim b/app/views/checks/_check.html.slim
index 62996f0..7f99880 100644
--- a/app/views/checks/_check.html.slim
+++ b/app/views/checks/_check.html.slim
@@ -11,8 +11,8 @@ div id=dom_id(check)
th = Check.human_attribute_name(:number)
td = check.number
tr
- th = Principle.model_name.human
- td = check.principle&.t_name
+ th = Guideline.model_name.human
+ td = check.guideline&.name_en
tr
th = Standard.model_name.human(count: check.standard_ids.size)
td = check.standards.map(&:t_name).sort_by(&:downcase).join(", ")
@@ -80,4 +80,4 @@ div id=dom_id(check)
ul
- check.links.select{ _1.link_category == category }.map { |link| link_to link.text, link.url, target: :_blank }.each do |link|
li = link
-
\ No newline at end of file
+
diff --git a/app/views/checks/_form.html.slim b/app/views/checks/_form.html.slim
index 53e4bb7..9f5bb2c 100644
--- a/app/views/checks/_form.html.slim
+++ b/app/views/checks/_form.html.slim
@@ -1,9 +1,9 @@
= bootstrap_form_with(model: check, remote: true, data: { controller: "unsaved-changes" }) do |form|
h2 Details
= multilang_form_field(form, :name)
- = form.text_field :number, required: false
.row
- = form.collection_radio_buttons(:principle_id, Principle.all.sort_by(&:t_name), :id, :t_name) { |b| b.label(class: "col-md-2") { b.radio_button + b.text } }
+ = form.collection_radio_buttons(:guideline_id, Guideline.all.sort_by(&:full_number), :id, :to_s) { |b| b.label(class: "col-md-2") { b.radio_button + b.text } }
+ = form.text_field :number, required: false
= form.collection_check_boxes :standard_ids, Standard.all.sort_by{ _1.t_name.downcase }, :id, :t_name, include_blank: true
h2 Einschränkung/Zugänglichkeit
diff --git a/app/views/elements/_form.html.slim b/app/views/elements/_form.html.slim
index 4feb80d..b821401 100644
--- a/app/views/elements/_form.html.slim
+++ b/app/views/elements/_form.html.slim
@@ -6,4 +6,5 @@
- if element.persisted?
= safe_display(element.screenshot) { tag.div(link_to(_1.filename.to_s, _1), class: "mb-3") }
= form.submit class: "btn btn-primary"
- = link_to("Abbrechen", element.persisted? ? element : element.report, class: "btn btn-outline-secondary")
+ - unless modal?
+ = link_to("Abbrechen", element.persisted? ? element : element.report, class: "btn btn-outline-secondary")
diff --git a/app/views/exports/show.html.slim b/app/views/exports/show.html.slim
index d7ca86d..1fe71d1 100644
--- a/app/views/exports/show.html.slim
+++ b/app/views/exports/show.html.slim
@@ -1,26 +1,3 @@
-/nav
- = link_to(@report.name, "##{dom_id(@report)}")
- ul
- li = link_to("Inhaltsverzeichnis", "#toc")
- li
- = link_to('Testbericht')
- ul
- - @report.pages.select { |p| p.elements.any? { |e| e.success_criteria.any?(&:failed?) } }.each do |page|
- li
- = link_to("#{page.position} #{page.path}", "##{dom_id(page)}")
- ul
- - page.elements.select { |e| e.success_criteria.any?(&:failed?) }.each do |element|
- li
- = link_to("#{element.number} #{element.title}")
- ul
- - element.success_criteria.select(&:failed?).each do |sc|
- li = link_to("#{sc.number} #{sc.title}", "##{dom_id(sc)}")
- li
- = link_to("Anhang")
- ul
- - @failed_success_criteria.group_by(&:check).each do |check, scs|
- li = link_to(check.display_label)
-
h1.title id=dom_id(@report) = @report.name
h2 1 Einschätzung
@@ -42,18 +19,18 @@ h2 2 Protokoll
- current_page_pos += 1
- current_element_pos = 0
h3 = "2.#{current_page_pos} #{page.path}"
+ p
+ strong URL
+ = page.url
- page.elements.select { |e| e.success_criteria.any? { _1.failed? } }.each do |element|
- current_element_pos += 1
- current_abs_element_pos += 1
- current_sc_pos = 0
h4 = "2.#{current_page_pos}.#{current_element_pos} #{element.title}"
/h3 = "2.#{current_abs_element_pos} #{element.title}"
- p
- strong Pfad:
- span =< page.path
= safe_display(element.screenshot) { image_tag(_1.representation(resize_to_fit: [250, 250]))}
= element.description
- - element.success_criteria.select{ _1.failed? }.each do |sc|
+ - element.success_criteria.select(&:failed?).each do |sc|
- current_sc_pos += 1
/h4
= "2.#{current_abs_element_pos}.#{current_sc_pos} #{sc.title}"
diff --git a/app/views/guidelines/_form.html.erb b/app/views/guidelines/_form.html.erb
new file mode 100644
index 0000000..d3c952a
--- /dev/null
+++ b/app/views/guidelines/_form.html.erb
@@ -0,0 +1,7 @@
+<%= bootstrap_form_with(model: guideline) do |form| %>
+ <%= form.collection_select :principle_id, Principle.all.sort_by(&:id), :id, :t_name %>
+ <%= form.number_field :number %>
+ <%= form.text_field :name_de %>
+ <%= form.rich_text_area :description_de %>
+ <%= form.submit %>
+<% end %>
diff --git a/app/views/guidelines/_guideline.html.erb b/app/views/guidelines/_guideline.html.erb
new file mode 100644
index 0000000..0560533
--- /dev/null
+++ b/app/views/guidelines/_guideline.html.erb
@@ -0,0 +1,15 @@
+
+
+ Principle:
+ <%= guideline.principle.t_name %>
+
+
+ <%= guideline.description_de %>
+
Richtlinien
+ <% guideline.checks.each do |check| %>
+
+ <%= link_to check %>
+ <%= check.t_criterion %>
+
+ <% end %>
+
diff --git a/app/views/guidelines/_guideline.json.jbuilder b/app/views/guidelines/_guideline.json.jbuilder
new file mode 100644
index 0000000..72c091d
--- /dev/null
+++ b/app/views/guidelines/_guideline.json.jbuilder
@@ -0,0 +1,2 @@
+json.extract! guideline, :id, :principle_id, :number, :name_de, :created_at, :updated_at
+json.url guideline_url(guideline, format: :json)
diff --git a/app/views/guidelines/edit.html.erb b/app/views/guidelines/edit.html.erb
new file mode 100644
index 0000000..2411616
--- /dev/null
+++ b/app/views/guidelines/edit.html.erb
@@ -0,0 +1,8 @@
+<%= t("scaffold.pagetitle_edit", model: Guideline.model_name.human) %>
+
+<%= render "form", guideline: @guideline %>
+
+
+ <%= link_to t("scaffold.link_show", model: Guideline.model_name.human), @guideline %>
+ <%= link_to t("scaffold.link_index", model: Guideline.model_name.human(count: 2)), guidelines_path %>
+
diff --git a/app/views/guidelines/index.html.erb b/app/views/guidelines/index.html.erb
new file mode 100644
index 0000000..fe34cbf
--- /dev/null
+++ b/app/views/guidelines/index.html.erb
@@ -0,0 +1,28 @@
+<%= t("scaffold.pagetitle_index", model: Guideline.model_name.human(count: 2)) %>
+
+
+
+
+
+ | <%= Guideline.human_attribute_name(:name_de) %> |
+
+ <%= Guideline.human_attribute_name(:description_de) %> |
+
+
+
+ <% @guidelines.each do |guideline| %>
+
+
+
+
+ | <%= link_to(guideline, url_for(guideline)) %> |
+ <%= link_to(guideline.description_de, url_for(guideline)) %> |
+
+
+ <% end %>
+
+
+
+
+ <%= link_to t("scaffold.link_new", model: Guideline.model_name.human), new_guideline_path %>
+
diff --git a/app/views/guidelines/index.json.jbuilder b/app/views/guidelines/index.json.jbuilder
new file mode 100644
index 0000000..cd94a2f
--- /dev/null
+++ b/app/views/guidelines/index.json.jbuilder
@@ -0,0 +1 @@
+json.array! @guidelines, partial: "guidelines/guideline", as: :guideline
diff --git a/app/views/guidelines/new.html.erb b/app/views/guidelines/new.html.erb
new file mode 100644
index 0000000..7e57546
--- /dev/null
+++ b/app/views/guidelines/new.html.erb
@@ -0,0 +1,7 @@
+<%= t("scaffold.pagetitle_new", model: Guideline.model_name.human) %>
+
+<%= render "form", guideline: @guideline %>
+
+
+ <%= link_to t("scaffold.link_index", model: Guideline.model_name.human(count: 2)), guidelines_path %>
+
diff --git a/app/views/guidelines/show.html.erb b/app/views/guidelines/show.html.erb
new file mode 100644
index 0000000..7334fa3
--- /dev/null
+++ b/app/views/guidelines/show.html.erb
@@ -0,0 +1,9 @@
+<%= @guideline %>
+
+<%= render @guideline %>
+
+
+ <%= link_to t("scaffold.link_edit", model: @guideline.model_name.human), edit_guideline_path(@guideline) %>
+ <%= link_to t("scaffold.link_index", model: @guideline.model_name.human(count: 2)), guidelines_path %>
+ <%= button_to t("scaffold.link_destroy", model: @guideline.model_name.human), @guideline, method: :delete, class: "btn btn-outline-danger" %>
+
diff --git a/app/views/guidelines/show.json.jbuilder b/app/views/guidelines/show.json.jbuilder
new file mode 100644
index 0000000..a0b1efe
--- /dev/null
+++ b/app/views/guidelines/show.json.jbuilder
@@ -0,0 +1 @@
+json.partial! "guidelines/guideline", guideline: @guideline
diff --git a/app/views/home/show.html.slim b/app/views/home/show.html.slim
index 1ab4d19..2d5443c 100644
--- a/app/views/home/show.html.slim
+++ b/app/views/home/show.html.slim
@@ -19,6 +19,12 @@ h1 Dashboard
li = link_to(r.name, r)
.col-md-6
+ h2 Browser Erweiterungen
+ p = link_to "Language Tools KI Korrektur", "https://languagetool.org/services#browsers"
+ p = link_to "DeepL Firefox Extension", "https://www.deepl.com/en/firefox-extension"
+ p = link_to "DeepL Chrome Extension", "https://www.deepl.com/en/chrome-extension"
+ p = link_to "DeepL Edge Extension", "https://www.deepl.com/en/edge-extension"
+
h2 Hotkeys
p Auf der Bericht-Ausfüllen Seite können folgende Shortcuts verwendet werden:
dl
diff --git a/app/views/layouts/_toast.html.slim b/app/views/layouts/_toast.html.slim
index 5917715..600e969 100644
--- a/app/views/layouts/_toast.html.slim
+++ b/app/views/layouts/_toast.html.slim
@@ -1,4 +1,4 @@
-.toast class="#{alert ? "text-bg-danger" : "text-bg-info"}" role="alert" aria-live="assertive" aria-atomic="true" data={ controller: "toast" }
+.toast class="#{alert ? "text-bg-danger" : "text-bg-info"}" role="alert" aria-live="assertive" aria-atomic="true" data={ controller: "toast", ts: Time.now.to_f }
.toast-header
/img src="..." class="rounded me-2" alt="...">
/strong.me-auto = heading
diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim
index ac756a6..a53d602 100644
--- a/app/views/layouts/application.html.slim
+++ b/app/views/layouts/application.html.slim
@@ -1,5 +1,5 @@
doctype html
-html data-bs-theme="#{cookies[:"modeTheme"] || "light"}" data-controller="set-theme"
+html lang=:de data-bs-theme="#{cookies[:"modeTheme"] || "light"}" data-controller="set-theme"
head
title a11ydive
meta[name="viewport" content="width=device-width,initial-scale=1"]
diff --git a/app/views/pages/_form.html.slim b/app/views/pages/_form.html.slim
index 0d0beda..a909d1f 100644
--- a/app/views/pages/_form.html.slim
+++ b/app/views/pages/_form.html.slim
@@ -2,4 +2,5 @@
= form.text_field :path
= form.text_field :url
= form.submit
- = link_to("Abbrechen", report_path(@page.report), class: "btn btn-outline-secondary")
+ - unless modal?
+ = link_to("Abbrechen", report_path(@page.report), class: "btn btn-outline-secondary")
diff --git a/app/views/success_criteria/_form.html.slim b/app/views/success_criteria/_form.html.slim
index c67c2b0..b459173 100644
--- a/app/views/success_criteria/_form.html.slim
+++ b/app/views/success_criteria/_form.html.slim
@@ -7,4 +7,5 @@
= form.rich_text_area :test_comment
= form.submit class: "btn btn-primary"
- unless modal?
+ p Not MODAL
=< link_to "Abbrechen", success_criterion.persisted? ? success_criterion : success_criterion.element, class: "btn btn-outline-secondary"
diff --git a/bin/dev b/bin/dev
index edcb0e0..eda330c 100755
--- a/bin/dev
+++ b/bin/dev
@@ -8,4 +8,4 @@ fi
# Default to port 3000 if not specified
export PORT="${PORT:-3000}"
-exec foreman start -f /app/Procfile.dev "$@"
+exec foreman start -f Procfile.dev "$@"
diff --git a/bin/dev_entrypoint b/bin/dev_entrypoint
index 3062b49..1ca3bf7 100755
--- a/bin/dev_entrypoint
+++ b/bin/dev_entrypoint
@@ -1,7 +1,7 @@
#!/bin/bash
-if [ -f /app/tmp/pids/server.pid ]; then
- rm /app/tmp/pids/server.pid
+if [ -f tmp/pids/server.pid ]; then
+ rm tmp/pids/server.pid
fi
exec "$@"
diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc
index 7741360..d5e9f74 100644
--- a/config/credentials.yml.enc
+++ b/config/credentials.yml.enc
@@ -1 +1 @@
-vRtWWWCynlFuZljZsCQOV5D6xZlwp/LkuGZ2bPp1IuZiCRfJ2F8CXbubRavkqM0xxpHWkC7hiQ0lSv/dCPtaujG+aJ2Q0+KSw81kJ3xiYd/AiR3ZxO9prk5Zsf0LPLoONGBbYurJIb37hAWQ7h1r1qORLbtQGLb9pYlynObhXvkaYQR5E7Jr0Rcnon0d2uKJ13ukDAHUiIgwCE5/f+Y6UVllTLBCk0a+YDZvkv7xsYNpTTD9bgjpAU/pg6jv1xY0k/gZ8SFRsSQaJs8CYtbhMsyZBvImtguGfc7U7B4cFrgdzUPY473vBKBqm6O0StNagS5muP3/YLLN7xcrRDTBi9n3qllATlfJ9cxZ+JCWZJmyqINI4X+T/sc3lpzlo/grW0W+HwQ/4CZ3LkCN/OOqZlG1HL1u--NhnYNqgGpqSnh7Ut--KGndHl8kyj/uAjRG12R3zg==
\ No newline at end of file
+TjpgJe/DwNAzOraDbzXUo20hxCLkOn72DlXYkIouG0crCD3m4/LAiwDOlOWwsCO5Je6FzqKZniLUqSfVthChxewvZn+PY7XGTLECbB9gjSpRC6hERUxKIirLot+CH7lkMlM3f4o3NPf2I4vs8j6hooXcc8Vd8l1uMHOU1RHd+8EfPmTetqd0IETnEUdXigL50yjcbpxy8jHGdaeA8hHU3F+jwk7gRv11uVgEfn069qD9tc5AlAFWdnYJj/ZadAX2+bimHyne5Y12gmRAiqu95KXzUs0OlI+Vx9lpFyMQNacuKPPx0AeeBafjnMBozXOSU7MMCBUGzig07Kg+/tJSiekeLX0X2VEj3Ecqe9nL54fAGVSqJmwT19KvjeS4WfjvFDff9KAY4H+vKzfkBQzMFOTJjnMTNHa+dtNly0kUphwDtsFWDhF3PaZQIRCeI7RIXKhFMgrRFE6UL4AFFzhocQ1DAwaZElXFJaKjiCWWCY+acLCRz2AnriR08KMsEGN54nMtcGcWnUS2ewr/txLQDkipjADYmjoxsz+rDqp2IH+4y4ZFJf8=--jX6TlsuL0nwliAuN--lnbA1H3K7bwrmIjgJzAT9A==
\ No newline at end of file
diff --git a/config/initializers/deepl.rb b/config/initializers/deepl.rb
new file mode 100644
index 0000000..007121a
--- /dev/null
+++ b/config/initializers/deepl.rb
@@ -0,0 +1,6 @@
+if Rails.application.credentials[:deepl_api_key]
+ DeepL.configure do |config|
+ config.auth_key = Rails.application.credentials[:deepl_api_key]
+ config.host = "https://api-free.deepl.com"
+ end
+end
diff --git a/config/routes.rb b/config/routes.rb
index 7b3bcee..1c19c13 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,5 +1,6 @@
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
Rails.application.routes.draw do
+ resources :guidelines
resource :session
resources :passwords, param: :token
namespace :admin do
diff --git a/db/migrate/20250101163808_create_guidelines.rb b/db/migrate/20250101163808_create_guidelines.rb
new file mode 100644
index 0000000..197cb17
--- /dev/null
+++ b/db/migrate/20250101163808_create_guidelines.rb
@@ -0,0 +1,12 @@
+class CreateGuidelines < ActiveRecord::Migration[8.0]
+ def change
+ create_table :guidelines do |t|
+ t.references :principle, null: false, foreign_key: true
+ t.integer :number
+ t.string :name_de
+ t.string :name_en
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20250101163835_add_guideline_id_to_checks.rb b/db/migrate/20250101163835_add_guideline_id_to_checks.rb
new file mode 100644
index 0000000..09662e8
--- /dev/null
+++ b/db/migrate/20250101163835_add_guideline_id_to_checks.rb
@@ -0,0 +1,6 @@
+class AddGuidelineIdToChecks < ActiveRecord::Migration[8.0]
+ def change
+ add_reference :checks, :guideline, null: false, foreign_key: true
+ remove_reference :checks, :principle
+ end
+end
diff --git a/db/migrate/20250101171836_remove_unique_number_constraint_on_checks.rb b/db/migrate/20250101171836_remove_unique_number_constraint_on_checks.rb
new file mode 100644
index 0000000..1406d2b
--- /dev/null
+++ b/db/migrate/20250101171836_remove_unique_number_constraint_on_checks.rb
@@ -0,0 +1,5 @@
+class RemoveUniqueNumberConstraintOnChecks < ActiveRecord::Migration[8.0]
+ def change
+ remove_index :checks, :number
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 754674b..55b94e9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[8.0].define(version: 2024_11_24_183406) do
+ActiveRecord::Schema[8.0].define(version: 2025_01_01_171836) do
create_table "account_remember_keys", force: :cascade do |t|
t.string "key", null: false
t.datetime "deadline", null: false
@@ -94,7 +94,6 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_24_183406) do
t.boolean "cognitive", default: false, null: false
t.boolean "applicable_to_web", default: false, null: false
t.boolean "applicable_to_app", default: false, null: false
- t.integer "principle_id"
t.integer "conformity_level"
t.integer "priority"
t.boolean "manual_test", default: true, null: false
@@ -106,8 +105,8 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_24_183406) do
t.integer "external_number_1"
t.integer "external_number_2"
t.integer "external_number_3"
- t.index ["number"], name: "index_checks_on_number", unique: true
- t.index ["principle_id"], name: "index_checks_on_principle_id"
+ t.integer "guideline_id", null: false
+ t.index ["guideline_id"], name: "index_checks_on_guideline_id"
end
create_table "checks_links", id: false, force: :cascade do |t|
@@ -131,6 +130,16 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_24_183406) do
t.index ["page_id"], name: "index_elements_on_page_id"
end
+ create_table "guidelines", force: :cascade do |t|
+ t.integer "principle_id", null: false
+ t.integer "number"
+ t.string "name_de"
+ t.string "name_en"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["principle_id"], name: "index_guidelines_on_principle_id"
+ end
+
create_table "link_categories", force: :cascade do |t|
t.string "name"
t.text "description"
@@ -230,8 +239,9 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_24_183406) do
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "checklist_entries", "checklists"
add_foreign_key "checklist_entries", "checks"
- add_foreign_key "checks", "principles"
+ add_foreign_key "checks", "guidelines"
add_foreign_key "elements", "pages"
+ add_foreign_key "guidelines", "principles"
add_foreign_key "links", "link_categories"
add_foreign_key "pages", "reports"
add_foreign_key "reports", "projects"
diff --git a/db/seeds.rb b/db/seeds.rb
index b0ddeb2..bf0bfc7 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -72,6 +72,8 @@ Principle.create!(name_de: "Verständlich", name_en: "Understandable")
Principle.create!(name_de: "Robust", name_en: "Robust")
Principle.create!(name_de: "Sonstige", name_en: "Other")
+LinkCategory.create!(name: "Verstehen")
+LinkCategory.create!(name: "WCAG Quick Reference")
LinkCategory.create!(name: "Tools")
LinkCategory.create!(name: "Beispiele")
LinkCategory.create!(name: "Artikel")
@@ -92,4 +94,3 @@ Link.create!(url: "https://www.a11yproject.com/",
link_category: LinkCategory.find_by(name: "Artikel"))
User.find_or_initialize_by(email_address: "admin@example.com").update!(password: "password")
-User.find_or_initialize_by(email_address: "goran@quiet.ch").update!(password: "password")
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 5ce4a06..0000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-# This is available in $COMPOSE_PROJECT_NAME
-name: a11yist
-
-networks:
- traefik:
- external: true
-
-services:
- app: &app
- build:
- context: .
- restart: "unless-stopped"
- command: ["/bin/sh", "-c", "/app/bin/dev"]
- volumes:
- - ./:/app:cached
- - ${PWD}:${PWD}
- - ${SSH_AUTH_SOCK}:/ssh-agent
- - .devenv/helix:/home/app/.config/helix
- - .devenv/fish:/home/app/.config/fish
- env_file:
- - .env
- environment:
- RAILS_ENV: development
- LOG_LEVEL: debug
- TRUSTED_IP: 172.16.0.0/12,192.168.0.0/16,10.0.0.0/24
- SSH_AUTH_SOCK: /ssh-agent
- RAILS_SERVE_STATIC_FILES: 1
- APP_HOST: ${COMPOSE_PROJECT_NAME}.localhost
- HISTFILE: /app/tmp/.bash_history
- PSQL_HISTORY: /app/tmp/.psql_history
- IRBRC: /app/.irbrc
- SELENIUM_REMOTE_URL: http://chrome:4444/wd/hub
- labels:
- - traefik.http.routers.app-${COMPOSE_PROJECT_NAME}.entrypoints=http
- - traefik.http.routers.app-${COMPOSE_PROJECT_NAME}.rule=Host(`${COMPOSE_PROJECT_NAME}.localhost`)
- - traefik.http.services.app-${COMPOSE_PROJECT_NAME}.loadbalancer.server.port=3000
- - traefik.docker.network=traefik
- networks:
- - traefik
- - default
-
- edit:
- <<: *app
- restart: "no"
- labels: []
- depends_on: []
- command: ["hx", "."]
- entrypoint: null
- networks:
- - default
-
- chrome:
- image: selenium/standalone-chrome
- shm_size: 2g
- labels:
- - traefik.http.routers.chrome-${COMPOSE_PROJECT_NAME}.entrypoints=http
- - traefik.http.routers.chrome-${COMPOSE_PROJECT_NAME}.rule=Host(`chrome.${COMPOSE_PROJECT_NAME}.localhost`)
- - traefik.http.services.chrome-${COMPOSE_PROJECT_NAME}.loadbalancer.server.port=4444
- - traefik.docker.network=traefik
- networks:
- - traefik
- - default
diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake
index dccb8d4..ef0cc5a 100644
--- a/lib/tasks/import.rake
+++ b/lib/tasks/import.rake
@@ -1,20 +1,66 @@
# frozen_string_literal: true
+
URL = "https://outline-rocks.github.io/wcag/translations/WCAG21-de/"
WCAG_22_EN_URL ="https://www.w3.org/TR/WCAG22/"
+WCAG_22_EN_QREF_URL = "https://www.w3.org/WAI/WCAG22/quickref/"
+
+def translate(input)
+ DeepL.translate(input, "EN", "DE")
+end
def import_wcag22en
doc = Nokogiri::HTML5(URI.open(WCAG_22_EN_URL))
- standards = [Standard.find_by(name_de: "WCAG 2.2"), Standard.find_by(name_de: "EN 301 549")]
+ qrefdoc = Nokogiri::HTML5(URI.open(WCAG_22_EN_QREF_URL))
+ quick_criteria = qrefdoc.css(".guidelines section:has(h4)").each_with_object({}) do |node, h|
+ h[node.css("h4 strong").first.content] = {
+ quick_criterion_en: node.css(".sc-content .sc-text p").first.content,
+ link_url: node.css(".understanding a").first.attribute("href").value,
+ perm_url: "#{WCAG_22_EN_QREF_URL}##{node.css("article").first.attribute("id").value}"
+ }
+ rescue
+ debugger
+ end
+ link_category = LinkCategory.find_by(name: "Verstehen")
+ qr_category = LinkCategory.find_by(name: "WCAG Quick Reference")
+ # debugger
+ # raise ActiveRecord::Rollback
+
+ standards = [ Standard.find_by(name_de: "WCAG 2.2"), Standard.find_by(name_de: "EN 301 549") ]
doc.css("section.principle").each do |principle_node|
_principle_id = principle_node.attributes["id"].value
principle_title = principle_node.css("h2").first.content.scan(/([a-zA-Z]+)/)
- principle = Principle.find_by!(name_en: principle_title)
+ principle = Principle.find_or_create_by!(name_en: principle_title)
+
principle_node.css("section.guideline").each do |guideline_node|
+ next unless guideline_node.css("h3").first
+
+ puts guideline_node.css("h3").first&.content
+ puts guideline_node.css_path
+
+ g_title = guideline_node.css("h3")
+ .first
+ .content
+ .scan(/Guideline \d+\.\d+ (.*)/)
+ .first
+ .first
+ g_number = guideline_node.css("h3 bdi")
+ .first
+ .content
+ .scan(/\d+\.(\d+)/)
+ .first
+ .first
+ g_text = guideline_node.css("> p").first.content
+
+ guideline = Guideline.find_or_create_by(principle: principle, number: g_number, name_en: g_title)
+ guideline.update(description_en: g_text, description_de: translate(g_text), name_de: translate(g_title)) if guideline.description_de.blank?
+
guideline_node.css("section.guideline").each do |sc|
+ puts sc.css_path
+ puts sc.css("h4 bdi")
sc_number, sc_title = sc.css("h4")
.first
.content
- .scan(/Success Criterion (\d+\.\d+\.\d+) (.*)/)
+ .scan(/Success Criterion \d+\.\d+\.(\d+) (.*)/)
.first
sc_level = sc.css("p.conformance-level").first&.content&.scan(/\(Level (A+)\)/)&.first&.last
sc_url = sc.css("a.self-link").first.attr("href")
@@ -23,20 +69,35 @@ def import_wcag22en
.select { _1.class == Nokogiri::XML::Element }
.select { _1.attr("class").nil? || _1.attr("class") == "note" }
.reduce("") { |str, node| str + node.to_s }
-
- check = Check.find_or_initialize_by(external_number: sc_number)
+
+ check = Check.find_or_initialize_by(guideline_id: guideline.id, number: sc_number)
new_standards = Set.new(check.standards)
new_standards += standards
- check.name_de = sc_title
+ check.name_de = translate sc_title if check.name_de.blank?
check.name_en = sc_title
- check.principle = principle
check.standards = new_standards
check.applicable_to_app = check.applicable_to_web = true
- check.external_number = sc_number
check.external_url = "#{WCAG_22_EN_URL}#{sc_url}"
check.conformity_level = sc_level&.to_sym
- check.conformity_notice_de = sc_conformity_notice
- check.criterion_de = "#{full_text}
".gsub('href="#', %(href="#{WCAG_22_EN_URL}#))
+ check.conformity_notice_de = translate sc_conformity_notice
+ check.criterion_de = "#{translate full_text}
".gsub('href="#', %(href="#{WCAG_22_EN_URL}#)) if check.criterion_de.blank?
+ qref_attrs = quick_criteria["#{principle.id}.#{guideline.number}.#{sc_number}"]
+ check.quick_criterion_en = qref_attrs&.dig :quick_criterion_en
+ check.quick_criterion_de = qref_attrs&.dig :quick_criterion_en
+
+ if qref_attrs&.dig(:link_url)
+ link = Link.find_or_create_by(link_category:, url: qref_attrs[:link_url])
+ link.update(text: "#{check.full_number} Verstehen")
+ check.links << link
+ end
+
+ if qref_attrs&.dig(:perm_url)
+ link = Link.find_or_create_by(link_category: qr_category, url: qref_attrs[:perm_url])
+ link.update(text: "#{check.full_number} Quick Reference")
+ check.links << link
+ end
+ # check.criterion_details_en = qref_attrs&.dig :criterion_details_en
+ # check.criterion_details_de = qref_attrs&.dig :criterion_details_en
check.save!
end
end
diff --git a/test/controllers/checks_controller_test.rb b/test/controllers/checks_controller_test.rb
index f66c842..669e480 100644
--- a/test/controllers/checks_controller_test.rb
+++ b/test/controllers/checks_controller_test.rb
@@ -8,7 +8,7 @@ class ChecksControllerTest < ::ControllerTest
end
setup do
- @principle = principles(:one)
+ @guideline = guidelines(:one)
@check = checks(:deletable)
User.create!(email_address: "test@example.com", password: "password")
login("test@example.com", "password")
@@ -27,7 +27,7 @@ class ChecksControllerTest < ::ControllerTest
test "should create check" do
assert_difference("Check.count") do
post checks_url,
- params: { check: { principle_id: @principle.id, number: Check.maximum(:number) + 1, level: @check.level, name_de: @check.name_de, position: @check.position,
+ params: { check: { guideline_id: @guideline.id, number: Check.maximum(:number) + 1, level: @check.level, name_de: @check.name_de, position: @check.position,
criterion_de: @check.criterion_de } }
end
@@ -46,7 +46,7 @@ class ChecksControllerTest < ::ControllerTest
test "should update check" do
patch check_url(@check),
- params: { check: { principle_id: @principle.id, level: @check.level, name_de: @check.t_name, position: @check.position,
+ params: { check: { guideline_id: @guideline.id, level: @check.level, name_de: @check.t_name, position: @check.position,
criterion_de: @check.criterion_de } }
assert_redirected_to check_url(@check)
end
diff --git a/test/controllers/guidelines_controller_test.rb b/test/controllers/guidelines_controller_test.rb
new file mode 100644
index 0000000..cf37063
--- /dev/null
+++ b/test/controllers/guidelines_controller_test.rb
@@ -0,0 +1,49 @@
+require "test_helper"
+
+class GuidelinesControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ skip "login"
+ @guideline = guidelines(:one)
+ end
+
+ test "should get index" do
+ get guidelines_url
+ assert_response :success
+ end
+
+ test "should get new" do
+ get new_guideline_url
+ assert_response :success
+ end
+
+ test "should create guideline" do
+ assert_difference("Guideline.count") do
+ post guidelines_url, params: { guideline: { name_de: @guideline.name_de, number: @guideline.number, principle_id: @guideline.principle_id } }
+ end
+
+ assert_redirected_to guideline_url(Guideline.last)
+ end
+
+ test "should show guideline" do
+ get guideline_url(@guideline)
+ assert_response :success
+ end
+
+ test "should get edit" do
+ get edit_guideline_url(@guideline)
+ assert_response :success
+ end
+
+ test "should update guideline" do
+ patch guideline_url(@guideline), params: { guideline: { name_de: @guideline.name_de, number: @guideline.number, principle_id: @guideline.principle_id } }
+ assert_redirected_to guideline_url(@guideline)
+ end
+
+ test "should destroy guideline" do
+ assert_difference("Guideline.count", -1) do
+ delete guideline_url(@guideline)
+ end
+
+ assert_redirected_to guidelines_url
+ end
+end
diff --git a/test/fixtures/checks.yml b/test/fixtures/checks.yml
index afadaf9..29d2a96 100644
--- a/test/fixtures/checks.yml
+++ b/test/fixtures/checks.yml
@@ -5,18 +5,18 @@ one:
name_de: MyString
level: 1
number: 1
- principle: one
+ guideline: one
two:
position: MyString
name_de: MyString
level: 1
number: 2
- principle: one
+ guideline: one
deletable:
position: MyString
name_de: MyString
level: 1
number: 3
- principle: one
+ guideline: one
diff --git a/test/fixtures/guidelines.yml b/test/fixtures/guidelines.yml
new file mode 100644
index 0000000..63db8d4
--- /dev/null
+++ b/test/fixtures/guidelines.yml
@@ -0,0 +1,11 @@
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+ principle: one
+ number: 1
+ name_de: MyString
+
+two:
+ principle: two
+ number: 1
+ name_de: MyString
diff --git a/test/models/guideline_test.rb b/test/models/guideline_test.rb
new file mode 100644
index 0000000..eb514f4
--- /dev/null
+++ b/test/models/guideline_test.rb
@@ -0,0 +1,7 @@
+require "test_helper"
+
+class GuidelineTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/system/guidelines_test.rb b/test/system/guidelines_test.rb
new file mode 100644
index 0000000..f108ac9
--- /dev/null
+++ b/test/system/guidelines_test.rb
@@ -0,0 +1,45 @@
+require "application_system_test_case"
+
+class GuidelinesTest < ApplicationSystemTestCase
+ setup do
+ @guideline = guidelines(:one)
+ end
+
+ test "visiting the index" do
+ visit guidelines_url
+ assert_selector "h1", text: "Guidelines"
+ end
+
+ test "should create guideline" do
+ visit guidelines_url
+ click_on "New guideline"
+
+ fill_in "Name de", with: @guideline.name_de
+ fill_in "Number", with: @guideline.number
+ fill_in "Principle", with: @guideline.principle_id
+ click_on "Create Guideline"
+
+ assert_text "Guideline was successfully created"
+ click_on "Back"
+ end
+
+ test "should update Guideline" do
+ visit guideline_url(@guideline)
+ click_on "Edit this guideline", match: :first
+
+ fill_in "Name de", with: @guideline.name_de
+ fill_in "Number", with: @guideline.number
+ fill_in "Principle", with: @guideline.principle_id
+ click_on "Update Guideline"
+
+ assert_text "Guideline was successfully updated"
+ click_on "Back"
+ end
+
+ test "should destroy Guideline" do
+ visit guideline_url(@guideline)
+ click_on "Destroy this guideline", match: :first
+
+ assert_text "Guideline was successfully destroyed"
+ end
+end
diff --git a/tmp/pids/.keep b/tmp/pids/.keep
deleted file mode 100644
index e69de29..0000000