class TheatresController < ApplicationController def show theatre = Theatre.find_by(id: params[:id]) return head :not_found unless theatre render json: TheatreRepr.base(theatre) end def watching return head :unauthorized unless current_user theatre = Theatre.find_by(id: params[:id]) return head :not_found unless theatre host_flg = false post_id = nil post_started_at = nil theatre.with_lock do TheatreWatchingUser.find_or_initialize_by(theatre:, user: current_user).tap { _1.expires_at = 30.seconds.from_now }.save! if (!(theatre.host_user_id?) || !(theatre.watching_users.exists?(id: theatre.host_user_id))) theatre.update!(host_user_id: current_user.id) end host_flg = theatre.host_user_id == current_user.id post_id = theatre.current_post_id post_started_at = theatre.current_post_started_at end render json: theatre_info_json(theatre, host_flg:, post_id:, post_started_at:) end def next_post return head :unauthorized unless current_user theatre = Theatre.find_by(id: params[:id]) return head :not_found unless theatre return head :forbidden if theatre.host_user != current_user ApplicationRecord.transaction do theatre.lock! TheatrePostAdvancer.call(theatre:) end head :no_content end def skip_vote return head :unauthorized unless current_user theatre = Theatre.find_by(id: params[:id]) return head :not_found unless theatre skipped = false ApplicationRecord.transaction do theatre.lock! if theatre.current_post TheatreWatchingUser.find_or_initialize_by(theatre:, user: current_user).tap { _1.expires_at = 30.seconds.from_now }.save! TheatreSkipVote.find_or_create_by!(theatre:, post: theatre.current_post, user: current_user) vote_status = skip_vote_status(theatre) if vote_status[:votes_count] >= vote_status[:required_count] TheatreSkipFinalizer.call(theatre:, user: current_user) TheatrePostAdvancer.call(theatre:) skipped = true end end end theatre.reload render json: theatre_info_json(theatre, skipped:) end def unskip_vote return head :unauthorized unless current_user theatre = Theatre.find_by(id: params[:id]) return head :not_found unless theatre if theatre.current_post TheatreSkipVote.where(theatre:, post: theatre.current_post, user: current_user).delete_all end render json: theatre_info_json(theatre, skipped: false) end def post_selection_weights theatre = Theatre.find_by(id: params[:id]) return head :not_found unless theatre render json: TheatrePostSelector.new(theatre:).weight_json end private def theatre_info_json(theatre, host_flg: nil, post_id: nil, post_started_at: nil, skipped: nil) host_flg = theatre.host_user_id == current_user&.id if host_flg.nil? post_id = theatre.current_post_id if post_id.nil? post_started_at = theatre.current_post_started_at if post_started_at.nil? json = { host_flg:, post_id:, post_started_at:, post_elapsed_ms: post_started_at ? ((Time.current - post_started_at) * 1000).floor : nil, watching_users: theatre.watching_users.as_json(only: [:id, :name]), skip_vote: skip_vote_status(theatre) } json[:skipped] = skipped unless skipped.nil? json end def skip_vote_status(theatre) watching_user_ids = theatre.watching_users.ids watching_users_count = watching_user_ids.size required_count = (watching_users_count / 2) + 1 post = theatre.current_post votes = if post TheatreSkipVote.where(theatre:, post:, user_id: watching_user_ids) else TheatreSkipVote.none end { votes_count: post ? votes.count : 0, required_count:, watching_users_count:, voted: post && current_user ? votes.exists?(user_id: current_user.id) : false } end end