169 lines
6.7 KiB
Ruby
169 lines
6.7 KiB
Ruby
class BoardsController < ApplicationController
|
||
include BoardAccessible
|
||
|
||
before_action :require_login
|
||
before_action :set_game
|
||
before_action :set_board, only: [ :show, :toggle_public ]
|
||
|
||
def index
|
||
# 参加中の掲示板(共通掲示板含む)を取得
|
||
# ゲーム終了後は履歴モードとして、過去に参加していた掲示板もすべて表示
|
||
@current_participant = @game.participants.find_by(user: current_user)
|
||
|
||
# マップ表示用:各国がどの掲示板(交渉)を持っているかのデータを作成
|
||
# { "FRANCE" => ["GERMANY", "ENGLAND"], ... } のような形式でビューに渡す
|
||
@diplomacy_matrix = build_diplomacy_matrix
|
||
|
||
if @game.status == "finished"
|
||
# 履歴モード:かつて参加していた掲示板をすべて表示
|
||
@boards = @game.boards.includes(:participants, :board_posts, :board_memberships)
|
||
.select { |b| b.member?(@current_participant) || b.global? }
|
||
.sort_by { |b| [ b.global? ? 0 : 1, b.created_at ] }
|
||
else
|
||
return redirect_to game_path(@game), alert: "参加者ではないためアクセスできません" unless @current_participant
|
||
|
||
# 進行中:参加中の掲示板のみ(eager load で N+1 防止)
|
||
@boards = @current_participant.boards.includes(:participants, :board_posts, :board_memberships).order(created_at: :desc)
|
||
# 共通掲示板のフォールバック
|
||
global_board = @game.boards.global.first
|
||
if global_board && !@boards.include?(global_board)
|
||
@boards = [ global_board ] + @boards
|
||
end
|
||
@boards = @boards.sort_by { |b| b.global? ? 0 : 1 }
|
||
end
|
||
end
|
||
|
||
def show
|
||
@current_participant = @game.participants.find_by(user: current_user)
|
||
|
||
# アクセス制御
|
||
access_allowed = false
|
||
|
||
if @board.global?
|
||
# 共通掲示板はゲーム参加者なら誰でもアクセス可能
|
||
# 未読管理のためにメンバーシップがない場合は作成する
|
||
access_allowed = true
|
||
unless @board.board_memberships.exists?(participant: @current_participant)
|
||
@board.board_memberships.create(participant: @current_participant, joined_at: Time.current)
|
||
end
|
||
elsif @board.member?(@current_participant)
|
||
access_allowed = true
|
||
elsif @game.status == "finished"
|
||
# ゲーム終了後は、元メンバーならアクセス可能(共通掲示板は上記でカバー済み)
|
||
is_past_member = @board.board_memberships.exists?(participant: @current_participant)
|
||
access_allowed = is_past_member
|
||
elsif @board.is_public?
|
||
# 公開掲示板は誰でも閲覧可能
|
||
access_allowed = true
|
||
end
|
||
|
||
unless access_allowed
|
||
return redirect_to game_boards_path(@game), alert: "権限がありません"
|
||
end
|
||
|
||
# 既読更新
|
||
if @current_participant && @board.active_memberships.exists?(participant: @current_participant)
|
||
last_post = @board.board_posts.last
|
||
if last_post
|
||
membership = @board.board_memberships.find_by(participant: @current_participant)
|
||
membership.mark_read!(last_post.id)
|
||
end
|
||
end
|
||
|
||
@posts = @board.board_posts.includes(:participant).order(created_at: :desc)
|
||
@proposals = @board.board_proposals.includes(:proposer).order(created_at: :desc)
|
||
@new_post = BoardPost.new
|
||
@new_proposal = BoardProposal.new
|
||
@active_members = @board.active_memberships.includes(:participant).map(&:participant)
|
||
|
||
# メンバー追加用:招待可能なプレイヤー一覧
|
||
if @board.negotiation? && !@board.history_mode?
|
||
existing_member_ids = @board.board_memberships.where(left_at: nil).pluck(:participant_id)
|
||
@candidates = @game.participants.where.not(id: existing_member_ids).where.not(power: nil)
|
||
end
|
||
end
|
||
|
||
def new
|
||
@board = Board.new(board_type: "negotiation")
|
||
@current_participant = @game.participants.find_by(user: current_user)
|
||
# 自分以外の参加者一覧
|
||
@participants = @game.participants.where.not(id: @current_participant.id).where.not(power: nil)
|
||
end
|
||
|
||
def create
|
||
@current_participant = @game.participants.find_by(user: current_user)
|
||
|
||
# トランザクションで掲示板作成とメンバー追加を一括実行
|
||
ActiveRecord::Base.transaction do
|
||
@board = @game.boards.new(board_params)
|
||
@board.board_type = "negotiation"
|
||
@board.created_by_participant_id = @current_participant.id
|
||
|
||
if @board.save
|
||
# 作成者をメンバーに追加
|
||
@board.board_memberships.create!(participant: @current_participant, joined_at: Time.current)
|
||
|
||
# 招待されたメンバーを追加
|
||
if params[:invited_participant_ids].present?
|
||
params[:invited_participant_ids].each do |pid|
|
||
@board.board_memberships.create!(participant_id: pid, joined_at: Time.current)
|
||
end
|
||
end
|
||
|
||
redirect_to game_board_path(@game, @board), notice: "交渉用掲示板を作成しました"
|
||
else
|
||
@participants = @game.participants.where.not(id: @current_participant.id).where.not(power: nil)
|
||
render :new, status: :unprocessable_entity
|
||
end
|
||
end
|
||
rescue ActiveRecord::RecordInvalid
|
||
@participants = @game.participants.where.not(id: @current_participant.id).where.not(power: nil)
|
||
render :new, status: :unprocessable_entity
|
||
end
|
||
|
||
def toggle_public
|
||
# 公開宣言機能(追加提案)
|
||
@current_participant = @game.participants.find_by(user: current_user)
|
||
unless @board.member?(@current_participant)
|
||
return redirect_to game_board_path(@game, @board), alert: "権限がありません"
|
||
end
|
||
|
||
@board.update(is_public: !@board.is_public)
|
||
status = @board.is_public ? "公開" : "非公開"
|
||
redirect_to game_board_path(@game, @board), notice: "掲示板を#{status}に設定しました"
|
||
end
|
||
|
||
private
|
||
|
||
def board_params
|
||
params.fetch(:board, {}).permit(:is_public)
|
||
end
|
||
|
||
def build_diplomacy_matrix
|
||
powers = @game.participants.where.not(power: nil).pluck(:power)
|
||
matrix = {}
|
||
powers.each { |p| matrix[p] = [] }
|
||
|
||
# 自分が参加している掲示板・公開された掲示板の関係を表示
|
||
visible_boards = @game.boards.negotiation.includes(:participants, :board_memberships)
|
||
|
||
visible_boards.each do |board|
|
||
# アクセス権チェック(簡易)
|
||
is_member = board.board_memberships.exists?(participant: @current_participant, left_at: nil)
|
||
next unless is_member || board.is_public || @game.status == "finished"
|
||
|
||
# メンバー間のリンクを作成
|
||
members = board.participants.pluck(:power)
|
||
members.each do |p1|
|
||
members.each do |p2|
|
||
next if p1 == p2
|
||
matrix[p1] ||= []
|
||
matrix[p1] << p2 unless matrix[p1].include?(p2)
|
||
end
|
||
end
|
||
end
|
||
|
||
matrix
|
||
end
|
||
end
|