# frozen_string_literal: true module Api module V1 class CrewsController < Api::V1::ApiController include CrewAuthorizationConcern before_action :restrict_access before_action :set_crew, only: %i[show update members roster leave transfer_captain] before_action :require_crew!, only: %i[show update members roster] before_action :authorize_crew_member!, only: %i[show members] before_action :authorize_crew_officer!, only: %i[update roster] before_action :authorize_crew_captain!, only: %i[transfer_captain] # GET /crew or GET /crews/:id def show render json: CrewBlueprint.render(@crew, view: :full, root: :crew, current_user: current_user) end # POST /crews def create raise CrewErrors::AlreadyInCrewError if current_user.crew.present? @crew = Crew.new(crew_params) ActiveRecord::Base.transaction do @crew.save! CrewMembership.create!(crew: @crew, user: current_user, role: :captain) end render json: CrewBlueprint.render(@crew.reload, view: :full, root: :crew, current_user: current_user), status: :created end # PUT /crew def update if @crew.update(crew_params) render json: CrewBlueprint.render(@crew, view: :full, root: :crew, current_user: current_user) else render_validation_error_response(@crew) end end # GET /crew/members # Params: # filter: 'active' (default), 'retired', 'phantom', 'all' def members filter = params[:filter]&.to_sym || :active case filter when :active members = @crew.active_memberships.includes(:user).order(role: :desc, created_at: :asc) phantoms = @crew.phantom_players.not_deleted.active.includes(:claimed_by).order(:name) when :retired members = @crew.crew_memberships.retired.includes(:user).order(retired_at: :desc) phantoms = @crew.phantom_players.not_deleted.retired.includes(:claimed_by).order(:name) when :phantom members = [] phantoms = @crew.phantom_players.not_deleted.includes(:claimed_by).order(:name) when :all members = @crew.crew_memberships.includes(:user).order(role: :desc, retired: :asc, created_at: :asc) phantoms = @crew.phantom_players.not_deleted.includes(:claimed_by).order(:name) else members = @crew.active_memberships.includes(:user).order(role: :desc, created_at: :asc) phantoms = @crew.phantom_players.not_deleted.active.includes(:claimed_by).order(:name) end render json: { members: CrewMembershipBlueprint.render_as_hash(members, view: :with_user), phantoms: PhantomPlayerBlueprint.render_as_hash(phantoms, view: :with_claimed_by) } end # POST /crew/leave def leave membership = current_user.active_crew_membership raise CrewErrors::NotInCrewError unless membership raise CrewErrors::CaptainCannotLeaveError if membership.captain? membership.retire! head :no_content end # GET /crew/roster # Returns collection ownership for crew members based on requested item IDs # Params: character_ids[], weapon_ids[], summon_ids[] def roster members = @crew.active_memberships.includes(:user) render json: { members: members.map { |m| build_member_roster(m) } } end # POST /crews/:id/transfer_captain def transfer_captain new_captain_id = params[:user_id] new_captain_membership = @crew.active_memberships.find_by(user_id: new_captain_id) raise CrewErrors::MemberNotFoundError unless new_captain_membership ActiveRecord::Base.transaction do current_user.active_crew_membership.update!(role: :vice_captain) new_captain_membership.update!(role: :captain) end render json: CrewBlueprint.render(@crew.reload, view: :full, root: :crew, current_user: current_user) end private def set_crew @crew = if params[:id] Crew.find(params[:id]) else current_user&.crew end end def crew_params params.require(:crew).permit(:name, :gamertag, :granblue_crew_id, :description) end def require_crew! render_not_found_response('crew') unless @crew end def build_member_roster(membership) user = membership.user { user_id: user.id, username: user.username, role: membership.role, characters: find_collection_items(user, :characters), weapons: find_collection_items(user, :weapons), summons: find_collection_items(user, :summons) } end def find_collection_items(user, type) ids = params["#{type.to_s.singularize}_ids"] return [] if ids.blank? collection = case type when :characters then user.collection_characters.includes(:character).where(character_id: ids) when :weapons then user.collection_weapons.includes(:weapon).where(weapon_id: ids) when :summons then user.collection_summons.includes(:summon).where(summon_id: ids) end collection.map do |item| canonical = case type when :characters then item.character when :weapons then item.weapon when :summons then item.summon end result = { id: item_id_for(item, type), uncap_level: item.uncap_level, transcendence_step: item.transcendence_step, flb: canonical&.flb, ulb: canonical&.ulb } if type == :characters result[:special] = canonical&.special # For characters, transcendence availability is indicated by ulb on non-special chars result[:transcendence] = !canonical&.special && canonical&.ulb else result[:transcendence] = canonical&.transcendence end result end end def item_id_for(item, type) case type when :characters then item.character_id when :weapons then item.weapon_id when :summons then item.summon_id end end end end end