Compare commits
10 Commits
d1395c780a
...
93359a5b59
Author | SHA1 | Date |
---|---|---|
|
93359a5b59 | |
|
716176a1b8 | |
|
72bee55d7e | |
|
ed01262d88 | |
|
f70a676456 | |
|
ce241b1674 | |
|
5a930074f6 | |
|
c22a5ffac2 | |
|
e3f53839d5 | |
|
df777e9927 |
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
ln .git-hooks/pre-commit .git/hooks/pre-commit
|
||||
chmod +x .git/hooks/pre-commit
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
AMBER='\033[0;33m'
|
||||
RED='\033[0;31m'
|
||||
CLEAR_COLOR='\033[0m'
|
||||
|
||||
function run_command {
|
||||
local COMMAND=$1
|
||||
local COMMAND_NAME=$2
|
||||
|
||||
echo -e "${AMBER}Running $COMMAND_NAME…${AMBER}"
|
||||
$COMMAND &>/dev/null
|
||||
if [[ $? -ne 0 ]] ; then
|
||||
echo -e "${RED}❌ $COMMAND_NAME failed${CLEAR_COLOR}"
|
||||
exit 1
|
||||
else
|
||||
echo -e "${GREEN}✓ $COMMAND_NAME passed${CLEAR_COLOR}"
|
||||
fi
|
||||
}
|
||||
|
||||
run_command "brakeman --format html -o ../tmp/brakeman.html" "Brakeman"
|
||||
run_command "bundle exec rubocop" "Rubocop"
|
||||
run_command "bundle exec rails test" "test suite"
|
2
Gemfile
2
Gemfile
|
@ -3,7 +3,7 @@ source "https://rubygems.org"
|
|||
ruby file: "./.ruby-version"
|
||||
|
||||
gem "rails", "~> 7.1.3", ">= 7.1.3.2"
|
||||
gem "sprockets-rails"
|
||||
gem "propshaft"
|
||||
gem "pg"
|
||||
gem "puma", ">= 5.0"
|
||||
gem "importmap-rails"
|
||||
|
|
176
Gemfile.lock
176
Gemfile.lock
|
@ -1,35 +1,35 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.1.3.2)
|
||||
actionpack (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
actioncable (7.1.3.3)
|
||||
actionpack (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (7.1.3.2)
|
||||
actionpack (= 7.1.3.2)
|
||||
activejob (= 7.1.3.2)
|
||||
activerecord (= 7.1.3.2)
|
||||
activestorage (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
actionmailbox (7.1.3.3)
|
||||
actionpack (= 7.1.3.3)
|
||||
activejob (= 7.1.3.3)
|
||||
activerecord (= 7.1.3.3)
|
||||
activestorage (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.1.3.2)
|
||||
actionpack (= 7.1.3.2)
|
||||
actionview (= 7.1.3.2)
|
||||
activejob (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
actionmailer (7.1.3.3)
|
||||
actionpack (= 7.1.3.3)
|
||||
actionview (= 7.1.3.3)
|
||||
activejob (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (7.1.3.2)
|
||||
actionview (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
actionpack (7.1.3.3)
|
||||
actionview (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
nokogiri (>= 1.8.5)
|
||||
racc
|
||||
rack (>= 2.2.4)
|
||||
|
@ -37,35 +37,35 @@ GEM
|
|||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
actiontext (7.1.3.2)
|
||||
actionpack (= 7.1.3.2)
|
||||
activerecord (= 7.1.3.2)
|
||||
activestorage (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
actiontext (7.1.3.3)
|
||||
actionpack (= 7.1.3.3)
|
||||
activerecord (= 7.1.3.3)
|
||||
activestorage (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
actionview (7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
activejob (7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
activejob (7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
activerecord (7.1.3.2)
|
||||
activemodel (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
activemodel (7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
activerecord (7.1.3.3)
|
||||
activemodel (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
timeout (>= 0.4.0)
|
||||
activestorage (7.1.3.2)
|
||||
actionpack (= 7.1.3.2)
|
||||
activejob (= 7.1.3.2)
|
||||
activerecord (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
activestorage (7.1.3.3)
|
||||
actionpack (= 7.1.3.3)
|
||||
activejob (= 7.1.3.3)
|
||||
activerecord (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
marcel (~> 1.0)
|
||||
activesupport (7.1.3.2)
|
||||
activesupport (7.1.3.3)
|
||||
base64
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
|
@ -80,7 +80,7 @@ GEM
|
|||
ast (2.4.2)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
bigdecimal (3.1.7)
|
||||
bigdecimal (3.1.8)
|
||||
bindex (0.8.1)
|
||||
bootsnap (1.18.3)
|
||||
msgpack (~> 1.2)
|
||||
|
@ -105,17 +105,17 @@ GEM
|
|||
erubi (1.12.0)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
i18n (1.14.4)
|
||||
i18n (1.14.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
importmap-rails (2.0.1)
|
||||
actionpack (>= 6.0.0)
|
||||
activesupport (>= 6.0.0)
|
||||
railties (>= 6.0.0)
|
||||
io-console (0.7.2)
|
||||
irb (1.12.0)
|
||||
rdoc
|
||||
irb (1.13.1)
|
||||
rdoc (>= 4.0.0)
|
||||
reline (>= 0.4.2)
|
||||
jbuilder (2.11.5)
|
||||
jbuilder (2.12.0)
|
||||
actionview (>= 5.0.0)
|
||||
activesupport (>= 5.0.0)
|
||||
json (2.7.2)
|
||||
|
@ -131,10 +131,10 @@ GEM
|
|||
marcel (1.0.4)
|
||||
matrix (0.4.2)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.22.3)
|
||||
minitest (5.23.1)
|
||||
msgpack (1.7.2)
|
||||
mutex_m (0.2.0)
|
||||
net-imap (0.4.10)
|
||||
net-imap (0.4.11)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
|
@ -143,31 +143,36 @@ GEM
|
|||
timeout
|
||||
net-smtp (0.5.0)
|
||||
net-protocol
|
||||
nio4r (2.7.1)
|
||||
nokogiri (1.16.4-aarch64-linux)
|
||||
nio4r (2.7.3)
|
||||
nokogiri (1.16.5-aarch64-linux)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.16.4-arm-linux)
|
||||
nokogiri (1.16.5-arm-linux)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.16.4-arm64-darwin)
|
||||
nokogiri (1.16.5-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.16.4-x86-linux)
|
||||
nokogiri (1.16.5-x86-linux)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.16.4-x86_64-darwin)
|
||||
nokogiri (1.16.5-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.16.4-x86_64-linux)
|
||||
nokogiri (1.16.5-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
parallel (1.24.0)
|
||||
parser (3.3.0.5)
|
||||
parser (3.3.1.0)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
pg (1.5.6)
|
||||
propshaft (0.9.0)
|
||||
actionpack (>= 7.0.0)
|
||||
activesupport (>= 7.0.0)
|
||||
rack
|
||||
railties (>= 7.0.0)
|
||||
psych (5.1.2)
|
||||
stringio
|
||||
public_suffix (5.0.5)
|
||||
puma (6.4.2)
|
||||
nio4r (~> 2.0)
|
||||
racc (1.7.3)
|
||||
rack (3.0.10)
|
||||
racc (1.8.0)
|
||||
rack (3.0.11)
|
||||
rack-session (2.0.0)
|
||||
rack (>= 3.0.0)
|
||||
rack-test (2.1.0)
|
||||
|
@ -175,20 +180,20 @@ GEM
|
|||
rackup (2.1.0)
|
||||
rack (>= 3)
|
||||
webrick (~> 1.8)
|
||||
rails (7.1.3.2)
|
||||
actioncable (= 7.1.3.2)
|
||||
actionmailbox (= 7.1.3.2)
|
||||
actionmailer (= 7.1.3.2)
|
||||
actionpack (= 7.1.3.2)
|
||||
actiontext (= 7.1.3.2)
|
||||
actionview (= 7.1.3.2)
|
||||
activejob (= 7.1.3.2)
|
||||
activemodel (= 7.1.3.2)
|
||||
activerecord (= 7.1.3.2)
|
||||
activestorage (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
rails (7.1.3.3)
|
||||
actioncable (= 7.1.3.3)
|
||||
actionmailbox (= 7.1.3.3)
|
||||
actionmailer (= 7.1.3.3)
|
||||
actionpack (= 7.1.3.3)
|
||||
actiontext (= 7.1.3.3)
|
||||
actionview (= 7.1.3.3)
|
||||
activejob (= 7.1.3.3)
|
||||
activemodel (= 7.1.3.3)
|
||||
activerecord (= 7.1.3.3)
|
||||
activestorage (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.1.3.2)
|
||||
railties (= 7.1.3.3)
|
||||
rails-dom-testing (2.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
|
@ -196,9 +201,9 @@ GEM
|
|||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
railties (7.1.3.2)
|
||||
actionpack (= 7.1.3.2)
|
||||
activesupport (= 7.1.3.2)
|
||||
railties (7.1.3.3)
|
||||
actionpack (= 7.1.3.3)
|
||||
activesupport (= 7.1.3.3)
|
||||
irb
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
|
@ -206,13 +211,14 @@ GEM
|
|||
zeitwerk (~> 2.6)
|
||||
rainbow (3.1.1)
|
||||
rake (13.2.1)
|
||||
rdoc (6.6.3.1)
|
||||
rdoc (6.7.0)
|
||||
psych (>= 4.0.0)
|
||||
regexp_parser (2.9.0)
|
||||
reline (0.5.1)
|
||||
regexp_parser (2.9.2)
|
||||
reline (0.5.7)
|
||||
io-console (~> 0.5)
|
||||
rexml (3.2.6)
|
||||
rubocop (1.63.1)
|
||||
rexml (3.2.8)
|
||||
strscan (>= 3.0.9)
|
||||
rubocop (1.64.0)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
parallel (~> 1.10)
|
||||
|
@ -223,15 +229,15 @@ GEM
|
|||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.31.2)
|
||||
parser (>= 3.3.0.4)
|
||||
rubocop-ast (1.31.3)
|
||||
parser (>= 3.3.1.0)
|
||||
rubocop-minitest (0.35.0)
|
||||
rubocop (>= 1.61, < 2.0)
|
||||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
rubocop-performance (1.21.0)
|
||||
rubocop (>= 1.48.1, < 2.0)
|
||||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
rubocop-rails (2.24.1)
|
||||
rubocop-rails (2.25.0)
|
||||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
|
@ -243,21 +249,15 @@ GEM
|
|||
rubocop-rails
|
||||
ruby-progressbar (1.13.0)
|
||||
rubyzip (2.3.2)
|
||||
selenium-webdriver (4.19.0)
|
||||
selenium-webdriver (4.21.1)
|
||||
base64 (~> 0.2)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 3.0)
|
||||
websocket (~> 1.0)
|
||||
sprockets (4.2.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (>= 2.2.4, < 4)
|
||||
sprockets-rails (3.4.2)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
sprockets (>= 3.0.0)
|
||||
stimulus-rails (1.3.3)
|
||||
railties (>= 6.0.0)
|
||||
stringio (3.1.0)
|
||||
strscan (3.1.0)
|
||||
thor (1.3.1)
|
||||
timeout (0.4.1)
|
||||
turbo-rails (2.0.5)
|
||||
|
@ -279,7 +279,7 @@ GEM
|
|||
websocket-extensions (0.1.5)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.6.13)
|
||||
zeitwerk (2.6.15)
|
||||
|
||||
PLATFORMS
|
||||
aarch64-linux
|
||||
|
@ -297,11 +297,11 @@ DEPENDENCIES
|
|||
importmap-rails
|
||||
jbuilder
|
||||
pg
|
||||
propshaft
|
||||
puma (>= 5.0)
|
||||
rails (~> 7.1.3, >= 7.1.3.2)
|
||||
rubocop-rails-omakase
|
||||
selenium-webdriver
|
||||
sprockets-rails
|
||||
stimulus-rails
|
||||
turbo-rails
|
||||
tzinfo-data
|
||||
|
|
29
README.md
29
README.md
|
@ -1,17 +1,26 @@
|
|||
# Forg
|
||||
# Tabletop Companion
|
||||
|
||||
Forg is a _Family ORGaniser_.
|
||||
|
||||
It will allow you to:
|
||||
|
||||
- Set and assign todos
|
||||
- Includes regularly scheduled tasks, such as housework
|
||||
- Set a meal plan
|
||||
- Allows for advanced reminders to cook/purchase ingredients/defrost
|
||||
- Manage a shopping list
|
||||
Tabletop Companion is a lightweight way to assist you playing tabletop games, online with
|
||||
the video chat software of your choice or offline at a physical table.
|
||||
|
||||
## Development setup
|
||||
|
||||
Spin up the application with `./bin/setup`.
|
||||
|
||||
Run tests with `rails test`.
|
||||
|
||||
### Git hooks
|
||||
|
||||
There is a pre-commit git hook stored in .git-hooks which can be installed by running `.git-hooks/install.bash`.
|
||||
|
||||
The hooks:
|
||||
- Run Rubocop
|
||||
- Run tests
|
||||
- Run Brakeman
|
||||
|
||||
### Brakeman
|
||||
|
||||
If Brakeman issues are introduced, they should be immediately fixed or ignored with a note as to why it
|
||||
is not a real issue. To do so, run `bundle exec brakeman -I`.
|
||||
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
||||
* listed below.
|
||||
*
|
||||
* Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's
|
||||
* vendor/assets/stylesheets directory can be referenced here using a relative path.
|
||||
*
|
||||
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
||||
* compiled file so the styles you add here take precedence over styles defined in any other CSS
|
||||
* files in this directory. Styles in this file should be added after the last require_* statement.
|
||||
* It is generally better to create a new file per style scope.
|
||||
*
|
||||
*= require_tree .
|
||||
*= require_self
|
||||
*/
|
|
@ -2,4 +2,12 @@
|
|||
--inset-bg-color: #eee;
|
||||
|
||||
--border-radius: .5em;
|
||||
|
||||
--button-bg-color: #333;
|
||||
--button-text-color: #fff;
|
||||
--button-hover-bg-color: #555;
|
||||
--button-hover-text-color: #fff;
|
||||
|
||||
--notice-bg-color: #5cb85c;
|
||||
--notice-text-color: #fff;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,13 @@ main {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
aside.flash {
|
||||
background-color: var(--notice-bg-color);
|
||||
color: var(--notice-text-color);
|
||||
padding: 1em;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
section.inset {
|
||||
width: 70%;
|
||||
max-width: 60em;
|
||||
|
@ -25,3 +32,25 @@ section.inset {
|
|||
h1, h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header nav {
|
||||
ul {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
li {
|
||||
list-style-type: none;
|
||||
padding: 0 .5em;
|
||||
}
|
||||
a:link, a:visited {
|
||||
background-color: var(--button-bg-color);
|
||||
color: var(--button-text-color);
|
||||
border-radius: var(--border-radius);
|
||||
text-decoration: none;
|
||||
padding: .5em;
|
||||
}
|
||||
a:hover {
|
||||
background-color: var(--button-hover-bg-color);
|
||||
color: var(--button-hover-text-color);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
class Admin::GameSystemsController < AdminController
|
||||
before_action :set_game_system, only: [ :show, :edit, :update, :destroy ]
|
||||
def index
|
||||
@game_systems = GameSystem.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def new
|
||||
@game_system = GameSystem.new
|
||||
end
|
||||
|
||||
def create
|
||||
@game_system = GameSystem.new(game_system_params)
|
||||
if @game_system.save
|
||||
redirect_to admin_game_system_path(@game_system), notice: t(".success", name: @game_system.name)
|
||||
else
|
||||
flash.now[:alert] = t(".error", name: @game_system.name)
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @game_system.update(game_system_params)
|
||||
redirect_to admin_game_system_path(@game_system), notice: t(".success", name: @game_system.name)
|
||||
else
|
||||
flash.now[:alert] = t(".error", name: @game_system.name)
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
name = @game_system.name
|
||||
if @game_system.destroy
|
||||
redirect_to admin_game_systems_path, notice: t(".success", name:)
|
||||
else
|
||||
flash[:alert] = t(".error", name:)
|
||||
redirect_to admin_game_systems_path, alert: t(".error")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def game_system_params
|
||||
params.require(:game_system).permit(
|
||||
:name,
|
||||
)
|
||||
end
|
||||
|
||||
def set_game_system
|
||||
@game_system = GameSystem.find(params[:id])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
class AdminController < ApplicationController
|
||||
layout "admin"
|
||||
|
||||
before_action :authenticate_user_as_admin
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate_user_as_admin
|
||||
head :forbidden unless Current.user&.admin?
|
||||
end
|
||||
end
|
|
@ -4,7 +4,6 @@ class ApplicationController < ActionController::Base
|
|||
private
|
||||
|
||||
def authenticate
|
||||
Rails.logger.error "Session: #{session.inspect}"
|
||||
if authenticated_user = User.find_by(id: session[:user_id])
|
||||
Current.user = authenticated_user
|
||||
else
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
class TablesController < ApplicationController
|
||||
def index
|
||||
end
|
||||
end
|
|
@ -1,4 +0,0 @@
|
|||
class TodosController < ApplicationController
|
||||
def index
|
||||
end
|
||||
end
|
|
@ -5,12 +5,12 @@ class UserMailer < ApplicationMailer
|
|||
@user = params[:user]
|
||||
@token = params[:token]
|
||||
|
||||
mail(to: @user.email, subject: "[Forg] Verify your email")
|
||||
mail(to: @user.email, subject: "[Tabletop Companion] Verify your email")
|
||||
end
|
||||
|
||||
def email_verified
|
||||
@user = params[:user]
|
||||
|
||||
mail(to: @user.email, subject: "[Forg] Your email has been verified")
|
||||
mail(to: @user.email, subject: "[Tabletop Companion] Your email has been verified")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class GameSystem < ApplicationRecord
|
||||
validates :name, presence: true,
|
||||
uniqueness: true,
|
||||
length: { maximum: 100 }
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
class SiteRole < ApplicationRecord
|
||||
validates :name, presence: true
|
||||
end
|
|
@ -1,4 +1,6 @@
|
|||
class User < ApplicationRecord
|
||||
has_and_belongs_to_many :site_roles
|
||||
|
||||
has_secure_password
|
||||
generates_token_for :password_reset, expires_in: 4.hours do
|
||||
password_salt.last(10) # Invalidates when password changed
|
||||
|
@ -35,4 +37,8 @@ class User < ApplicationRecord
|
|||
|
||||
"#{first_name} #{last_name}"
|
||||
end
|
||||
|
||||
def admin?
|
||||
site_roles.include? SiteRole.find_by(name: "Admin")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<% # locals: (game_system: @game_system, button_text:, url:) %>
|
||||
|
||||
<%= form_with model: @game_system, url: do |f| %>
|
||||
<%= f.label :name %>
|
||||
<%= f.text_field :name %>
|
||||
|
||||
<%= f.submit button_text %>
|
||||
<% end %>
|
|
@ -0,0 +1,4 @@
|
|||
<h2><%= t(".edit", name: @game_system.name) %></h2>
|
||||
|
||||
<%= render partial: "form",
|
||||
locals: { button_text: t(".update", name: @game_system.name), url: admin_game_system_path(@game_system) } %>
|
|
@ -0,0 +1,9 @@
|
|||
<% content_for :title, t(".game_systems") %>
|
||||
|
||||
<%= link_to t(".new_game_system"), new_admin_game_system_path %>
|
||||
|
||||
<% @game_systems.each do |game_system| %>
|
||||
<div id=<%= dom_id(game_system) %> class="game-system">
|
||||
<%= link_to game_system.name, admin_game_system_path(game_system) %>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1,3 @@
|
|||
<h2><%= t(".new") %></h2>
|
||||
|
||||
<%= render partial: "form", locals: { button_text: t(".create"), url: admin_game_systems_path } %>
|
|
@ -0,0 +1,6 @@
|
|||
<h2><%= @game_system.name %></h2>
|
||||
|
||||
<%= link_to t("edit"), edit_admin_game_system_path(@game_system) %>
|
||||
|
||||
<%= link_to t("delete"), admin_game_system_path(@game_system),
|
||||
data: { turbo_method: :delete, turbo_confirm: t(".confirm_delete", name: @game_system.name) } %>
|
|
@ -0,0 +1,2 @@
|
|||
<% content_for :title, t(".dashboard") %>
|
||||
<%= t(".intro") %>
|
|
@ -0,0 +1,11 @@
|
|||
<% content_for :submenu do %>
|
||||
<h2><%= t("administration") %>: <%= content_for :title %></h2>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><%= link_to t(".dashboard"), admin_index_path %></li>
|
||||
<li><%= link_to t(".game_systems"), admin_game_systems_path %></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<% end %>
|
||||
|
||||
<%= render template: "layouts/application" %>
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= "#{yield(:title)} | " if content_for? :title %><%= t("forg") %></title>
|
||||
<title><%= "#{yield(:title)} | " if content_for? :title %><%= t("site_name") %></title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<%= csrf_meta_tags %>
|
||||
<%= csp_meta_tag %>
|
||||
|
||||
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
||||
<%= stylesheet_link_tag :all, "data-turbo-track": "reload" %>
|
||||
<%= javascript_importmap_tags %>
|
||||
<meta name="turbo-refresh-method" content="morph">
|
||||
<meta name="turbo-refresh-scroll" content="preserve">
|
||||
|
@ -14,19 +14,24 @@
|
|||
|
||||
<body>
|
||||
<header>
|
||||
<h1><%= link_to t("forg"), root_path %></h1>
|
||||
<h1><%= link_to t("site_name"), root_path %></h1>
|
||||
<nav>
|
||||
<ul>
|
||||
<% if logged_in? %>
|
||||
<li><%= link_to t("log_out"), logout_path, data: {turbo_method: :delete} %></li>
|
||||
<% if Current.user.admin? %>
|
||||
<li><%= link_to t("administration"), admin_index_path %></li>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<li><%= link_to t("log_in"), login_path %></li>
|
||||
<li><%= link_to t("sign_up"), new_user_path %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><%= link_to t("forg"), root_path %></li>
|
||||
<% if logged_in? %>
|
||||
<li><%= link_to t("log_out"), logout_path, data: {turbo_method: :delete} %></li>
|
||||
<% else %>
|
||||
<li><%= link_to t("log_in"), login_path %></li>
|
||||
<li><%= link_to t("sign_up"), new_user_path %></li>
|
||||
<% end %>
|
||||
<%= render partial: "shared/flash_messages" %>
|
||||
<main>
|
||||
<%= yield(:submenu) if content_for?(:submenu) %>
|
||||
<%= yield %>
|
||||
</main>
|
||||
</body>
|
||||
|
|
|
@ -6,7 +6,7 @@ require "rails/all"
|
|||
# you've limited to :test, :development, or :production.
|
||||
Bundler.require(*Rails.groups)
|
||||
|
||||
module Forg
|
||||
module TabletopCompanion
|
||||
class Application < Rails::Application
|
||||
# Initialize configuration defaults for originally generated Rails version.
|
||||
config.load_defaults 7.1
|
||||
|
|
|
@ -7,4 +7,4 @@ test:
|
|||
production:
|
||||
adapter: redis
|
||||
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
|
||||
channel_prefix: forg_production
|
||||
channel_prefix: tabletop_companion_production
|
||||
|
|
|
@ -9,12 +9,12 @@ default: &default
|
|||
|
||||
development:
|
||||
<<: *default
|
||||
database: forg_development
|
||||
database: tabletop_companion_development
|
||||
|
||||
test:
|
||||
<<: *default
|
||||
database: forg_test
|
||||
database: tabletop_companion_test
|
||||
|
||||
production:
|
||||
<<: *default
|
||||
database: forg_production
|
||||
database: tabletop_companion_production
|
||||
|
|
|
@ -1,24 +1,56 @@
|
|||
en:
|
||||
forg: Forg
|
||||
site_name: Tabletop Companion
|
||||
administration: Administration
|
||||
log_in: Log in
|
||||
log_out: Log out
|
||||
sign_up: Sign up
|
||||
not_authenticated: You need to log in to access this page.
|
||||
edit: Edit
|
||||
delete: Delete
|
||||
layouts:
|
||||
admin:
|
||||
dashboard: Dashboard
|
||||
game_systems: Game Systems
|
||||
mailer:
|
||||
greeting: "Hello, %{name}"
|
||||
sign_off: |
|
||||
See you soon,
|
||||
The Forg team
|
||||
sign_off_html: "<p>See you soon,<br>The Forg team</p>"
|
||||
The Tabletop Companion team
|
||||
sign_off_html: "<p>See you soon,<br>The Tabletop Companion team</p>"
|
||||
account_verifications:
|
||||
show:
|
||||
success: "Thanks for verifying your email address! You can now log in."
|
||||
error: "Invalid token, could not verify your account."
|
||||
admin:
|
||||
index:
|
||||
dashboard: Dashboard
|
||||
intro: With great power comes great responsibility
|
||||
game_systems:
|
||||
error: Error
|
||||
index:
|
||||
game_systems: Game systems
|
||||
new_game_system: New game system
|
||||
new:
|
||||
new: New game system
|
||||
create: Add game system
|
||||
create:
|
||||
success: “%{name}” has been created.
|
||||
error: “%{name}” could not be created.
|
||||
show:
|
||||
confirm_delete: Are you sure you want to delete “%{name}”?
|
||||
edit:
|
||||
edit: Edit %{name}
|
||||
update: Update %{name}
|
||||
update:
|
||||
success: Successfully updated “%{name}”.
|
||||
error: “%{name}” could not be updated.
|
||||
destroy:
|
||||
success: Successfully deleted “%{name}”.
|
||||
error: “%{name}” could not be deleted.
|
||||
sessions:
|
||||
create:
|
||||
success: "Hello, %{name}!"
|
||||
error: "Could not sign in. Please check your email and password."
|
||||
error: "Could not sign in. Please check your username and password."
|
||||
new:
|
||||
log_in: Log in
|
||||
destroy:
|
||||
|
@ -31,16 +63,16 @@ en:
|
|||
sign_up: Sign up
|
||||
create:
|
||||
error: "Could not create account: %{error}"
|
||||
success: "Thanks for joining Forg, %{name}! Please check your email to verify your address."
|
||||
success: "Thanks for joining Tabletop Companion, %{name}! Please check your email to verify your address."
|
||||
user_mailer:
|
||||
email_verified:
|
||||
content: |-
|
||||
Thanks for verifying your email address, and welcome to Forg!
|
||||
Thanks for verifying your email address, and welcome to Tabletop Companion!
|
||||
|
||||
You can now go ahead and log in. Enjoy!
|
||||
email_verification:
|
||||
content: |-
|
||||
If you did not sign up for Forg, please ignore this email.
|
||||
If you did not sign up for Tabletop Companion, please ignore this email.
|
||||
|
||||
Otherwise, please visit the link below to verify your email address.
|
||||
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
Rails.application.routes.draw do
|
||||
get 'todos/index'
|
||||
default_url_options host: "forg-app.com"
|
||||
default_url_options host: "summonplayer.com"
|
||||
|
||||
root "todos#index"
|
||||
root "tables#index"
|
||||
|
||||
get "login" => "sessions#new", as: :login
|
||||
delete "logout" => "sessions#destroy", as: :logout
|
||||
|
||||
resources :users, only: %i[new create]
|
||||
resources :account_verifications, only: %i[show]
|
||||
resources :sessions, only: %i[new create destroy]
|
||||
resources :users, only: [ :new, :create ]
|
||||
resources :account_verifications, only: [ :show ]
|
||||
resources :sessions, only: [ :new, :create, :destroy ]
|
||||
|
||||
resources :tables, only: [ :index ]
|
||||
|
||||
resources :admin, only: [ :index ]
|
||||
namespace :admin do
|
||||
resources :game_systems
|
||||
end
|
||||
|
||||
get "up" => "rails/health#show", as: :rails_health_check
|
||||
end
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class CreateGameSystems < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
create_table :game_systems do |t|
|
||||
t.string :name, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
class CreateUserRoles < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
create_table :site_roles do |t|
|
||||
t.string :name, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table :site_roles_users do |t|
|
||||
t.belongs_to :user
|
||||
t.belongs_to :site_role
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
class AddUniqueIndexToGameSystemName < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_index :game_systems, :name, unique: true
|
||||
|
||||
add_check_constraint :game_systems, "length(name) <= 100", name: "chk_name_max_length"
|
||||
end
|
||||
end
|
|
@ -10,10 +10,31 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_04_14_122652) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_05_26_102908) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
create_table "game_systems", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["name"], name: "index_game_systems_on_name", unique: true
|
||||
t.check_constraint "length(name::text) <= 100", name: "chk_name_max_length"
|
||||
end
|
||||
|
||||
create_table "site_roles", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "site_roles_users", force: :cascade do |t|
|
||||
t.bigint "user_id"
|
||||
t.bigint "site_role_id"
|
||||
t.index ["site_role_id"], name: "index_site_roles_users_on_site_role_id"
|
||||
t.index ["user_id"], name: "index_site_roles_users_on_user_id"
|
||||
end
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "username", limit: 20, null: false
|
||||
t.string "password_digest", limit: 200, null: false
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
require "test_helper"
|
||||
|
||||
class AdminGameSystemsControllerTest < ActionDispatch::IntegrationTest
|
||||
test "should get game systems index if signed in as admin" do
|
||||
sign_in users(:admin)
|
||||
get admin_game_systems_path
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "should not get game systems index if signed in as non-admin user" do
|
||||
sign_in users(:trevor)
|
||||
get admin_game_systems_path
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
test "should not get game systems index if not signed in" do
|
||||
get admin_game_systems_path
|
||||
assert_redirected_to login_path
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
require "test_helper"
|
||||
|
||||
class AdminControllerTest < ActionDispatch::IntegrationTest
|
||||
test "should get index if signed in as admin" do
|
||||
sign_in users(:admin)
|
||||
get admin_index_url
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "should not get index if signed in as non-admin user" do
|
||||
sign_in users(:trevor)
|
||||
get admin_index_url
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
test "should not get index if not signed in" do
|
||||
get admin_index_url
|
||||
assert_redirected_to login_path
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
troika:
|
||||
name: Troika
|
|
@ -0,0 +1,2 @@
|
|||
admin:
|
||||
name: Admin
|
|
@ -16,6 +16,12 @@ unverified:
|
|||
last_name: User
|
||||
verified: false
|
||||
|
||||
admin:
|
||||
<<: *DEFAULTS
|
||||
first_name: Admin
|
||||
last_name: User
|
||||
site_roles: admin
|
||||
|
||||
<% 1.upto(10) do |i| %>
|
||||
user_<%= i %>:
|
||||
<<: *DEFAULTS
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
require "test_helper"
|
||||
|
||||
class AdminGameSystemsIntegrationTest < ActionDispatch::IntegrationTest
|
||||
test "index should show most all game systems" do
|
||||
sign_in users(:admin)
|
||||
get admin_game_systems_path
|
||||
assert_response :success
|
||||
|
||||
assert_select ".game-system", GameSystem.all.size
|
||||
end
|
||||
|
||||
test "show should show game system" do
|
||||
sign_in users(:admin)
|
||||
get admin_game_system_path(game_systems(:troika))
|
||||
assert_response :success
|
||||
assert_select "h2", game_systems(:troika).name
|
||||
end
|
||||
|
||||
test "new should show form to create new game system" do
|
||||
sign_in users(:admin)
|
||||
get new_admin_game_system_path
|
||||
assert_response :success
|
||||
|
||||
assert_select "form[action=?][method=?]", admin_game_systems_path, "post"
|
||||
end
|
||||
|
||||
test "create should create new game system" do
|
||||
sign_in users(:admin)
|
||||
assert_difference "GameSystem.count", 1 do
|
||||
post admin_game_systems_path, params: { game_system: { name: "Test Game System" } }
|
||||
end
|
||||
assert_redirected_to admin_game_system_path(GameSystem.last)
|
||||
end
|
||||
|
||||
test "create should fail if game system already exists" do
|
||||
sign_in users(:admin)
|
||||
assert_no_difference "GameSystem.count" do
|
||||
post admin_game_systems_path, params: { game_system: { name: game_systems(:troika).name } }
|
||||
end
|
||||
assert_response :unprocessable_entity
|
||||
end
|
||||
|
||||
test "edit should show form to edit game system" do
|
||||
sign_in users(:admin)
|
||||
get edit_admin_game_system_path(game_systems(:troika))
|
||||
assert_response :success
|
||||
|
||||
assert_select "form[action=?][method=?]", admin_game_system_path(game_systems(:troika)), "post"
|
||||
end
|
||||
|
||||
test "update should update game system" do
|
||||
sign_in users(:admin)
|
||||
patch admin_game_system_path(game_systems(:troika)), params: { game_system: { name: "Test Game System" } }
|
||||
assert_redirected_to admin_game_system_path(game_systems(:troika))
|
||||
end
|
||||
|
||||
test "destroy should destroy game system" do
|
||||
sign_in users(:admin)
|
||||
assert_difference "GameSystem.count", -1 do
|
||||
delete admin_game_system_path(game_systems(:troika))
|
||||
end
|
||||
assert_redirected_to admin_game_systems_path
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
require "test_helper"
|
||||
|
||||
class PermissionsTest < ActionDispatch::IntegrationTest
|
||||
test "admin? returns true for users with an admin role" do
|
||||
user = users(:trevor)
|
||||
assert_not user.admin?
|
||||
|
||||
user.site_roles << site_roles(:admin)
|
||||
assert user.admin?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
require "test_helper"
|
||||
|
||||
class GameSystemTest < ActiveSupport::TestCase
|
||||
test "name must exist" do
|
||||
assert_must_exist(game_systems(:troika), :name)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
require "test_helper"
|
||||
|
||||
class UserRoleTest < ActiveSupport::TestCase
|
||||
test "name must exist" do
|
||||
assert_must_exist(site_roles(:admin), :name)
|
||||
end
|
||||
end
|
|
@ -21,5 +21,9 @@ module ActiveSupport
|
|||
def attr_name(klass, attr)
|
||||
klass.human_attribute_name(attr)
|
||||
end
|
||||
|
||||
def sign_in(user, password: "password")
|
||||
post sessions_path, params: { username: user.username, password: password }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue