Rails 8 Update #39
67 changed files with 519 additions and 684 deletions
|
|
@ -37,6 +37,7 @@ jobs:
|
||||||
services:
|
services:
|
||||||
chrome:
|
chrome:
|
||||||
image: selenium/standalone-chrome
|
image: selenium/standalone-chrome
|
||||||
|
shm_size: 2g
|
||||||
steps:
|
steps:
|
||||||
- name: Cache repository
|
- name: Cache repository
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
|
|
||||||
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
|
|
@ -4,16 +4,11 @@
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
// {
|
|
||||||
// "type": "rdbg",
|
|
||||||
// "request": "attach",
|
|
||||||
// "name": "Attach to a debuggee"
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
"type": "ruby_lsp",
|
"type": "ruby_lsp",
|
||||||
"name": "Debug server",
|
"name": "Debug server",
|
||||||
"request": "attach",
|
"request": "attach",
|
||||||
"preLaunchTask": "dev"
|
"preLaunchTask": "dev",
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
11
Gemfile
11
Gemfile
|
|
@ -5,14 +5,13 @@ source "https://rubygems.org"
|
||||||
ruby "3.2.5"
|
ruby "3.2.5"
|
||||||
|
|
||||||
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
|
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
|
||||||
gem "rails", "~> 7.2"
|
gem "rails", "~> 8.0"
|
||||||
|
|
||||||
# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
|
gem "propshaft"
|
||||||
gem "sprockets-rails"
|
|
||||||
|
|
||||||
# Use sqlite3 as the database for Active Record
|
# Use sqlite3 as the database for Active Record
|
||||||
# gem "sqlite3", "~> 1.4"
|
# gem "sqlite3", "~> 1.4"
|
||||||
gem "sqlite3", ">= 2.0"
|
gem "sqlite3", ">= 2.1"
|
||||||
|
|
||||||
# Use the Puma web server [https://github.com/puma/puma]
|
# Use the Puma web server [https://github.com/puma/puma]
|
||||||
gem "puma", ">= 5.0"
|
gem "puma", ">= 5.0"
|
||||||
|
|
@ -39,7 +38,7 @@ gem "jbuilder"
|
||||||
# gem "kredis"
|
# gem "kredis"
|
||||||
|
|
||||||
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
|
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
|
||||||
# gem "bcrypt", "~> 3.1.7"
|
gem "bcrypt", "~> 3.1.7"
|
||||||
|
|
||||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||||
gem "tzinfo-data", platforms: %i[windows jruby]
|
gem "tzinfo-data", platforms: %i[windows jruby]
|
||||||
|
|
@ -48,7 +47,6 @@ gem "tzinfo-data", platforms: %i[windows jruby]
|
||||||
gem "bootsnap", require: false
|
gem "bootsnap", require: false
|
||||||
|
|
||||||
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
|
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
|
||||||
gem "activerecord-enhancedsqlite3-adapter"
|
|
||||||
gem "bootstrap_form"
|
gem "bootstrap_form"
|
||||||
gem "caxlsx"
|
gem "caxlsx"
|
||||||
gem "caxlsx_rails"
|
gem "caxlsx_rails"
|
||||||
|
|
@ -58,7 +56,6 @@ gem "pagy", "~> 9.0"
|
||||||
gem "pandoc-ruby"
|
gem "pandoc-ruby"
|
||||||
gem "prawn-markup"
|
gem "prawn-markup"
|
||||||
gem "prawn-rails"
|
gem "prawn-rails"
|
||||||
gem "rodauth-rails"
|
|
||||||
gem "sablon"
|
gem "sablon"
|
||||||
gem "slim"
|
gem "slim"
|
||||||
|
|
||||||
|
|
|
||||||
177
Gemfile.lock
177
Gemfile.lock
|
|
@ -1,70 +1,67 @@
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (7.2.0)
|
actioncable (8.0.0)
|
||||||
actionpack (= 7.2.0)
|
actionpack (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (7.2.0)
|
actionmailbox (8.0.0)
|
||||||
actionpack (= 7.2.0)
|
actionpack (= 8.0.0)
|
||||||
activejob (= 7.2.0)
|
activejob (= 8.0.0)
|
||||||
activerecord (= 7.2.0)
|
activerecord (= 8.0.0)
|
||||||
activestorage (= 7.2.0)
|
activestorage (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
actionmailer (7.2.0)
|
actionmailer (8.0.0)
|
||||||
actionpack (= 7.2.0)
|
actionpack (= 8.0.0)
|
||||||
actionview (= 7.2.0)
|
actionview (= 8.0.0)
|
||||||
activejob (= 7.2.0)
|
activejob (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (7.2.0)
|
actionpack (8.0.0)
|
||||||
actionview (= 7.2.0)
|
actionview (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
racc
|
rack (>= 2.2.4)
|
||||||
rack (>= 2.2.4, < 3.2)
|
|
||||||
rack-session (>= 1.0.1)
|
rack-session (>= 1.0.1)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
useragent (~> 0.16)
|
useragent (~> 0.16)
|
||||||
actiontext (7.2.0)
|
actiontext (8.0.0)
|
||||||
actionpack (= 7.2.0)
|
actionpack (= 8.0.0)
|
||||||
activerecord (= 7.2.0)
|
activerecord (= 8.0.0)
|
||||||
activestorage (= 7.2.0)
|
activestorage (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (7.2.0)
|
actionview (8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
activejob (7.2.0)
|
activejob (8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (7.2.0)
|
activemodel (8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
activerecord (7.2.0)
|
activerecord (8.0.0)
|
||||||
activemodel (= 7.2.0)
|
activemodel (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activerecord-enhancedsqlite3-adapter (0.8.0)
|
activestorage (8.0.0)
|
||||||
activerecord (>= 7.1)
|
actionpack (= 8.0.0)
|
||||||
sqlite3 (>= 1.6)
|
activejob (= 8.0.0)
|
||||||
activestorage (7.2.0)
|
activerecord (= 8.0.0)
|
||||||
actionpack (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
activejob (= 7.2.0)
|
|
||||||
activerecord (= 7.2.0)
|
|
||||||
activesupport (= 7.2.0)
|
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (7.2.0)
|
activesupport (8.0.0)
|
||||||
base64
|
base64
|
||||||
|
benchmark (>= 0.3)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
connection_pool (>= 2.2.5)
|
connection_pool (>= 2.2.5)
|
||||||
|
|
@ -74,14 +71,13 @@ GEM
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
securerandom (>= 0.3)
|
securerandom (>= 0.3)
|
||||||
tzinfo (~> 2.0, >= 2.0.5)
|
tzinfo (~> 2.0, >= 2.0.5)
|
||||||
|
uri (>= 0.13.1)
|
||||||
addressable (2.8.7)
|
addressable (2.8.7)
|
||||||
public_suffix (>= 2.0.2, < 7.0)
|
public_suffix (>= 2.0.2, < 7.0)
|
||||||
after_commit_everywhere (1.4.0)
|
|
||||||
activerecord (>= 4.2)
|
|
||||||
activesupport
|
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
base64 (0.2.0)
|
base64 (0.2.0)
|
||||||
bcrypt (3.1.20)
|
bcrypt (3.1.20)
|
||||||
|
benchmark (0.4.0)
|
||||||
bigdecimal (3.1.8)
|
bigdecimal (3.1.8)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootsnap (1.18.3)
|
bootsnap (1.18.3)
|
||||||
|
|
@ -114,7 +110,7 @@ GEM
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
cssbundling-rails (1.4.0)
|
cssbundling-rails (1.4.0)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
date (3.3.4)
|
date (3.4.0)
|
||||||
debug (1.9.2)
|
debug (1.9.2)
|
||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
|
|
@ -163,7 +159,7 @@ GEM
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
minitest (5.24.1)
|
minitest (5.24.1)
|
||||||
msgpack (1.7.2)
|
msgpack (1.7.2)
|
||||||
net-imap (0.4.14)
|
net-imap (0.5.0)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
|
|
@ -220,6 +216,11 @@ GEM
|
||||||
prawn-table (0.2.2)
|
prawn-table (0.2.2)
|
||||||
prawn (>= 1.3.0, < 3.0.0)
|
prawn (>= 1.3.0, < 3.0.0)
|
||||||
prism (1.2.0)
|
prism (1.2.0)
|
||||||
|
propshaft (1.1.0)
|
||||||
|
actionpack (>= 7.0.0)
|
||||||
|
activesupport (>= 7.0.0)
|
||||||
|
rack
|
||||||
|
railties (>= 7.0.0)
|
||||||
psych (5.1.2)
|
psych (5.1.2)
|
||||||
stringio
|
stringio
|
||||||
public_suffix (6.0.0)
|
public_suffix (6.0.0)
|
||||||
|
|
@ -234,20 +235,20 @@ GEM
|
||||||
rackup (2.1.0)
|
rackup (2.1.0)
|
||||||
rack (>= 3)
|
rack (>= 3)
|
||||||
webrick (~> 1.8)
|
webrick (~> 1.8)
|
||||||
rails (7.2.0)
|
rails (8.0.0)
|
||||||
actioncable (= 7.2.0)
|
actioncable (= 8.0.0)
|
||||||
actionmailbox (= 7.2.0)
|
actionmailbox (= 8.0.0)
|
||||||
actionmailer (= 7.2.0)
|
actionmailer (= 8.0.0)
|
||||||
actionpack (= 7.2.0)
|
actionpack (= 8.0.0)
|
||||||
actiontext (= 7.2.0)
|
actiontext (= 8.0.0)
|
||||||
actionview (= 7.2.0)
|
actionview (= 8.0.0)
|
||||||
activejob (= 7.2.0)
|
activejob (= 8.0.0)
|
||||||
activemodel (= 7.2.0)
|
activemodel (= 8.0.0)
|
||||||
activerecord (= 7.2.0)
|
activerecord (= 8.0.0)
|
||||||
activestorage (= 7.2.0)
|
activestorage (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 7.2.0)
|
railties (= 8.0.0)
|
||||||
rails-dom-testing (2.2.0)
|
rails-dom-testing (2.2.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
minitest
|
minitest
|
||||||
|
|
@ -255,9 +256,9 @@ GEM
|
||||||
rails-html-sanitizer (1.6.0)
|
rails-html-sanitizer (1.6.0)
|
||||||
loofah (~> 2.21)
|
loofah (~> 2.21)
|
||||||
nokogiri (~> 1.14)
|
nokogiri (~> 1.14)
|
||||||
railties (7.2.0)
|
railties (8.0.0)
|
||||||
actionpack (= 7.2.0)
|
actionpack (= 8.0.0)
|
||||||
activesupport (= 7.2.0)
|
activesupport (= 8.0.0)
|
||||||
irb (~> 1.13)
|
irb (~> 1.13)
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
|
|
@ -274,21 +275,6 @@ GEM
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
rexml (3.3.2)
|
rexml (3.3.2)
|
||||||
strscan
|
strscan
|
||||||
roda (3.84.0)
|
|
||||||
rack
|
|
||||||
rodauth (2.36.0)
|
|
||||||
roda (>= 2.6.0)
|
|
||||||
sequel (>= 4)
|
|
||||||
rodauth-model (0.2.1)
|
|
||||||
rodauth (~> 2.0)
|
|
||||||
rodauth-rails (1.15.0)
|
|
||||||
bcrypt
|
|
||||||
railties (>= 5.0, < 8)
|
|
||||||
roda (~> 3.76)
|
|
||||||
rodauth (~> 2.36)
|
|
||||||
rodauth-model (~> 0.2)
|
|
||||||
sequel-activerecord_connection (~> 1.1)
|
|
||||||
tilt
|
|
||||||
rubocop (1.65.0)
|
rubocop (1.65.0)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (>= 3.17.0)
|
language_server-protocol (>= 3.17.0)
|
||||||
|
|
@ -341,29 +327,16 @@ GEM
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
rubyzip (>= 1.2.2, < 3.0)
|
rubyzip (>= 1.2.2, < 3.0)
|
||||||
websocket (~> 1.0)
|
websocket (~> 1.0)
|
||||||
sequel (5.84.0)
|
|
||||||
bigdecimal
|
|
||||||
sequel-activerecord_connection (1.4.1)
|
|
||||||
activerecord (>= 5.0, < 8)
|
|
||||||
after_commit_everywhere (~> 1.1)
|
|
||||||
sequel (~> 5.38)
|
|
||||||
slim (5.2.1)
|
slim (5.2.1)
|
||||||
temple (~> 0.10.0)
|
temple (~> 0.10.0)
|
||||||
tilt (>= 2.1.0)
|
tilt (>= 2.1.0)
|
||||||
sorbet-runtime (0.5.11625)
|
sorbet-runtime (0.5.11625)
|
||||||
sprockets (4.2.1)
|
sqlite3 (2.2.0-aarch64-linux-gnu)
|
||||||
concurrent-ruby (~> 1.0)
|
sqlite3 (2.2.0-arm-linux-gnu)
|
||||||
rack (>= 2.2.4, < 4)
|
sqlite3 (2.2.0-arm64-darwin)
|
||||||
sprockets-rails (3.5.1)
|
sqlite3 (2.2.0-x86-linux-gnu)
|
||||||
actionpack (>= 6.1)
|
sqlite3 (2.2.0-x86_64-darwin)
|
||||||
activesupport (>= 6.1)
|
sqlite3 (2.2.0-x86_64-linux-gnu)
|
||||||
sprockets (>= 3.0.0)
|
|
||||||
sqlite3 (2.0.3-aarch64-linux-gnu)
|
|
||||||
sqlite3 (2.0.3-arm-linux-gnu)
|
|
||||||
sqlite3 (2.0.3-arm64-darwin)
|
|
||||||
sqlite3 (2.0.3-x86-linux-gnu)
|
|
||||||
sqlite3 (2.0.3-x86_64-darwin)
|
|
||||||
sqlite3 (2.0.3-x86_64-linux-gnu)
|
|
||||||
stimulus-rails (1.3.3)
|
stimulus-rails (1.3.3)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
stringio (3.1.1)
|
stringio (3.1.1)
|
||||||
|
|
@ -381,6 +354,7 @@ GEM
|
||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
unicode-display_width (2.5.0)
|
unicode-display_width (2.5.0)
|
||||||
|
uri (1.0.1)
|
||||||
useragent (0.16.10)
|
useragent (0.16.10)
|
||||||
web-console (4.2.1)
|
web-console (4.2.1)
|
||||||
actionview (>= 6.0.0)
|
actionview (>= 6.0.0)
|
||||||
|
|
@ -405,7 +379,7 @@ PLATFORMS
|
||||||
x86_64-linux
|
x86_64-linux
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
activerecord-enhancedsqlite3-adapter
|
bcrypt (~> 3.1.7)
|
||||||
bootsnap
|
bootsnap
|
||||||
bootstrap_form
|
bootstrap_form
|
||||||
brakeman
|
brakeman
|
||||||
|
|
@ -423,9 +397,9 @@ DEPENDENCIES
|
||||||
pandoc-ruby
|
pandoc-ruby
|
||||||
prawn-markup
|
prawn-markup
|
||||||
prawn-rails
|
prawn-rails
|
||||||
|
propshaft
|
||||||
puma (>= 5.0)
|
puma (>= 5.0)
|
||||||
rails (~> 7.2)
|
rails (~> 8.0)
|
||||||
rodauth-rails
|
|
||||||
rubocop
|
rubocop
|
||||||
rubocop-capybara
|
rubocop-capybara
|
||||||
rubocop-rails
|
rubocop-rails
|
||||||
|
|
@ -435,8 +409,7 @@ DEPENDENCIES
|
||||||
sablon
|
sablon
|
||||||
selenium-webdriver
|
selenium-webdriver
|
||||||
slim
|
slim
|
||||||
sprockets-rails
|
sqlite3 (>= 2.1)
|
||||||
sqlite3 (>= 2.0)
|
|
||||||
stimulus-rails
|
stimulus-rails
|
||||||
turbo-rails
|
turbo-rails
|
||||||
tzinfo-data
|
tzinfo-data
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
//= link_tree ../images
|
|
||||||
//= link_tree ../builds
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
$font-family-sans-serif:
|
|
||||||
Lexend,
|
$font-family-sans-serif: Lexend,
|
||||||
// Cross-platform generic font family (default user interface font)
|
// Cross-platform generic font family (default user interface font)
|
||||||
system-ui,
|
system-ui,
|
||||||
// Safari for macOS and iOS (San Francisco)
|
// Safari for macOS and iOS (San Francisco)
|
||||||
|
|
@ -29,6 +29,13 @@ $enable-rounded: false;
|
||||||
@import 'bootstrap/scss/bootstrap';
|
@import 'bootstrap/scss/bootstrap';
|
||||||
@import 'bootstrap-icons/font/bootstrap-icons';
|
@import 'bootstrap-icons/font/bootstrap-icons';
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-display: block;
|
||||||
|
font-family: "bootstrap-icons";
|
||||||
|
src: url("./bootstrap-icons.woff2") format("woff2"),
|
||||||
|
url("./bootstrap-icons.woff") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
.rails-bootstrap-forms-date-select select,
|
.rails-bootstrap-forms-date-select select,
|
||||||
.rails-bootstrap-forms-time-select select,
|
.rails-bootstrap-forms-time-select select,
|
||||||
.rails-bootstrap-forms-datetime-select select {
|
.rails-bootstrap-forms-datetime-select select {
|
||||||
|
|
@ -64,7 +71,8 @@ $enable-rounded: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trix-content .attachment-gallery.attachment-gallery--2>action-text-attachment,
|
.trix-content .attachment-gallery.attachment-gallery--2>action-text-attachment,
|
||||||
.trix-content .attachment-gallery.attachment-gallery--2 > .attachment, .trix-content .attachment-gallery.attachment-gallery--4 > action-text-attachment,
|
.trix-content .attachment-gallery.attachment-gallery--2>.attachment,
|
||||||
|
.trix-content .attachment-gallery.attachment-gallery--4>action-text-attachment,
|
||||||
.trix-content .attachment-gallery.attachment-gallery--4>.attachment {
|
.trix-content .attachment-gallery.attachment-gallery--4>.attachment {
|
||||||
flex-basis: 50%;
|
flex-basis: 50%;
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
|
|
@ -98,6 +106,7 @@ $enable-rounded: false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end fix trix dark mode */
|
/* end fix trix dark mode */
|
||||||
|
|
||||||
.trix-content {
|
.trix-content {
|
||||||
|
|
@ -107,9 +116,11 @@ $enable-rounded: false;
|
||||||
border: var(--bs-border-width) solid var(--bs-border-color) !important;
|
border: var(--bs-border-width) solid var(--bs-border-color) !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0.6rem;
|
margin-bottom: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
p:last-child {
|
p:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -145,6 +156,7 @@ trix-toolbar .trix-input--dialog {
|
||||||
trix-toolbar .trix-dialog--link {
|
trix-toolbar .trix-dialog--link {
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* trix-editor.trix-content {
|
/* trix-editor.trix-content {
|
||||||
min-height: 350px;
|
min-height: 350px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module ApplicationCable
|
module ApplicationCable
|
||||||
class Connection < ActionCable::Connection::Base
|
class Connection < ActionCable::Connection::Base
|
||||||
|
identified_by :current_user
|
||||||
|
|
||||||
|
def connect
|
||||||
|
set_current_user || reject_unauthorized_connection
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def set_current_user
|
||||||
|
if session = Session.find_by(id: cookies.signed[:session_id])
|
||||||
|
self.current_user = session.user
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
|
include Authentication
|
||||||
include Pagy::Backend
|
include Pagy::Backend
|
||||||
|
|
||||||
# allow_browser versions: :modern
|
# allow_browser versions: :modern
|
||||||
|
|
@ -13,15 +14,29 @@ class ApplicationController < ActionController::Base
|
||||||
def initialize_navbar
|
def initialize_navbar
|
||||||
return unless request.get?
|
return unless request.get?
|
||||||
|
|
||||||
@navbar_items = if rodauth.logged_in?
|
@navbar_items = if authenticated?
|
||||||
[
|
[
|
||||||
{ label: "Dashboard", icon: :speedometer2, path: :root },
|
{
|
||||||
{ label: Report.model_name.human(count: 2), icon: :'journal-text', path: :reports },
|
label: "Dashboard",
|
||||||
{ label: I18n.t("backoffice"), icon: :gear, path: :backoffice, active: %w[backoffice checklists checks links link_categories].include?(controller_name) },
|
icon: :speedometer2,
|
||||||
{ label: Account.model_name.human, icon: :person, path: profile_path }
|
path: :root
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: Report.model_name.human(count: 2),
|
||||||
|
icon: :'journal-text',
|
||||||
|
path: :reports },
|
||||||
|
{
|
||||||
|
label: I18n.t("backoffice"),
|
||||||
|
icon: :gear,
|
||||||
|
path: :backoffice,
|
||||||
|
active: %w[backoffice checklists checks links link_categories].include?(controller_name) },
|
||||||
|
{
|
||||||
|
label: "Konto",
|
||||||
|
path: profile_path
|
||||||
|
}
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
[ { label: "Login", icon: :'door-closed', path: rodauth.login_path, label_class: "text-info" } ]
|
[ { label: "Login", icon: :'door-closed', path: new_session_path, label_class: "text-info" } ]
|
||||||
end
|
end
|
||||||
@nav_path = controller_name
|
@nav_path = controller_name
|
||||||
@search_url = nil
|
@search_url = nil
|
||||||
|
|
|
||||||
55
app/controllers/concerns/authentication.rb
Normal file
55
app/controllers/concerns/authentication.rb
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
module Authentication
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
before_action :require_authentication
|
||||||
|
helper_method :authenticated?
|
||||||
|
end
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def allow_unauthenticated_access(**options)
|
||||||
|
skip_before_action :require_authentication, **options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def authenticated?
|
||||||
|
resume_session
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_authentication
|
||||||
|
resume_session || request_authentication
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def resume_session
|
||||||
|
Current.session ||= find_session_by_cookie
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_session_by_cookie
|
||||||
|
Session.find_by(id: cookies.signed[:session_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def request_authentication
|
||||||
|
session[:return_to_after_authenticating] = request.url
|
||||||
|
redirect_to new_session_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_authentication_url
|
||||||
|
session.delete(:return_to_after_authenticating) || root_url
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def start_new_session_for(user)
|
||||||
|
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
|
||||||
|
Current.session = session
|
||||||
|
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def terminate_session
|
||||||
|
Current.session.destroy
|
||||||
|
cookies.delete(:session_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,10 +1,36 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class HomeController < ApplicationController
|
class HomeController < ApplicationController
|
||||||
|
allow_unauthenticated_access only: [ :show ]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
if rodauth.logged_in?
|
end
|
||||||
else
|
|
||||||
render :root
|
def profile
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def initialize_sidebar_items
|
||||||
|
return [] unless action_name == "profile"
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
label: "Profil",
|
||||||
|
icon: :person,
|
||||||
|
path: profile_path,
|
||||||
|
active: action_name == "profile"
|
||||||
|
},
|
||||||
|
# {
|
||||||
|
# label: "Passwort ändern",
|
||||||
|
# path: new_password_path,
|
||||||
|
# icon: :lock
|
||||||
|
# },
|
||||||
|
{
|
||||||
|
label: "Logout",
|
||||||
|
icon: :"box-arrow-right",
|
||||||
|
path: session_path,
|
||||||
|
method: :delete
|
||||||
|
}
|
||||||
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
33
app/controllers/passwords_controller.rb
Normal file
33
app/controllers/passwords_controller.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
class PasswordsController < ApplicationController
|
||||||
|
allow_unauthenticated_access
|
||||||
|
before_action :set_user_by_token, only: %i[ edit update ]
|
||||||
|
|
||||||
|
def new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
if user = User.find_by(email_address: params[:email_address])
|
||||||
|
PasswordsMailer.reset(user).deliver_later
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to new_session_path, notice: "Password reset instructions sent (if user with that email address exists)."
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if @user.update(params.permit(:password, :password_confirmation))
|
||||||
|
redirect_to new_session_path, notice: "Password has been reset."
|
||||||
|
else
|
||||||
|
redirect_to edit_password_path(params[:token]), alert: "Passwords did not match."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def set_user_by_token
|
||||||
|
@user = User.find_by_password_reset_token!(params[:token])
|
||||||
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||||
|
redirect_to new_password_path, alert: "Password reset link is invalid or has expired."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
class RodauthController < ApplicationController
|
|
||||||
# Used by Rodauth for rendering views, CSRF protection, running any
|
|
||||||
# registered action callbacks and rescue handlers, instrumentation etc.
|
|
||||||
|
|
||||||
# Controller callbacks and rescue handlers will run around Rodauth endpoints.
|
|
||||||
# before_action :verify_captcha, only: :login, if: -> { request.post? }
|
|
||||||
# rescue_from("SomeError") { |exception| ... }
|
|
||||||
|
|
||||||
# Layout can be changed for all Rodauth pages or only certain pages.
|
|
||||||
# layout "authentication"
|
|
||||||
# layout -> do
|
|
||||||
# case rodauth.current_route
|
|
||||||
# when :login, :create_account, :verify_account, :verify_account_resend,
|
|
||||||
# :reset_password, :reset_password_request
|
|
||||||
# "authentication"
|
|
||||||
# else
|
|
||||||
# "application"
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
before_action do
|
|
||||||
# Fix encoding in rodauth views.
|
|
||||||
response.headers["Content-Type"] = "text/html; charset=utf-8" if request.format.html?
|
|
||||||
end
|
|
||||||
|
|
||||||
def profile
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def initialize_sidebar_items
|
|
||||||
return unless rodauth.logged_in?
|
|
||||||
|
|
||||||
[
|
|
||||||
{ label: "Profile", icon: :'person', path: profile_path, active: action_name == "profile" },
|
|
||||||
{ label: "Passwort ändern", icon: :'lock', path: rodauth.change_password_path, active: action_name == "change_password" },
|
|
||||||
{ label: "Logout", icon: :'box-arrow-right', path: rodauth.logout_path, active: action_name == "logout" }
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
24
app/controllers/sessions_controller.rb
Normal file
24
app/controllers/sessions_controller.rb
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
class SessionsController < ApplicationController
|
||||||
|
allow_unauthenticated_access only: %i[ new create ]
|
||||||
|
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." }
|
||||||
|
|
||||||
|
def new
|
||||||
|
redirect_to :root if authenticated?
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
redirect_to :root if authenticated?
|
||||||
|
|
||||||
|
if user = User.authenticate_by(params.permit(:email_address, :password))
|
||||||
|
start_new_session_for user
|
||||||
|
redirect_to after_authentication_url
|
||||||
|
else
|
||||||
|
redirect_to new_session_path, alert: "Try another email address or password."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
terminate_session
|
||||||
|
redirect_to new_session_path
|
||||||
|
end
|
||||||
|
end
|
||||||
6
app/mailers/passwords_mailer.rb
Normal file
6
app/mailers/passwords_mailer.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
class PasswordsMailer < ApplicationMailer
|
||||||
|
def reset(user)
|
||||||
|
@user = user
|
||||||
|
mail subject: "Reset your password", to: user.email_address
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
class RodauthApp < Rodauth::Rails::App
|
|
||||||
# primary configuration
|
|
||||||
configure RodauthMain
|
|
||||||
|
|
||||||
# secondary configuration
|
|
||||||
# configure RodauthAdmin, :admin
|
|
||||||
|
|
||||||
route do |r|
|
|
||||||
rodauth.load_memory # autologin remembered users
|
|
||||||
|
|
||||||
r.rodauth # route rodauth requests
|
|
||||||
|
|
||||||
# ==> Authenticating requests
|
|
||||||
# Call `rodauth.require_account` for requests that you want to
|
|
||||||
# require authentication for. For example:
|
|
||||||
#
|
|
||||||
# # authenticate /dashboard/* and /account/* requests
|
|
||||||
# if r.path.start_with?("/dashboard") || r.path.start_with?("/account")
|
|
||||||
# rodauth.require_account
|
|
||||||
# end
|
|
||||||
|
|
||||||
# ==> Secondary configurations
|
|
||||||
# r.rodauth(:admin) # route admin rodauth requests
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
require "sequel/core"
|
|
||||||
|
|
||||||
class RodauthMain < Rodauth::Rails::Auth
|
|
||||||
configure do
|
|
||||||
# List of authentication features that are loaded.
|
|
||||||
# enable :create_account, :verify_account, :verify_account_grace_period,
|
|
||||||
# :login, :logout, :remember,
|
|
||||||
# :reset_password, :change_password, :change_login, :verify_login_change,
|
|
||||||
# :close_account
|
|
||||||
enable :login, :logout, :remember, :change_password
|
|
||||||
|
|
||||||
# See the Rodauth documentation for the list of available config options:
|
|
||||||
# http://rodauth.jeremyevans.net/documentation.html
|
|
||||||
|
|
||||||
# ==> General
|
|
||||||
# Initialize Sequel and have it reuse Active Record's database connection.
|
|
||||||
db Sequel.sqlite(extensions: :activerecord_connection, keep_reference: false)
|
|
||||||
# Avoid DB query that checks accounts table schema at boot time.
|
|
||||||
convert_token_id_to_integer? { Account.columns_hash["id"].type == :integer }
|
|
||||||
|
|
||||||
# Change prefix of table and foreign key column names from default "account"
|
|
||||||
# accounts_table :users
|
|
||||||
# verify_account_table :user_verification_keys
|
|
||||||
# verify_login_change_table :user_login_change_keys
|
|
||||||
# reset_password_table :user_password_reset_keys
|
|
||||||
# remember_table :user_remember_keys
|
|
||||||
|
|
||||||
# The secret key used for hashing public-facing tokens for various features.
|
|
||||||
# Defaults to Rails `secret_key_base`, but you can use your own secret key.
|
|
||||||
# hmac_secret "9180872c271f678dc279aabf6610187b7a11f2d23054ce38ebc66980971e993a25f5613ba255956c9ee7bc4afe724eef16abc411a6e2a8642d53b85531685de1"
|
|
||||||
|
|
||||||
# Use path prefix for all routes.
|
|
||||||
# prefix "/auth"
|
|
||||||
|
|
||||||
# Specify the controller used for view rendering, CSRF, and callbacks.
|
|
||||||
rails_controller { RodauthController }
|
|
||||||
|
|
||||||
# Make built-in page titles accessible in your views via an instance variable.
|
|
||||||
title_instance_variable :@page_title
|
|
||||||
|
|
||||||
# Store account status in an integer column without foreign key constraint.
|
|
||||||
account_status_column :status
|
|
||||||
|
|
||||||
# Store password hash in a column instead of a separate table.
|
|
||||||
account_password_hash_column :password_hash
|
|
||||||
|
|
||||||
# Set password when creating account instead of when verifying.
|
|
||||||
# verify_account_set_password? false
|
|
||||||
|
|
||||||
# Change some default param keys.
|
|
||||||
login_param "email"
|
|
||||||
login_confirm_param "email-confirm"
|
|
||||||
# password_confirm_param "confirm_password"
|
|
||||||
|
|
||||||
# Redirect back to originally requested location after authentication.
|
|
||||||
# login_return_to_requested_location? true
|
|
||||||
# two_factor_auth_return_to_requested_location? true # if using MFA
|
|
||||||
|
|
||||||
# Autologin the user after they have reset their password.
|
|
||||||
# reset_password_autologin? true
|
|
||||||
|
|
||||||
# Delete the account record when the user has closed their account.
|
|
||||||
# delete_account_on_close? true
|
|
||||||
|
|
||||||
# Redirect to the app from login and registration pages if already logged in.
|
|
||||||
# already_logged_in { redirect login_redirect }
|
|
||||||
|
|
||||||
# ==> Emails
|
|
||||||
send_email do |email|
|
|
||||||
# queue email delivery on the mailer after the transaction commits
|
|
||||||
db.after_commit { email.deliver_later }
|
|
||||||
end
|
|
||||||
|
|
||||||
# ==> Flash
|
|
||||||
# Match flash keys with ones already used in the Rails app.
|
|
||||||
# flash_notice_key :success # default is :notice
|
|
||||||
# flash_error_key :error # default is :alert
|
|
||||||
|
|
||||||
# Override default flash messages.
|
|
||||||
# create_account_notice_flash "Your account has been created. Please verify your account by visiting the confirmation link sent to your email address."
|
|
||||||
# require_login_error_flash "Login is required for accessing this page"
|
|
||||||
# login_notice_flash nil
|
|
||||||
|
|
||||||
# ==> Validation
|
|
||||||
# Override default validation error messages.
|
|
||||||
# no_matching_login_message "user with this email address doesn't exist"
|
|
||||||
# already_an_account_with_this_login_message "user with this email address already exists"
|
|
||||||
# password_too_short_message { "needs to have at least #{password_minimum_length} characters" }
|
|
||||||
# login_does_not_meet_requirements_message { "invalid email#{", #{login_requirement_message}" if login_requirement_message}" }
|
|
||||||
|
|
||||||
# Passwords shorter than 8 characters are considered weak according to OWASP.
|
|
||||||
password_minimum_length 8
|
|
||||||
# bcrypt has a maximum input length of 72 bytes, truncating any extra bytes.
|
|
||||||
password_maximum_bytes 72
|
|
||||||
|
|
||||||
# Custom password complexity requirements (alternative to password_complexity feature).
|
|
||||||
# password_meets_requirements? do |password|
|
|
||||||
# super(password) && password_complex_enough?(password)
|
|
||||||
# end
|
|
||||||
# auth_class_eval do
|
|
||||||
# def password_complex_enough?(password)
|
|
||||||
# return true if password.match?(/\d/) && password.match?(/[^a-zA-Z\d]/)
|
|
||||||
# set_password_requirement_error_message(:password_simple, "requires one number and one special character")
|
|
||||||
# false
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# ==> Remember Feature
|
|
||||||
# Remember all logged in users.
|
|
||||||
after_login { remember_login }
|
|
||||||
|
|
||||||
# Or only remember users that have ticked a "Remember Me" checkbox on login.
|
|
||||||
# after_login { remember_login if param_or_nil("remember") }
|
|
||||||
|
|
||||||
# Extend user's remember period when remembered via a cookie
|
|
||||||
extend_remember_deadline? true
|
|
||||||
|
|
||||||
# ==> Hooks
|
|
||||||
# Validate custom fields in the create account form.
|
|
||||||
# before_create_account do
|
|
||||||
# throw_error_status(422, "name", "must be present") if param("name").empty?
|
|
||||||
# end
|
|
||||||
|
|
||||||
# Perform additional actions after the account is created.
|
|
||||||
# after_create_account do
|
|
||||||
# Profile.create!(account_id: account_id, name: param("name"))
|
|
||||||
# end
|
|
||||||
|
|
||||||
# Do additional cleanup after the account is closed.
|
|
||||||
# after_close_account do
|
|
||||||
# Profile.find_by!(account_id: account_id).destroy
|
|
||||||
# end
|
|
||||||
|
|
||||||
# ==> Redirects
|
|
||||||
# Redirect to home page after logout.
|
|
||||||
logout_redirect "/"
|
|
||||||
|
|
||||||
# Redirect to wherever login redirects to after account verification.
|
|
||||||
# verify_account_redirect { login_redirect }
|
|
||||||
|
|
||||||
# Redirect to login page after password reset.
|
|
||||||
# reset_password_redirect { login_path }
|
|
||||||
|
|
||||||
# Ensure requiring login follows login route changes.
|
|
||||||
require_login_redirect { login_path }
|
|
||||||
|
|
||||||
# ==> Deadlines
|
|
||||||
# Change default deadlines for some actions.
|
|
||||||
# verify_account_grace_period 3.days.to_i
|
|
||||||
# reset_password_deadline_interval Hash[hours: 6]
|
|
||||||
# verify_login_change_deadline_interval Hash[days: 2]
|
|
||||||
# remember_deadline_interval Hash[days: 30]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
class Account < ApplicationRecord
|
|
||||||
include Rodauth::Rails.model
|
|
||||||
|
|
||||||
enum :status, unverified: 1, verified: 2, closed: 3
|
|
||||||
end
|
|
||||||
4
app/models/current.rb
Normal file
4
app/models/current.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
class Current < ActiveSupport::CurrentAttributes
|
||||||
|
attribute :session
|
||||||
|
delegate :user, to: :session, allow_nil: true
|
||||||
|
end
|
||||||
3
app/models/session.rb
Normal file
3
app/models/session.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
class Session < ApplicationRecord
|
||||||
|
belongs_to :user
|
||||||
|
end
|
||||||
6
app/models/user.rb
Normal file
6
app/models/user.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
class User < ApplicationRecord
|
||||||
|
has_secure_password
|
||||||
|
has_many :sessions, dependent: :destroy
|
||||||
|
|
||||||
|
normalizes :email_address, with: ->(e) { e.strip.downcase }
|
||||||
|
end
|
||||||
2
app/views/home/profile.html.slim
Normal file
2
app/views/home/profile.html.slim
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pre
|
||||||
|
== JSON.pretty_generate(Current.session.attributes.merge(user: Current.session.user.attributes))
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<% if @sidebar_items %>
|
<% if @sidebar_items %>
|
||||||
<% @sidebar_items.each do |sidebar_item| %>
|
<% @sidebar_items.each do |sidebar_item| %>
|
||||||
<% if sidebar_item[:method].present? && sidebar_item[:method] != :get %>
|
<% if sidebar_item[:method].present? && sidebar_item[:method] != :get %>
|
||||||
<%= button_to(sidebar_item[:path], method: sidebar_item[:method], class: "list-group-item border-end-0 d-inline-block text-truncate") do %>
|
<%= button_to(sidebar_item[:path], method: sidebar_item[:method], class: "list-group-item border-0 d-inline-block text-truncate") do %>
|
||||||
<% if sidebar_item[:icon] %>
|
<% if sidebar_item[:icon] %>
|
||||||
<span aria-hidden="true" class="bi-<%= sidebar_item[:icon] %>"></span>
|
<span aria-hidden="true" class="bi-<%= sidebar_item[:icon] %>"></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
9
app/views/passwords/edit.html.erb
Normal file
9
app/views/passwords/edit.html.erb
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<h1>Update your password</h1>
|
||||||
|
|
||||||
|
<%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %>
|
||||||
|
|
||||||
|
<%= form_with url: password_path(params[:token]), method: :put do |form| %>
|
||||||
|
<%= form.password_field :password, required: true, autocomplete: "new-password", placeholder: "Enter new password", maxlength: 72 %><br>
|
||||||
|
<%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", placeholder: "Repeat new password", maxlength: 72 %><br>
|
||||||
|
<%= form.submit "Save" %>
|
||||||
|
<% end %>
|
||||||
8
app/views/passwords/new.html.erb
Normal file
8
app/views/passwords/new.html.erb
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<h1>Forgot your password?</h1>
|
||||||
|
|
||||||
|
<%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %>
|
||||||
|
|
||||||
|
<%= form_with url: passwords_path do |form| %>
|
||||||
|
<%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address] %><br>
|
||||||
|
<%= form.submit "Email reset instructions" %>
|
||||||
|
<% end %>
|
||||||
4
app/views/passwords_mailer/reset.html.erb
Normal file
4
app/views/passwords_mailer/reset.html.erb
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<p>
|
||||||
|
You can reset your password within the next 15 minutes on
|
||||||
|
<%= link_to "this password reset page", edit_password_url(@user.password_reset_token) %>.
|
||||||
|
</p>
|
||||||
2
app/views/passwords_mailer/reset.text.erb
Normal file
2
app/views/passwords_mailer/reset.text.erb
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
You can reset your password within the next 15 minutes on this password reset page:
|
||||||
|
<%= edit_password_url(@user.password_reset_token) %>
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<%= form_with url: rodauth.login_path, method: :post, data: { turbo: false } do |form| %>
|
|
||||||
<% if rodauth.skip_login_field_on_login? %>
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.label "login", rodauth.login_label, class: "form-label" %>
|
|
||||||
<%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", readonly: true, class: "form-control-plaintext" %>
|
|
||||||
</div>
|
|
||||||
<% else %>
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.label "login", rodauth.login_label, class: "form-label" %>
|
|
||||||
<%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", autocomplete: rodauth.login_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.login_param)}", aria: ({ invalid: true, describedby: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
|
|
||||||
<%= content_tag(:span, rodauth.field_error(rodauth.login_param), class: "invalid-feedback", id: "login_error_message") if rodauth.field_error(rodauth.login_param) %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% unless rodauth.skip_password_field_on_login? %>
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.label "password", rodauth.password_label, class: "form-label" %>
|
|
||||||
<%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_param)}", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
|
|
||||||
<%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "invalid-feedback", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.submit rodauth.login_button, class: "btn btn-primary" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<% unless rodauth.login_form_footer_links.empty? %>
|
|
||||||
<%== rodauth.login_form_footer_links_heading %>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<% rodauth.login_form_footer_links.sort.each do |_, link, text| %>
|
|
||||||
<li><%= link_to text, link %></li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
<% end %>
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<h1>Passwort ändern</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<%= form_with url: rodauth.change_password_path, method: :post, data: { turbo: false } do |form| %>
|
|
||||||
<% if rodauth.change_password_requires_password? %>
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.label "password", rodauth.password_label, class: "form-label" %>
|
|
||||||
<%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_param)}", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
|
|
||||||
<%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "invalid-feedback", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.label "new-password", rodauth.new_password_label, class: "form-label" %>
|
|
||||||
<%= form.password_field rodauth.new_password_param, value: "", id: "new-password", autocomplete: "new-password", required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.new_password_param)}", aria: ({ invalid: true, describedby: "new-password_error_message" } if rodauth.field_error(rodauth.new_password_param)) %>
|
|
||||||
<%= content_tag(:span, rodauth.field_error(rodauth.new_password_param), class: "invalid-feedback", id: "new-password_error_message") if rodauth.field_error(rodauth.new_password_param) %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<% if rodauth.require_password_confirmation? %>
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.label "password-confirm", rodauth.password_confirm_label, class: "form-label" %>
|
|
||||||
<%= form.password_field rodauth.password_confirm_param, value: "", id: "password-confirm", autocomplete: "new-password", required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_confirm_param)}", aria: ({ invalid: true, describedby: "password-confirm_error_message" } if rodauth.field_error(rodauth.password_confirm_param)) %>
|
|
||||||
<%= content_tag(:span, rodauth.field_error(rodauth.password_confirm_param), class: "invalid-feedback", id: "password-confirm_error_message") if rodauth.field_error(rodauth.password_confirm_param) %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.submit rodauth.change_password_button, class: "btn btn-primary" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<%== rodauth.login_form_header %>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<%= render "login_form" %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<%== rodauth.login_form_footer %>
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<h1>Adieu</h1>
|
|
||||||
<%= form_with url: rodauth.logout_path, method: :post, data: { turbo: false } do |form| %>
|
|
||||||
<% if rodauth.features.include?(:active_sessions) %>
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<div class="form-check">
|
|
||||||
<%= form.check_box rodauth.global_logout_param, id: "global-logout", class: "form-check-input", include_hidden: false %>
|
|
||||||
<%= form.label "global-logout", rodauth.global_logout_label, class: "form-check-label" %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.submit "Log out", class: "btn btn-warning" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<%== rodauth.login_form_header %>
|
|
||||||
<%== rodauth.render_multi_phase_login_forms %>
|
|
||||||
<%== rodauth.login_form_footer %>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<h1><%= current_account.email %></h1>
|
|
||||||
|
|
||||||
<pre><%= JSON.pretty_generate current_account.attributes %></pre>
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<%= form_with url: rodauth.remember_path, method: :post, data: { turbo: false } do |form| %>
|
|
||||||
<fieldset class="form-group mb-3">
|
|
||||||
<div class="form-check">
|
|
||||||
<%= form.radio_button rodauth.remember_param, rodauth.remember_remember_param_value, id: "remember-remember", class: "form-check-input" %>
|
|
||||||
<%= form.label "remember-remember", rodauth.remember_remember_label, class: "form-check-label" %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-check">
|
|
||||||
<%= form.radio_button rodauth.remember_param, rodauth.remember_forget_param_value, id: "remember-forget", class: "form-check-input" %>
|
|
||||||
<%= form.label "remember-forget", rodauth.remember_forget_label, class: "form-check-label" %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-check">
|
|
||||||
<%= form.radio_button rodauth.remember_param, rodauth.remember_disable_param_value, id: "remember-disable", class: "form-check-input" %>
|
|
||||||
<%= form.label "remember-disable", rodauth.remember_disable_label, class: "form-check-label" %>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div class="form-group mb-3">
|
|
||||||
<%= form.submit rodauth.remember_button, class: "btn btn-primary" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
13
app/views/sessions/new.html.slim
Normal file
13
app/views/sessions/new.html.slim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
= tag.div(flash[:alert], style: "color:red") if flash[:alert]
|
||||||
|
= tag.div(flash[:notice], style: "color:green") if flash[:notice]
|
||||||
|
|
||||||
|
h1 Login
|
||||||
|
|
||||||
|
= bootstrap_form_with url: session_path do |form|
|
||||||
|
= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], label: User.human_attribute_name(:email_address)
|
||||||
|
br
|
||||||
|
= form.password_field :password, required: true, autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72, label: User.human_attribute_name(:password)
|
||||||
|
br
|
||||||
|
= form.submit "Login"
|
||||||
|
br
|
||||||
|
= link_to "Forgot password?", new_password_path
|
||||||
2
bin/dev.new
Executable file
2
bin/dev.new
Executable file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
exec "./bin/rails", "server", *ARGV
|
||||||
|
|
@ -5,7 +5,7 @@ Rails.application.config.assets.version = '1.0'
|
||||||
|
|
||||||
# Add additional assets to the asset load path.
|
# Add additional assets to the asset load path.
|
||||||
# Rails.application.config.assets.paths << Emoji.images_path
|
# Rails.application.config.assets.paths << Emoji.images_path
|
||||||
Rails.application.config.assets.paths << Rails.root.join('node_modules/bootstrap-icons/font')
|
# Rails.application.config.assets.paths << Rails.root.join('node_modules/bootstrap-icons/font')
|
||||||
|
|
||||||
# Precompile additional assets.
|
# Precompile additional assets.
|
||||||
# application.js, application.css, and all non-JS/CSS in the app/assets
|
# application.js, application.css, and all non-JS/CSS in the app/assets
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
Rodauth::Rails.configure do |config|
|
|
||||||
config.app = "RodauthApp"
|
|
||||||
end
|
|
||||||
|
|
@ -81,6 +81,9 @@ de-CH:
|
||||||
path: Name
|
path: Name
|
||||||
url: Url
|
url: Url
|
||||||
notes: Notizen
|
notes: Notizen
|
||||||
|
user:
|
||||||
|
email_address: Login
|
||||||
|
password: Passwort
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
one: Konto
|
one: Konto
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
constraints Rodauth::Rails.authenticate do
|
resource :session
|
||||||
|
resources :passwords, param: :token
|
||||||
namespace :admin do
|
namespace :admin do
|
||||||
get "backup", to: "backups#show", as: :backup
|
get "backup", to: "backups#show", as: :backup
|
||||||
end
|
end
|
||||||
|
|
@ -27,9 +28,7 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
get "backoffice/show", as: :backoffice
|
get "backoffice/show", as: :backoffice
|
||||||
|
get "profile" => "home#profile", as: :profile
|
||||||
get "profile", to: "rodauth#profile"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
|
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
|
||||||
# Can be used by load balancers and uptime monitors to verify that the app is live.
|
# Can be used by load balancers and uptime monitors to verify that the app is live.
|
||||||
|
|
|
||||||
11
db/migrate/20241108175901_create_users.rb
Normal file
11
db/migrate/20241108175901_create_users.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
class CreateUsers < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
create_table :users do |t|
|
||||||
|
t.string :email_address, null: false
|
||||||
|
t.string :password_digest, null: false
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
add_index :users, :email_address, unique: true
|
||||||
|
end
|
||||||
|
end
|
||||||
11
db/migrate/20241108175905_create_sessions.rb
Normal file
11
db/migrate/20241108175905_create_sessions.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
class CreateSessions < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
create_table :sessions do |t|
|
||||||
|
t.references :user, null: false, foreign_key: true
|
||||||
|
t.string :ip_address
|
||||||
|
t.string :user_agent
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
17
db/migrate/20241108180654_drop_accounts.rb
Normal file
17
db/migrate/20241108180654_drop_accounts.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
class DropAccounts < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
# Used by the remember me feature
|
||||||
|
drop_table :account_remember_keys, id: false do |t|
|
||||||
|
t.integer :id, primary_key: true
|
||||||
|
t.foreign_key :accounts, column: :id
|
||||||
|
t.string :key, null: false
|
||||||
|
t.datetime :deadline, null: false
|
||||||
|
end
|
||||||
|
drop_table :accounts do |t|
|
||||||
|
t.integer :status, null: false, default: 1
|
||||||
|
t.string :email, null: false
|
||||||
|
t.index :email, unique: true, where: "status IN (1, 2)"
|
||||||
|
t.string :password_hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
33
db/schema.rb
generated
33
db/schema.rb
generated
|
|
@ -10,19 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.2].define(version: 2024_11_01_125547) do
|
ActiveRecord::Schema[8.0].define(version: 2024_11_08_180654) do
|
||||||
create_table "account_remember_keys", force: :cascade do |t|
|
|
||||||
t.string "key", null: false
|
|
||||||
t.datetime "deadline", null: false
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "accounts", force: :cascade do |t|
|
|
||||||
t.integer "status", default: 1, null: false
|
|
||||||
t.string "email", null: false
|
|
||||||
t.string "password_hash"
|
|
||||||
t.index ["email"], name: "index_accounts_on_email", unique: true, where: "status IN (1, 2)"
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "action_text_rich_texts", force: :cascade do |t|
|
create_table "action_text_rich_texts", force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.text "body"
|
t.text "body"
|
||||||
|
|
@ -174,6 +162,15 @@ ActiveRecord::Schema[7.2].define(version: 2024_11_01_125547) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "sessions", force: :cascade do |t|
|
||||||
|
t.integer "user_id", null: false
|
||||||
|
t.string "ip_address"
|
||||||
|
t.string "user_agent"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["user_id"], name: "index_sessions_on_user_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "standards", force: :cascade do |t|
|
create_table "standards", force: :cascade do |t|
|
||||||
t.string "name_de"
|
t.string "name_de"
|
||||||
t.string "name_en"
|
t.string "name_en"
|
||||||
|
|
@ -199,7 +196,14 @@ ActiveRecord::Schema[7.2].define(version: 2024_11_01_125547) do
|
||||||
t.index ["element_id"], name: "index_success_criteria_on_element_id"
|
t.index ["element_id"], name: "index_success_criteria_on_element_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_foreign_key "account_remember_keys", "accounts", column: "id"
|
create_table "users", force: :cascade do |t|
|
||||||
|
t.string "email_address", null: false
|
||||||
|
t.string "password_digest", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["email_address"], name: "index_users_on_email_address", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||||
add_foreign_key "checklist_entries", "checklists"
|
add_foreign_key "checklist_entries", "checklists"
|
||||||
|
|
@ -208,6 +212,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_11_01_125547) do
|
||||||
add_foreign_key "elements", "pages"
|
add_foreign_key "elements", "pages"
|
||||||
add_foreign_key "links", "link_categories"
|
add_foreign_key "links", "link_categories"
|
||||||
add_foreign_key "pages", "reports"
|
add_foreign_key "pages", "reports"
|
||||||
|
add_foreign_key "sessions", "users"
|
||||||
add_foreign_key "success_criteria", "checks"
|
add_foreign_key "success_criteria", "checks"
|
||||||
add_foreign_key "success_criteria", "elements"
|
add_foreign_key "success_criteria", "elements"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -91,5 +91,5 @@ Link.create!(url: "https://www.a11yproject.com/",
|
||||||
description: "The A11Y Project is a community-driven effort to make digital accessibility easier.",
|
description: "The A11Y Project is a community-driven effort to make digital accessibility easier.",
|
||||||
link_category: LinkCategory.find_by(name: "Artikel"))
|
link_category: LinkCategory.find_by(name: "Artikel"))
|
||||||
|
|
||||||
Account.find_or_initialize_by(email: "admin@example.com").update!(password: "password")
|
User.find_or_initialize_by(email_address: "admin@example.com").update!(password: "password")
|
||||||
Account.find_or_initialize_by(email: "goran@quiet.ch").update!(password: "password")
|
User.find_or_initialize_by(email_address: "goran@quiet.ch").update!(password: "password")
|
||||||
|
|
@ -39,3 +39,12 @@ services:
|
||||||
|
|
||||||
chrome:
|
chrome:
|
||||||
image: selenium/standalone-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
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,23 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def login(email, password)
|
def login(email, password)
|
||||||
visit "/login"
|
visit "/session/new"
|
||||||
|
assert_selector("h1", text: "Login")
|
||||||
fill_in "Login", with: email
|
fill_in "Login", with: email
|
||||||
fill_in "Password", with: password
|
fill_in "Passwort", with: password
|
||||||
click_button "Login"
|
click_button "Login"
|
||||||
|
assert_text("Dashboard")
|
||||||
|
save_screenshot "after_login.png"
|
||||||
end
|
end
|
||||||
|
|
||||||
def logout
|
def logout
|
||||||
visit "/logout"
|
Session.destroy_all
|
||||||
click_on "Log out"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def login_test
|
def login_test
|
||||||
Account.create(email: "test@example.com", password: "password")
|
user = User.find_or_initialize_by(email_address: "test@example.com")
|
||||||
login("test@example.com", "password")
|
user.update!(password: "password")
|
||||||
|
login(user.email_address, user.password)
|
||||||
|
save_screenshot "login.png"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
15
test/controller_test.rb
Normal file
15
test/controller_test.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class ControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
def login(email, password)
|
||||||
|
post "/session", params: { email_address: email, password: password }
|
||||||
|
assert_redirected_to "/"
|
||||||
|
end
|
||||||
|
|
||||||
|
def logout
|
||||||
|
delete "/session"
|
||||||
|
assert_redirected_to "/session/new"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -3,23 +3,13 @@
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class BackupsControllerTest < ActionDispatch::IntegrationTest
|
class BackupsControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,12 @@
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class BackofficeControllerTest < ActionDispatch::IntegrationTest
|
class BackofficeControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,14 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class ChecklistEntriesControllerTest < ActionDispatch::IntegrationTest
|
class ChecklistEntriesControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@checklist_entry = checklist_entries(:one)
|
@checklist_entry = checklist_entries(:one)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,14 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class ChecklistsControllerTest < ActionDispatch::IntegrationTest
|
class ChecklistsControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@checklist = checklists(:one)
|
@checklist = checklists(:one)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,7 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class ChecksControllerTest < ActionDispatch::IntegrationTest
|
class ChecksControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
@ -20,7 +10,7 @@ class ChecksControllerTest < ActionDispatch::IntegrationTest
|
||||||
setup do
|
setup do
|
||||||
@principle = principles(:one)
|
@principle = principles(:one)
|
||||||
@check = checks(:deletable)
|
@check = checks(:deletable)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,7 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class ElementsControllerTest < ActionDispatch::IntegrationTest
|
class ElementsControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
@ -20,7 +10,7 @@ class ElementsControllerTest < ActionDispatch::IntegrationTest
|
||||||
setup do
|
setup do
|
||||||
@element = elements(:one)
|
@element = elements(:one)
|
||||||
@checklist = checklists(:one)
|
@checklist = checklists(:one)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class HomeControllerTest < ActionDispatch::IntegrationTest
|
class HomeControllerTest < ::ControllerTest
|
||||||
test "should get show" do
|
test "should get show" do
|
||||||
get root_url
|
get root_url
|
||||||
assert_response :success
|
assert_response :success
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,14 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class LinkCategoriesControllerTest < ActionDispatch::IntegrationTest
|
class LinkCategoriesControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@link_category = link_categories(:one)
|
@link_category = link_categories(:one)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,14 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class LinksControllerTest < ActionDispatch::IntegrationTest
|
class LinksControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@link = links(:one)
|
@link = links(:one)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,12 @@
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class PagesControllerTest < ActionDispatch::IntegrationTest
|
class PagesControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
@page = pages(:one)
|
@page = pages(:one)
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,14 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class ReportsControllerTest < ActionDispatch::IntegrationTest
|
class ReportsControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@report = reports(:one)
|
@report = reports(:one)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,14 @@
|
||||||
|
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class SuccessCriteriaControllerTest < ActionDispatch::IntegrationTest
|
class SuccessCriteriaControllerTest < ::ControllerTest
|
||||||
def login(email, password)
|
|
||||||
post "/login", params: { email: email, password: password }
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
post "/logout"
|
|
||||||
assert_redirected_to "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
logout
|
logout
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@success_criterion = success_criteria(:one)
|
@success_criterion = success_criteria(:one)
|
||||||
Account.create(email: "test@example.com", password: "password")
|
User.create!(email_address: "test@example.com", password: "password")
|
||||||
login("test@example.com", "password")
|
login("test@example.com", "password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
10
test/fixtures/accounts.yml
vendored
10
test/fixtures/accounts.yml
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
|
||||||
one:
|
|
||||||
email: freddie@queen.com
|
|
||||||
password_hash: <%= RodauthApp.rodauth.allocate.password_hash("password") %>
|
|
||||||
status: verified
|
|
||||||
|
|
||||||
two:
|
|
||||||
email: brian@queen.com
|
|
||||||
password_hash: <%= RodauthApp.rodauth.allocate.password_hash("password") %>
|
|
||||||
status: verified
|
|
||||||
9
test/fixtures/users.yml
vendored
Normal file
9
test/fixtures/users.yml
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<% password_digest = BCrypt::Password.create("password") %>
|
||||||
|
|
||||||
|
one:
|
||||||
|
email_address: one@example.com
|
||||||
|
password_digest: <%= password_digest %>
|
||||||
|
|
||||||
|
two:
|
||||||
|
email_address: two@example.com
|
||||||
|
password_digest: <%= password_digest %>
|
||||||
7
test/mailers/previews/passwords_mailer_preview.rb
Normal file
7
test/mailers/previews/passwords_mailer_preview.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Preview all emails at http://localhost:3000/rails/mailers/passwords_mailer
|
||||||
|
class PasswordsMailerPreview < ActionMailer::Preview
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/passwords_mailer/reset
|
||||||
|
def reset
|
||||||
|
PasswordsMailer.reset(User.take)
|
||||||
|
end
|
||||||
|
end
|
||||||
7
test/models/user_test.rb
Normal file
7
test/models/user_test.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class UserTest < ActiveSupport::TestCase
|
||||||
|
# test "the truth" do
|
||||||
|
# assert true
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
|
@ -4,12 +4,14 @@ ENV["RAILS_ENV"] ||= "test"
|
||||||
require_relative "../config/environment"
|
require_relative "../config/environment"
|
||||||
require "rails/test_help"
|
require "rails/test_help"
|
||||||
require "action_text/system_test_helper"
|
require "action_text/system_test_helper"
|
||||||
|
require "capybara/rails"
|
||||||
|
require "controller_test"
|
||||||
|
|
||||||
module ActiveSupport
|
module ActiveSupport
|
||||||
class TestCase
|
class TestCase
|
||||||
include ActionText::SystemTestHelper
|
include ActionText::SystemTestHelper
|
||||||
# Run tests in parallel with specified workers
|
# Run tests in parallel with specified workers
|
||||||
parallelize(workers: :number_of_processors)
|
# parallelize(workers: :number_of_processors)
|
||||||
|
|
||||||
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
|
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
|
||||||
fixtures :all
|
fixtures :all
|
||||||
|
|
|
||||||
BIN
vendor/assets/fonts/bootstrap-icons.woff
vendored
Normal file
BIN
vendor/assets/fonts/bootstrap-icons.woff
vendored
Normal file
Binary file not shown.
BIN
vendor/assets/fonts/bootstrap-icons.woff2
vendored
Normal file
BIN
vendor/assets/fonts/bootstrap-icons.woff2
vendored
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue