add joined_at to memberships and phantoms for historical data
- editable field separate from created_at - active_during scope uses joined_at for filtering - backfills from created_at in migration
This commit is contained in:
parent
50e2318f59
commit
5968ed74d5
5 changed files with 58 additions and 4 deletions
|
|
@ -3,10 +3,10 @@
|
||||||
module Api
|
module Api
|
||||||
module V1
|
module V1
|
||||||
class CrewMembershipBlueprint < ApiBlueprint
|
class CrewMembershipBlueprint < ApiBlueprint
|
||||||
fields :role, :retired, :retired_at, :created_at
|
fields :role, :retired, :retired_at, :joined_at, :created_at
|
||||||
|
|
||||||
view :with_user do
|
view :with_user do
|
||||||
fields :role, :retired, :retired_at, :created_at
|
fields :role, :retired, :retired_at, :joined_at, :created_at
|
||||||
|
|
||||||
field :user do |membership|
|
field :user do |membership|
|
||||||
UserBlueprint.render_as_hash(membership.user, view: :minimal)
|
UserBlueprint.render_as_hash(membership.user, view: :minimal)
|
||||||
|
|
@ -14,7 +14,7 @@ module Api
|
||||||
end
|
end
|
||||||
|
|
||||||
view :with_crew do
|
view :with_crew do
|
||||||
fields :role, :retired, :retired_at, :created_at
|
fields :role, :retired, :retired_at, :joined_at, :created_at
|
||||||
|
|
||||||
field :crew do |membership|
|
field :crew do |membership|
|
||||||
CrewBlueprint.render_as_hash(membership.crew, view: :minimal)
|
CrewBlueprint.render_as_hash(membership.crew, view: :minimal)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
module Api
|
module Api
|
||||||
module V1
|
module V1
|
||||||
class PhantomPlayerBlueprint < ApiBlueprint
|
class PhantomPlayerBlueprint < ApiBlueprint
|
||||||
fields :name, :granblue_id, :notes, :claim_confirmed
|
fields :name, :granblue_id, :notes, :claim_confirmed, :retired, :retired_at, :joined_at
|
||||||
|
|
||||||
field :claimed do |phantom|
|
field :claimed do |phantom|
|
||||||
phantom.claimed_by_id.present?
|
phantom.claimed_by_id.present?
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ class CrewMembership < ApplicationRecord
|
||||||
|
|
||||||
enum :role, { member: 0, vice_captain: 1, captain: 2 }
|
enum :role, { member: 0, vice_captain: 1, captain: 2 }
|
||||||
|
|
||||||
|
before_validation :set_joined_at, on: :create
|
||||||
|
|
||||||
validates :user_id, uniqueness: { scope: :crew_id }
|
validates :user_id, uniqueness: { scope: :crew_id }
|
||||||
validate :one_active_crew_per_user, on: :create
|
validate :one_active_crew_per_user, on: :create
|
||||||
validate :captain_limit
|
validate :captain_limit
|
||||||
|
|
@ -14,6 +16,13 @@ class CrewMembership < ApplicationRecord
|
||||||
scope :active, -> { where(retired: false) }
|
scope :active, -> { where(retired: false) }
|
||||||
scope :retired, -> { where(retired: true) }
|
scope :retired, -> { where(retired: true) }
|
||||||
|
|
||||||
|
# Members who were active during a date range (either still active, or retired after the end date)
|
||||||
|
# Uses joined_at (editable) instead of created_at (system timestamp) for historical accuracy
|
||||||
|
scope :active_during, ->(start_date, end_date) {
|
||||||
|
where('retired = false OR retired_at >= ?', start_date)
|
||||||
|
.where('joined_at <= ?', end_date)
|
||||||
|
}
|
||||||
|
|
||||||
def retire!
|
def retire!
|
||||||
update!(retired: true, retired_at: Time.current, role: :member)
|
update!(retired: true, retired_at: Time.current, role: :member)
|
||||||
end
|
end
|
||||||
|
|
@ -24,6 +33,10 @@ class CrewMembership < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def set_joined_at
|
||||||
|
self.joined_at ||= Time.current
|
||||||
|
end
|
||||||
|
|
||||||
def one_active_crew_per_user
|
def one_active_crew_per_user
|
||||||
return if retired
|
return if retired
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ class PhantomPlayer < ApplicationRecord
|
||||||
|
|
||||||
has_many :gw_individual_scores, dependent: :nullify
|
has_many :gw_individual_scores, dependent: :nullify
|
||||||
|
|
||||||
|
before_validation :set_joined_at, on: :create
|
||||||
|
|
||||||
validates :name, presence: true, length: { maximum: 100 }
|
validates :name, presence: true, length: { maximum: 100 }
|
||||||
validates :granblue_id, length: { maximum: 20 }, allow_blank: true
|
validates :granblue_id, length: { maximum: 20 }, allow_blank: true
|
||||||
validates :granblue_id, uniqueness: { scope: :crew_id }, if: -> { granblue_id.present? }
|
validates :granblue_id, uniqueness: { scope: :crew_id }, if: -> { granblue_id.present? }
|
||||||
|
|
@ -17,6 +19,15 @@ class PhantomPlayer < ApplicationRecord
|
||||||
scope :unclaimed, -> { where(claimed_by_id: nil) }
|
scope :unclaimed, -> { where(claimed_by_id: nil) }
|
||||||
scope :claimed, -> { where.not(claimed_by_id: nil) }
|
scope :claimed, -> { where.not(claimed_by_id: nil) }
|
||||||
scope :pending_confirmation, -> { claimed.where(claim_confirmed: false) }
|
scope :pending_confirmation, -> { claimed.where(claim_confirmed: false) }
|
||||||
|
scope :active, -> { where(retired: false) }
|
||||||
|
scope :retired, -> { where(retired: true) }
|
||||||
|
|
||||||
|
# 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
|
||||||
|
scope :active_during, ->(start_date, end_date) {
|
||||||
|
where('retired = false OR retired_at >= ?', start_date)
|
||||||
|
.where('joined_at <= ?', end_date)
|
||||||
|
}
|
||||||
|
|
||||||
# Assign this phantom to a user (officer action)
|
# Assign this phantom to a user (officer action)
|
||||||
def assign_to(user)
|
def assign_to(user)
|
||||||
|
|
@ -43,8 +54,17 @@ class PhantomPlayer < ApplicationRecord
|
||||||
save!
|
save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retire the phantom player (keeps scores)
|
||||||
|
def retire!
|
||||||
|
update!(retired: true, retired_at: Time.current)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def set_joined_at
|
||||||
|
self.joined_at ||= Time.current
|
||||||
|
end
|
||||||
|
|
||||||
def claimed_by_must_be_crew_member
|
def claimed_by_must_be_crew_member
|
||||||
return unless claimed_by.present?
|
return unless claimed_by.present?
|
||||||
return if claimed_by.crew == crew
|
return if claimed_by.crew == crew
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddJoinedAtToCrewMembershipsAndPhantomPlayers < ActiveRecord::Migration[8.0]
|
||||||
|
def up
|
||||||
|
add_column :crew_memberships, :joined_at, :datetime
|
||||||
|
add_column :phantom_players, :joined_at, :datetime
|
||||||
|
|
||||||
|
# Backfill joined_at from created_at for existing records
|
||||||
|
execute <<-SQL
|
||||||
|
UPDATE crew_memberships SET joined_at = created_at WHERE joined_at IS NULL
|
||||||
|
SQL
|
||||||
|
execute <<-SQL
|
||||||
|
UPDATE phantom_players SET joined_at = created_at WHERE joined_at IS NULL
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :crew_memberships, :joined_at
|
||||||
|
remove_column :phantom_players, :joined_at
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue