フロントエンドプレイアブル
This commit is contained in:
33
app/controllers/application_controller.rb
Normal file
33
app/controllers/application_controller.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
class ApplicationController < ActionController::Base
|
||||
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
|
||||
allow_browser versions: :modern
|
||||
|
||||
# Changes to the importmap will invalidate the etag for HTML responses
|
||||
stale_when_importmap_changes
|
||||
|
||||
helper_method :current_user, :logged_in?
|
||||
|
||||
private
|
||||
|
||||
def current_user
|
||||
@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
|
||||
end
|
||||
|
||||
def logged_in?
|
||||
current_user.present?
|
||||
end
|
||||
|
||||
def require_login
|
||||
unless logged_in?
|
||||
flash[:alert] = "ログインが必要です"
|
||||
redirect_to login_path
|
||||
end
|
||||
end
|
||||
|
||||
def require_admin
|
||||
unless logged_in? && current_user.admin?
|
||||
flash[:alert] = "管理者権限が必要です"
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
end
|
||||
0
app/controllers/concerns/.keep
Normal file
0
app/controllers/concerns/.keep
Normal file
62
app/controllers/game_participants_controller.rb
Normal file
62
app/controllers/game_participants_controller.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
class GameParticipantsController < ApplicationController
|
||||
before_action :set_game
|
||||
before_action :require_login
|
||||
before_action :require_participant, only: [:select_power]
|
||||
|
||||
# POST /games/1/game_participants/select_power
|
||||
def select_power
|
||||
power_name = params[:power_name]
|
||||
|
||||
unless power_name.present?
|
||||
redirect_to @game, alert: "国を選択してください"
|
||||
return
|
||||
end
|
||||
|
||||
# 利用可能な国のリストを取得
|
||||
available_powers = get_available_powers
|
||||
|
||||
unless available_powers.include?(power_name)
|
||||
redirect_to @game, alert: "無効な国です"
|
||||
return
|
||||
end
|
||||
|
||||
# 既に選択されているかチェック
|
||||
if @game.game_participants.exists?(power: power_name)
|
||||
redirect_to @game, alert: "その国は既に選択されています"
|
||||
return
|
||||
end
|
||||
|
||||
# 国を選択
|
||||
@current_participant.select_power!(power_name)
|
||||
|
||||
# 全員が選択したかチェック
|
||||
if @game.can_start_order_input?
|
||||
redirect_to @game, notice: "国を選択しました。全員の選択が完了しました!"
|
||||
else
|
||||
redirect_to @game, notice: "国を選択しました。他のプレイヤーの選択を待っています..."
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_game
|
||||
@game = Game.find(params[:game_id])
|
||||
@current_participant = current_user && @game.game_participants.find_by(user: current_user)
|
||||
end
|
||||
|
||||
def require_participant
|
||||
unless @current_participant
|
||||
redirect_to @game, alert: "このゲームに参加していません"
|
||||
end
|
||||
end
|
||||
|
||||
def get_available_powers
|
||||
# ディプロマシーの標準的な国
|
||||
standard_powers = %w[Austria England France Germany Italy Russia Turkey]
|
||||
|
||||
# 既に選択されている国を除外
|
||||
selected_powers = @game.game_participants.where.not(power: nil).pluck(:power)
|
||||
|
||||
standard_powers - selected_powers
|
||||
end
|
||||
end
|
||||
421
app/controllers/games_controller.rb
Normal file
421
app/controllers/games_controller.rb
Normal file
@@ -0,0 +1,421 @@
|
||||
class GamesController < ApplicationController
|
||||
include GamesHelper
|
||||
before_action :set_game, only: %i[ show edit update destroy join_game start_power_selection start_order_input turn_data vote_draw force_draw ]
|
||||
before_action :require_login, only: %i[ new create join_game ]
|
||||
before_action :require_game_admin, only: %i[ edit update destroy start_power_selection start_order_input ]
|
||||
|
||||
helper_method :get_available_powers_for_select
|
||||
|
||||
# GET /games or /games.json
|
||||
def index
|
||||
@recruiting_games = Game.where(status: "recruiting").includes(:participants)
|
||||
@my_games = current_user ? Game.joins(:participants).where(participants: { user_id: current_user.id }).includes(:participants, :turns) : []
|
||||
@games = Game.all.includes(:participants, :turns)
|
||||
end
|
||||
|
||||
# GET /games/1 or /games/1.json
|
||||
def show
|
||||
@latest_turn = @game.turns.last
|
||||
|
||||
# ゲーム終了判定
|
||||
@game_finished = @game.status == "finished"
|
||||
|
||||
# 表示するターンの決定
|
||||
if @game_finished
|
||||
# 終了済みの場合:
|
||||
# params[:turn_number] があればそのターン
|
||||
# なければ 最初のターン (Turn 1) を表示
|
||||
if params[:turn_number].present?
|
||||
@display_turn = @game.turns.find_by(number: params[:turn_number].to_i)
|
||||
end
|
||||
|
||||
# 指定がない、または見つからない場合は初期ターン(number=1)を表示
|
||||
# もし存在しなければ最新(というかあるやつ)
|
||||
@display_turn ||= @game.turns.find_by(number: 1) || @latest_turn
|
||||
|
||||
# 最終結果の取得 (最後のターン情報から)
|
||||
if @latest_turn.game_state
|
||||
centers = @latest_turn.game_state["centers"] || {}
|
||||
alive_powers = centers.keys
|
||||
|
||||
# ソロ勝利判定
|
||||
solo_winner = @game.solo_victory_power(@latest_turn.game_state)
|
||||
if solo_winner
|
||||
result_type = "Solo Victory"
|
||||
winners = [ solo_winner ]
|
||||
else
|
||||
result_type = "Draw"
|
||||
winners = alive_powers
|
||||
end
|
||||
|
||||
@winner_info = {
|
||||
type: result_type,
|
||||
winners: winners,
|
||||
scores: @game.calculate_scores(@latest_turn.game_state)
|
||||
}
|
||||
end
|
||||
else
|
||||
# 進行中の場合: params[:turn_number] があればそのターン、なければ最新ターンを表示
|
||||
if params[:turn_number].present?
|
||||
@display_turn = @game.turns.find_by(number: params[:turn_number].to_i)
|
||||
end
|
||||
@display_turn ||= @latest_turn
|
||||
end
|
||||
|
||||
if @display_turn
|
||||
@game_state = @display_turn.game_state
|
||||
|
||||
# フェーズ名のパース
|
||||
@current_season_year = parse_phase(@display_turn.phase)
|
||||
|
||||
# 国別情報の集計 (表示対象ターンのデータ)
|
||||
centers = @game_state["centers"] || {}
|
||||
units = @game_state["units"] || {}
|
||||
|
||||
# 全7カ国(固定)
|
||||
powers = %w[AUSTRIA ENGLAND FRANCE GERMANY ITALY RUSSIA TURKEY]
|
||||
|
||||
@country_statuses = powers.map do |power|
|
||||
participant = @game.participants.find_by(power: power)
|
||||
# 終了済みなら全員完了扱い、そうでなければターンごとの提出状況
|
||||
submitted = @game_finished ? true : @display_turn.orders_submitted_for?(power)
|
||||
|
||||
{
|
||||
power: power,
|
||||
sc_count: centers[power]&.size || 0,
|
||||
unit_count: units[power]&.size || 0,
|
||||
submitted: submitted,
|
||||
participant: participant,
|
||||
is_user: current_user && participant&.user_id == current_user.id
|
||||
}
|
||||
end
|
||||
|
||||
# 自国を先頭に移動
|
||||
if current_user
|
||||
user_power_index = @country_statuses.find_index { |s| s[:is_user] }
|
||||
if user_power_index
|
||||
user_status = @country_statuses.delete_at(user_power_index)
|
||||
@country_statuses.unshift(user_status)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# GET /games/new
|
||||
def new
|
||||
@game = Game.new
|
||||
@game.is_solo_mode = current_user&.admin? ? false : false
|
||||
end
|
||||
|
||||
# GET /games/1/edit
|
||||
def edit
|
||||
end
|
||||
|
||||
# POST /games or /games.json
|
||||
def create
|
||||
@game = Game.new(game_params)
|
||||
|
||||
# ソロモードかどうかを判定(管理者のみ選択可能)
|
||||
if current_user&.admin? && params.dig(:game, :game_mode) == "admin_mode"
|
||||
@game.is_solo_mode = true
|
||||
else
|
||||
@game.is_solo_mode = false
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
if @game.save
|
||||
# ゲーム作成者は自動的に参加者として登録(管理者として)
|
||||
Participant.create!(
|
||||
game: @game,
|
||||
user: current_user,
|
||||
is_administrator: true
|
||||
)
|
||||
|
||||
# ソロモードの場合、即座に最初のターンを作成
|
||||
if @game.solo_mode?
|
||||
service = GameSetupService.new(@game)
|
||||
result = service.setup_initial_turn
|
||||
if result[:success]
|
||||
@game.update!(status: "in_progress")
|
||||
else
|
||||
# 失敗したらロールバックしたいところだが・・・
|
||||
# 現状はsave後なので、エラー表示だけにするかdestroyするか。
|
||||
# 今回は簡易的にログに残す
|
||||
logger.error result[:message]
|
||||
end
|
||||
end
|
||||
|
||||
format.html { redirect_to @game, notice: "ゲームが正常に作成されました。" }
|
||||
format.json { render :show, status: :created, location: @game }
|
||||
else
|
||||
format.html { render :new, status: :unprocessable_entity }
|
||||
format.json { render json: @game.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /games/1 or /games/1.json
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @game.update(game_params)
|
||||
# スケジュール変更時にデッドラインを再計算
|
||||
if @game.status == "in_progress"
|
||||
@game.update_column(:next_deadline_at, @game.auto_turn? ? @game.calculate_next_deadline : nil)
|
||||
end
|
||||
format.html { redirect_to @game, notice: "ゲームが正常に更新されました。", status: :see_other }
|
||||
format.json { render :show, status: :ok, location: @game }
|
||||
else
|
||||
format.html { render :edit, status: :unprocessable_entity }
|
||||
format.json { render json: @game.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /games/1 or /games/1.json
|
||||
def destroy
|
||||
@game.destroy!
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to games_path, notice: "ゲームが正常に削除されました。", status: :see_other }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
# POST /games/1/join
|
||||
def join_game
|
||||
unless current_user
|
||||
redirect_to login_path, alert: "ゲームに参加するにはログインしてください"
|
||||
return
|
||||
end
|
||||
|
||||
# パスワードチェック
|
||||
if @game.password_protected?
|
||||
password = params.dig(:participant, :password)
|
||||
unless @game.authenticate_password(password)
|
||||
redirect_to @game, alert: "パスワードが正しくありません"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# 既に参加しているかチェック
|
||||
if @game.participants.exists?(user: current_user)
|
||||
redirect_to @game, alert: "既にこのゲームに参加しています"
|
||||
return
|
||||
end
|
||||
|
||||
# 満員チェック
|
||||
if @game.participants.count >= @game.participants_count
|
||||
redirect_to @game, alert: "このゲームは満員です"
|
||||
return
|
||||
end
|
||||
|
||||
# 参加者を作成
|
||||
Participant.create!(
|
||||
game: @game,
|
||||
user: current_user
|
||||
)
|
||||
|
||||
# 定員到達チェック
|
||||
if @game.participants.count == @game.participants_count
|
||||
@game.update(status: "power_selection")
|
||||
end
|
||||
|
||||
redirect_to @game, notice: "ゲームに正常に参加しました!"
|
||||
end
|
||||
|
||||
# POST /games/1/start_power_selection
|
||||
def start_power_selection
|
||||
unless @game.participants.count >= 2
|
||||
redirect_to @game, alert: "最低2人の参加者が必要です"
|
||||
return
|
||||
end
|
||||
|
||||
@game.update!(status: "power_selection")
|
||||
redirect_to @game, notice: "国選択フェーズを開始しました!"
|
||||
end
|
||||
|
||||
# POST /games/1/start_order_input
|
||||
def start_order_input
|
||||
unless @game.all_powers_assigned?
|
||||
redirect_to @game, alert: "全員が国を選択する必要があります"
|
||||
return
|
||||
end
|
||||
|
||||
# 最初のターンを作成
|
||||
service = GameSetupService.new(@game)
|
||||
result = service.setup_initial_turn
|
||||
|
||||
if result[:success]
|
||||
update_attrs = { status: "in_progress" }
|
||||
update_attrs[:next_deadline_at] = @game.calculate_next_deadline if @game.auto_turn?
|
||||
@game.update!(update_attrs)
|
||||
redirect_to @game, notice: "命令入力フェーズを開始しました!"
|
||||
else
|
||||
redirect_to @game, alert: result[:message]
|
||||
end
|
||||
end
|
||||
|
||||
# GET /games/1/turn_data.json
|
||||
def turn_data
|
||||
if params[:turn_number].present?
|
||||
target_turn = @game.turns.find_by(number: params[:turn_number])
|
||||
end
|
||||
target_turn ||= @game.turns.last
|
||||
|
||||
return head :not_found unless target_turn
|
||||
|
||||
# 国別ステータス情報の再計算(JSON用)
|
||||
# showアクションと同様のロジック
|
||||
game_state = target_turn.game_state
|
||||
centers = game_state["centers"] || {}
|
||||
units = game_state["units"] || {}
|
||||
powers = %w[AUSTRIA ENGLAND FRANCE GERMANY ITALY RUSSIA TURKEY]
|
||||
|
||||
country_statuses = powers.map do |power|
|
||||
# 終了済みなら全員完了扱い
|
||||
submitted = @game.status == "finished" ? true : target_turn.orders_submitted_for?(power)
|
||||
{
|
||||
power: power,
|
||||
sc_count: centers[power]&.size || 0,
|
||||
unit_count: units[power]&.size || 0,
|
||||
submitted: submitted
|
||||
}
|
||||
end
|
||||
|
||||
render json: {
|
||||
turn_number: target_turn.number,
|
||||
phase: target_turn.phase,
|
||||
possible_orders: target_turn.possible_orders,
|
||||
decided_orders: target_turn.orders || {},
|
||||
svg_orders: target_turn.svg_orders || {},
|
||||
# svg_date カラムにデフォルトSVGが入っていると仮定(または svg_orders["NONE"])
|
||||
# ここでは svg_date が単一の画像パスかSVG文字列かによるが、
|
||||
# 既存の show.html.erb 実装を見ると svg_orders["NONE"] を使っている可能性が高い
|
||||
# 既存実装: default_svg: last_turn.svg_date となっていたのでそのまま変更なしでいくが
|
||||
# target_turn.svg_date を返すようにする
|
||||
default_svg: target_turn.svg_date,
|
||||
|
||||
# 完了状況
|
||||
all_orders_submitted: @game.status == "finished" || @game.all_orders_submitted?,
|
||||
missing_orders_powers: @game.status == "finished" ? [] : @game.participants.where(orders_submitted: false).pluck(:power).compact,
|
||||
country_statuses: country_statuses
|
||||
}
|
||||
end
|
||||
|
||||
def vote_draw
|
||||
return unless @game.status == "in_progress"
|
||||
|
||||
turn = @game.turns.last
|
||||
participant = @game.participants.find_by(user: current_user)
|
||||
|
||||
unless participant && participant.power
|
||||
redirect_to @game, alert: "権限がありません。"
|
||||
return
|
||||
end
|
||||
|
||||
power = participant.power
|
||||
if turn.draw_voted?(power)
|
||||
turn.revoke_draw_vote(power)
|
||||
flash[:notice] = "引き分け投票を取り消しました。"
|
||||
else
|
||||
turn.vote_draw(power)
|
||||
flash[:notice] = "引き分けに投票しました。"
|
||||
end
|
||||
|
||||
if turn.unanimous_draw?
|
||||
if execute_draw(turn)
|
||||
flash[:notice] = "全会一致により、ゲームは引き分けとなりました。"
|
||||
else
|
||||
# エラーメッセージは execute_draw 内で flash[:alert] に設定される
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to @game
|
||||
end
|
||||
|
||||
def force_draw
|
||||
return unless current_user.admin?
|
||||
|
||||
turn = @game.turns.last
|
||||
if execute_draw(turn)
|
||||
redirect_to @game, notice: "ゲームを強制的に引き分けにしました。"
|
||||
else
|
||||
redirect_to @game
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def execute_draw(turn)
|
||||
client = GameApiClient.new
|
||||
# 生存国を勝者として扱う(引き分け)
|
||||
winners = turn.powers
|
||||
begin
|
||||
response = client.api_game_draw(turn.game_state, winners: winners)
|
||||
|
||||
if response
|
||||
# 新しいターン(完了状態)を作成
|
||||
Turn.create!(
|
||||
game: @game,
|
||||
number: turn.number + 1,
|
||||
# year, season カラムは存在しないため削除
|
||||
# phase を COMPLETED に設定
|
||||
game_state: response,
|
||||
orders: {},
|
||||
possible_orders: {},
|
||||
phase: "COMPLETED",
|
||||
svg_date: turn.svg_date,
|
||||
svg_orders: turn.svg_orders
|
||||
)
|
||||
@game.update(status: "finished")
|
||||
true
|
||||
else
|
||||
flash[:alert] = "ゲームサーバーからの応答が不正です。"
|
||||
false
|
||||
end
|
||||
rescue Faraday::ConnectionFailed => e
|
||||
flash[:alert] = "ゲームサーバーへの接続に失敗しました。管理者へ連絡してください。"
|
||||
Rails.logger.error "API Connection Failed: #{e.message}"
|
||||
false
|
||||
rescue Faraday::TimeoutError => e
|
||||
flash[:alert] = "ゲームサーバーとの通信がタイムアウトしました。"
|
||||
Rails.logger.error "API Timeout: #{e.message}"
|
||||
false
|
||||
rescue StandardError => e
|
||||
flash[:alert] = "予期せぬエラーが発生しました: #{e.message}"
|
||||
Rails.logger.error "Execute Draw Error: #{e.message}"
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def set_game
|
||||
@game = Game.find(params.expect(:id))
|
||||
end
|
||||
|
||||
def require_game_admin
|
||||
unless current_user&.admin? || @game.administrator == current_user
|
||||
redirect_to @game, alert: "ゲーム管理者のみこの機能にアクセスできます"
|
||||
end
|
||||
end
|
||||
|
||||
def game_params
|
||||
house_rules = [ :year_limit, :victory_sc_count, :scoring_system, :turn_schedule ]
|
||||
|
||||
if action_name == "update"
|
||||
params.expect(game: [ :title, :memo, :auto_order_mode ] + house_rules)
|
||||
else
|
||||
permitted = [ :title, :memo ] + house_rules
|
||||
|
||||
if current_user&.admin?
|
||||
permitted += [ :participants_count, :password, :auto_order_mode ]
|
||||
else
|
||||
# 一般ユーザーはマルチプレイヤーモードのみ
|
||||
permitted += [ :participants_count, :password, :auto_order_mode ]
|
||||
end
|
||||
|
||||
params.expect(game: permitted)
|
||||
end
|
||||
end
|
||||
end
|
||||
87
app/controllers/participants_controller.rb
Normal file
87
app/controllers/participants_controller.rb
Normal file
@@ -0,0 +1,87 @@
|
||||
class ParticipantsController < ApplicationController
|
||||
before_action :set_game
|
||||
|
||||
# POST /games/:game_id/participants
|
||||
def create
|
||||
# パスワード確認
|
||||
if @game.password_protected?
|
||||
unless @game.authenticate_password(params[:password])
|
||||
redirect_to @game, alert: "パスワードが正しくありません"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
# 参加処理
|
||||
@participant = @game.participants.build(
|
||||
user: current_user,
|
||||
is_administrator: false
|
||||
)
|
||||
|
||||
if @participant.save
|
||||
# 定員到達チェック
|
||||
if @game.participants.count == @game.participants_count
|
||||
@game.update(status: "power_selection")
|
||||
end
|
||||
|
||||
redirect_to @game, notice: "ゲームに参加しました"
|
||||
else
|
||||
redirect_to @game, alert: @participant.errors.full_messages.join(", ")
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH /games/:game_id/participants/:id/select_power
|
||||
def select_power
|
||||
@participant = @game.participants.find(params[:id])
|
||||
|
||||
unless @participant.user == current_user
|
||||
redirect_to @game, alert: "権限がありません"
|
||||
return
|
||||
end
|
||||
|
||||
if @participant.update(power: params[:power])
|
||||
# 全員が国を選択したかチェック
|
||||
if @game.all_powers_assigned?
|
||||
service = GameSetupService.new(@game)
|
||||
result = service.setup_initial_turn
|
||||
|
||||
if result[:success]
|
||||
@game.update(status: "in_progress")
|
||||
flash[:notice] = "国を選択し、ゲームが開始されました!"
|
||||
else
|
||||
flash[:alert] = "ゲーム開始に失敗しました: #{result[:message]}"
|
||||
end
|
||||
else
|
||||
flash[:notice] = "国を選択しました"
|
||||
end
|
||||
|
||||
redirect_to @game
|
||||
else
|
||||
redirect_to @game, alert: @participant.errors.full_messages.join(", ")
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /games/:game_id/participants/:id
|
||||
def destroy
|
||||
@participant = @game.participants.find(params[:id])
|
||||
|
||||
unless @participant.user == current_user || current_user&.admin?
|
||||
redirect_to @game, alert: "権限がありません"
|
||||
return
|
||||
end
|
||||
|
||||
@participant.destroy
|
||||
|
||||
# ゲーム状態を更新
|
||||
if @game.status == "power_selection"
|
||||
@game.update(status: "recruiting")
|
||||
end
|
||||
|
||||
redirect_to games_path, notice: "ゲームから退出しました"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_game
|
||||
@game = Game.find(params[:game_id])
|
||||
end
|
||||
end
|
||||
22
app/controllers/sessions_controller.rb
Normal file
22
app/controllers/sessions_controller.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
class SessionsController < ApplicationController
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
user = User.find_by(email: params[:email]&.downcase)
|
||||
if user&.authenticate(params[:password])
|
||||
session[:user_id] = user.id
|
||||
flash[:notice] = "ログインしました"
|
||||
redirect_to root_path
|
||||
else
|
||||
flash.now[:alert] = "メールアドレスまたはパスワードが正しくありません"
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
session[:user_id] = nil
|
||||
flash[:notice] = "ログアウトしました"
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
108
app/controllers/turns_controller.rb
Normal file
108
app/controllers/turns_controller.rb
Normal file
@@ -0,0 +1,108 @@
|
||||
class TurnsController < ApplicationController
|
||||
before_action :require_login
|
||||
before_action :set_turn, only: %i[ show edit update destroy submit_orders process_turn ]
|
||||
|
||||
# GET /turns or /turns.json
|
||||
def index
|
||||
@turns = Turn.all
|
||||
end
|
||||
|
||||
# GET /turns/1 or /turns/1.json
|
||||
def show
|
||||
end
|
||||
|
||||
# GET /turns/new
|
||||
def new
|
||||
@turn = Turn.new
|
||||
end
|
||||
|
||||
# GET /turns/1/edit
|
||||
def edit
|
||||
end
|
||||
|
||||
# POST /turns or /turns.json
|
||||
def create
|
||||
@turn = Turn.new(turn_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @turn.save
|
||||
format.html { redirect_to @turn, notice: "Turn was successfully created." }
|
||||
format.json { render :show, status: :created, location: @turn }
|
||||
else
|
||||
format.html { render :new, status: :unprocessable_entity }
|
||||
format.json { render json: @turn.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /turns/1 or /turns/1.json
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @turn.update(turn_params)
|
||||
format.html { redirect_to @turn, notice: "Turn was successfully updated.", status: :see_other }
|
||||
format.json { render :show, status: :ok, location: @turn }
|
||||
else
|
||||
format.html { render :edit, status: :unprocessable_entity }
|
||||
format.json { render json: @turn.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /turns/1 or /turns/1.json
|
||||
def destroy
|
||||
@turn.destroy!
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to turns_path, notice: "Turn was successfully destroyed.", status: :see_other }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH /turns/1/submit_orders
|
||||
def submit_orders
|
||||
@turn = Turn.find(params[:id])
|
||||
power = params[:power]
|
||||
orders = params[:orders]&.permit!&.to_h || {}
|
||||
|
||||
service = OrderSubmissionService.new(@turn, current_user)
|
||||
result = service.submit(power: power, orders: orders)
|
||||
|
||||
if result[:success]
|
||||
redirect_to game_path(@turn.game), notice: result[:message]
|
||||
else
|
||||
redirect_to game_path(@turn.game), alert: result[:message]
|
||||
end
|
||||
end
|
||||
|
||||
# POST /turns/1/process_turn
|
||||
def process_turn
|
||||
@turn = Turn.find(params[:id])
|
||||
@game = @turn.game
|
||||
|
||||
# Check admin/turn ending permissions
|
||||
unless @game.solo_mode? || current_user&.admin? || @game.administrator == current_user
|
||||
redirect_to game_path(@game), alert: "ゲーム管理者のみターンを終了できます"
|
||||
return
|
||||
end
|
||||
|
||||
service = TurnProcessingService.new(@turn)
|
||||
result = service.process(force: params[:force])
|
||||
|
||||
if result[:success]
|
||||
redirect_to game_path(@game), notice: result[:message]
|
||||
else
|
||||
redirect_to game_path(@game), alert: result[:message]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_turn
|
||||
@turn = Turn.find(params.expect(:id))
|
||||
end
|
||||
|
||||
# Only allow a list of trusted parameters through.
|
||||
def turn_params
|
||||
params.expect(turn: [ :number, :phase, :game_state, :svg_date, :game_id, :possible_orders, :orders ])
|
||||
end
|
||||
end
|
||||
88
app/controllers/users_controller.rb
Normal file
88
app/controllers/users_controller.rb
Normal file
@@ -0,0 +1,88 @@
|
||||
class UsersController < ApplicationController
|
||||
before_action :require_admin, only: [:index, :destroy, :toggle_admin]
|
||||
before_action :set_user, only: [:show, :edit, :update, :destroy, :toggle_admin]
|
||||
before_action :require_admin_or_owner, only: [:show, :edit, :update]
|
||||
|
||||
def index
|
||||
@users = User.all.order(created_at: :desc)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def new
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.new(user_params)
|
||||
if @user.save
|
||||
session[:user_id] = @user.id
|
||||
flash[:notice] = "アカウントを作成しました"
|
||||
redirect_to root_path
|
||||
else
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
# パスワードが空の場合は更新しない
|
||||
if user_update_params[:password].blank?
|
||||
user_update_params.delete(:password)
|
||||
user_update_params.delete(:password_confirmation)
|
||||
end
|
||||
|
||||
if @user.update(user_update_params)
|
||||
flash[:notice] = "ユーザー情報を更新しました"
|
||||
redirect_to user_path(@user)
|
||||
else
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @user == current_user
|
||||
flash[:alert] = "自分自身を削除することはできません"
|
||||
redirect_to users_path
|
||||
else
|
||||
@user.destroy
|
||||
flash[:notice] = "ユーザーを削除しました"
|
||||
redirect_to users_path
|
||||
end
|
||||
end
|
||||
|
||||
def toggle_admin
|
||||
if @user == current_user
|
||||
flash[:alert] = "自分自身の管理者権限は変更できません"
|
||||
else
|
||||
@user.update(admin: !@user.admin)
|
||||
flash[:notice] = "管理者権限を#{@user.admin? ? '付与' : '削除'}しました"
|
||||
end
|
||||
redirect_to users_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_user
|
||||
@user = User.find(params[:id])
|
||||
end
|
||||
|
||||
def require_admin_or_owner
|
||||
unless current_user&.admin? || current_user == @user
|
||||
flash[:alert] = "アクセス権限がありません"
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:username, :email, :password, :password_confirmation)
|
||||
end
|
||||
|
||||
def user_update_params
|
||||
# メールアドレスは変更不可
|
||||
params.require(:user).permit(:username, :password, :password_confirmation)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user