soft delete phantoms after claim confirmation

keeps phantom records for logging, excludes from all queries
This commit is contained in:
Justin Edmund 2025-12-17 20:05:01 -08:00
parent de72d21e24
commit 5afd31fdb6
6 changed files with 24 additions and 4 deletions

View file

@ -55,10 +55,10 @@ module Api
phantoms = [] phantoms = []
when :phantom when :phantom
members = [] members = []
phantoms = @crew.phantom_players.includes(:claimed_by).order(:name) phantoms = @crew.phantom_players.not_deleted.includes(:claimed_by).order(:name)
when :all when :all
members = @crew.crew_memberships.includes(:user).order(role: :desc, retired: :asc, created_at: :asc) members = @crew.crew_memberships.includes(:user).order(role: :desc, retired: :asc, created_at: :asc)
phantoms = @crew.phantom_players.includes(:claimed_by).order(:name) phantoms = @crew.phantom_players.not_deleted.includes(:claimed_by).order(:name)
else else
members = @crew.active_memberships.includes(:user).order(role: :desc, created_at: :asc) members = @crew.active_memberships.includes(:user).order(role: :desc, created_at: :asc)
phantoms = [] phantoms = []

View file

@ -9,6 +9,7 @@ module Api
# Returns phantom players assigned to the current user that are pending confirmation # Returns phantom players assigned to the current user that are pending confirmation
def index def index
phantoms = PhantomPlayer phantoms = PhantomPlayer
.not_deleted
.includes(:crew, :claimed_by) .includes(:crew, :claimed_by)
.where(claimed_by: current_user, claim_confirmed: false) .where(claimed_by: current_user, claim_confirmed: false)
.order(created_at: :desc) .order(created_at: :desc)

View file

@ -13,7 +13,7 @@ module Api
# GET /crews/:crew_id/phantom_players # GET /crews/:crew_id/phantom_players
def index def index
phantoms = @crew.phantom_players.includes(:claimed_by).order(:name) phantoms = @crew.phantom_players.not_deleted.includes(:claimed_by).order(:name)
render json: PhantomPlayerBlueprint.render(phantoms, view: :with_claimed_by, root: :phantom_players) render json: PhantomPlayerBlueprint.render(phantoms, view: :with_claimed_by, root: :phantom_players)
end end

View file

@ -21,6 +21,8 @@ class PhantomPlayer < ApplicationRecord
scope :pending_confirmation, -> { claimed.where(claim_confirmed: false) } scope :pending_confirmation, -> { claimed.where(claim_confirmed: false) }
scope :active, -> { where(retired: false) } scope :active, -> { where(retired: false) }
scope :retired, -> { where(retired: true) } scope :retired, -> { where(retired: true) }
scope :not_deleted, -> { where(deleted_at: nil) }
scope :deleted, -> { where.not(deleted_at: nil) }
# Phantoms who were active during a date range (either still active, or retired after the end date) # Phantoms who were active during a date range (either still active, or retired after the end date)
# Uses joined_at (editable) instead of created_at for historical accuracy # Uses joined_at (editable) instead of created_at for historical accuracy
@ -39,12 +41,19 @@ class PhantomPlayer < ApplicationRecord
end end
# Confirm the claim (user action) # Confirm the claim (user action)
# After confirmation, soft deletes the phantom since scores have been transferred
def confirm_claim!(user) def confirm_claim!(user)
raise CrewErrors::NotClaimedByUserError unless claimed_by == user raise CrewErrors::NotClaimedByUserError unless claimed_by == user
self.claim_confirmed = true self.claim_confirmed = true
transfer_scores_to_membership! transfer_scores_to_membership!
save! save!
soft_delete!
end
# Soft delete the phantom (keeps record for logging)
def soft_delete!
update!(deleted_at: Time.current)
end end
# Unassign the phantom (officer action or user rejection) # Unassign the phantom (officer action or user rejection)

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
class AddDeletedAtToPhantomPlayers < ActiveRecord::Migration[8.0]
def change
add_column :phantom_players, :deleted_at, :datetime
add_index :phantom_players, :deleted_at
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_12_15_173625) do ActiveRecord::Schema[8.0].define(version: 2025_12_17_195837) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "btree_gin" enable_extension "btree_gin"
enable_extension "pg_catalog.plpgsql" enable_extension "pg_catalog.plpgsql"
@ -688,10 +688,12 @@ ActiveRecord::Schema[8.0].define(version: 2025_12_15_173625) do
t.boolean "retired", default: false, null: false t.boolean "retired", default: false, null: false
t.datetime "retired_at" t.datetime "retired_at"
t.datetime "joined_at" t.datetime "joined_at"
t.datetime "deleted_at"
t.index ["claimed_by_id"], name: "index_phantom_players_on_claimed_by_id" t.index ["claimed_by_id"], name: "index_phantom_players_on_claimed_by_id"
t.index ["claimed_from_membership_id"], name: "index_phantom_players_on_claimed_from_membership_id" t.index ["claimed_from_membership_id"], name: "index_phantom_players_on_claimed_from_membership_id"
t.index ["crew_id", "granblue_id"], name: "index_phantom_players_on_crew_id_and_granblue_id", unique: true, where: "(granblue_id IS NOT NULL)" t.index ["crew_id", "granblue_id"], name: "index_phantom_players_on_crew_id_and_granblue_id", unique: true, where: "(granblue_id IS NOT NULL)"
t.index ["crew_id"], name: "index_phantom_players_on_crew_id" t.index ["crew_id"], name: "index_phantom_players_on_crew_id"
t.index ["deleted_at"], name: "index_phantom_players_on_deleted_at"
end end
create_table "raid_groups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| create_table "raid_groups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|