diff --git a/app/controllers/admin/game_systems_controller.rb b/app/controllers/admin/game_systems_controller.rb new file mode 100644 index 0000000..e689198 --- /dev/null +++ b/app/controllers/admin/game_systems_controller.rb @@ -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 diff --git a/app/models/game_system.rb b/app/models/game_system.rb index 0086c99..2852549 100644 --- a/app/models/game_system.rb +++ b/app/models/game_system.rb @@ -1,3 +1,5 @@ class GameSystem < ApplicationRecord - validates :name, presence: true + validates :name, presence: true, + uniqueness: true, + length: { maximum: 100 } end diff --git a/app/views/admin/game_systems/_form.html.erb b/app/views/admin/game_systems/_form.html.erb new file mode 100644 index 0000000..1367e21 --- /dev/null +++ b/app/views/admin/game_systems/_form.html.erb @@ -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 %> diff --git a/app/views/admin/game_systems/edit.html.erb b/app/views/admin/game_systems/edit.html.erb new file mode 100644 index 0000000..192c22c --- /dev/null +++ b/app/views/admin/game_systems/edit.html.erb @@ -0,0 +1,4 @@ +

<%= t(".edit", name: @game_system.name) %>

+ +<%= render partial: "form", + locals: { button_text: t(".update", name: @game_system.name), url: admin_game_system_path(@game_system) } %> diff --git a/app/views/admin/game_systems/index.html.erb b/app/views/admin/game_systems/index.html.erb new file mode 100644 index 0000000..7cee350 --- /dev/null +++ b/app/views/admin/game_systems/index.html.erb @@ -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| %> +
class="game-system"> + <%= link_to game_system.name, admin_game_system_path(game_system) %> +
+<% end %> diff --git a/app/views/admin/game_systems/new.html.erb b/app/views/admin/game_systems/new.html.erb new file mode 100644 index 0000000..8edf44e --- /dev/null +++ b/app/views/admin/game_systems/new.html.erb @@ -0,0 +1,3 @@ +

<%= t(".new") %>

+ +<%= render partial: "form", locals: { button_text: t(".create"), url: admin_game_systems_path } %> diff --git a/app/views/admin/game_systems/show.html.erb b/app/views/admin/game_systems/show.html.erb new file mode 100644 index 0000000..253ef1f --- /dev/null +++ b/app/views/admin/game_systems/show.html.erb @@ -0,0 +1,6 @@ +

<%= @game_system.name %>

+ +<%= 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) } %> diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb index 6547a62..a059c52 100644 --- a/app/views/admin/index.html.erb +++ b/app/views/admin/index.html.erb @@ -1 +1,2 @@ +<% content_for :title, t(".dashboard") %> <%= t(".intro") %> diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index 2f4221c..fc31da2 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb @@ -2,6 +2,8 @@

<%= t("administration") %>: <%= content_for :title %>

<% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9e66d07..5562422 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -31,6 +31,7 @@ <%= render partial: "shared/flash_messages" %>
+ <%= yield(:submenu) if content_for?(:submenu) %> <%= yield %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 69e293e..e423344 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -5,7 +5,12 @@ en: 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: | @@ -18,7 +23,30 @@ en: 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}!" diff --git a/config/routes.rb b/config/routes.rb index dad18fd..e28f5f1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -13,6 +13,9 @@ Rails.application.routes.draw do 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 diff --git a/db/migrate/20240526102908_add_unique_index_to_game_system_name.rb b/db/migrate/20240526102908_add_unique_index_to_game_system_name.rb new file mode 100644 index 0000000..a86ad43 --- /dev/null +++ b/db/migrate/20240526102908_add_unique_index_to_game_system_name.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 1b3dfdf..7beccff 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_26_085315) 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" @@ -18,6 +18,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_26_085315) do 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| diff --git a/test/controllers/admin/game_systems_controller_test.rb b/test/controllers/admin/game_systems_controller_test.rb new file mode 100644 index 0000000..e9c3ef7 --- /dev/null +++ b/test/controllers/admin/game_systems_controller_test.rb @@ -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 diff --git a/test/integration/admin_game_systems_integration_test.rb b/test/integration/admin_game_systems_integration_test.rb new file mode 100644 index 0000000..a0f7885 --- /dev/null +++ b/test/integration/admin_game_systems_integration_test.rb @@ -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