Skip to content

Commit

Permalink
feat: add polymorphic association on reward pools, add quest and badge
Browse files Browse the repository at this point in the history
  • Loading branch information
juliano-quatrin-nunes committed Jan 20, 2025
1 parent 0e259d6 commit 81d23a3
Show file tree
Hide file tree
Showing 19 changed files with 177 additions and 34 deletions.
9 changes: 9 additions & 0 deletions apps/govquests-api/govquests/gamification/lib/gamification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require_relative "gamification/leaderboard"
require_relative "gamification/badge"
require_relative "gamification/user_badge"
require_relative "gamification/special_badge"

ACTION_BADGE_NAMESPACE_UUID = "5FA78373-03E0-4D0B-91D1-3F2C6CA3F088"

Expand Down Expand Up @@ -82,5 +83,13 @@ class CommandHandler < Infra::CommandHandlerRegistry
handle "Gamification::EarnBadge", aggregate: UserBadge do |user_badge, cmd|
user_badge.earn_badge(cmd.user_id, cmd.badgeable_id, cmd.badgeable_type, cmd.earned_at)
end

handle "Gamification::CreateSpecialBadge", aggregate: SpecialBadge do |special_badge, cmd|
special_badge.create(cmd.display_data, cmd.badge_type, cmd.badge_data)
end

handle "Gamification::AssociateRewardPool", aggregate: SpecialBadge do |special_badge, cmd|
special_badge.associate_reward_pool(cmd.pool_id, cmd.reward_definition)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,19 @@ class EarnBadge < Infra::Command
end

class CreateSpecialBadge < Infra::Command
attribute :badge_id, Infra::Types::String
attribute :badge_id, Infra::Types::UUID
attribute :display_data, Infra::Types::Hash
attribute :badge_type, Infra::Types::String
attribute :badge_data, Infra::Types::Hash
attribute :points, Infra::Types::Integer

alias_method :aggregate_id, :badge_id
end

class AssociateRewardPool < Infra::Command
attribute :badge_id, Infra::Types::UUID
attribute :pool_id, Infra::Types::UUID
attribute :reward_definition, Infra::Types::Hash

alias :aggregate_id :badge_id
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,15 @@ class BadgeEarned < Infra::Event
end

class SpecialBadgeCreated < Infra::Event
attribute :badge_id, Infra::Types::String
attribute :badge_id, Infra::Types::UUID
attribute :display_data, Infra::Types::Hash
attribute :badge_type, Infra::Types::String
attribute :badge_data, Infra::Types::Hash
attribute :points, Infra::Types::Integer
end

class RewardPoolAssociated < Infra::Event
attribute :badge_id, Infra::Types::UUID
attribute :pool_id, Infra::Types::String
attribute :reward_definition, Infra::Types::Hash
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ def initialize(id)
@display_data = nil
@badge_type = nil
@badge_data = nil
@points = nil
@reward_pools = []
end

def create(display_data, badge_type, badge_data, points)
def create(display_data, badge_type, badge_data)
apply SpecialBadgeCreated.new(data: {
badge_id: @id,
display_data:,
badge_type:,
badge_data:,
points:,
badge_data:
})
end

def associate_reward_pool(pool_id, reward_definition)
apply RewardPoolAssociated.new(data: {
badge_id: @id,
pool_id:,
reward_definition:
})
end

Expand All @@ -26,7 +33,13 @@ def create(display_data, badge_type, badge_data, points)
@display_data = event.data[:display_data]
@badge_type = event.data[:badge_type]
@badge_data = event.data[:badge_data]
@points = event.data[:points]
end

on RewardPoolAssociated do |event|
@reward_pools << {
pool_id: event.data[:pool_id],
reward_definition: event.data[:reward_definition]
}
end
end
end
3 changes: 2 additions & 1 deletion apps/govquests-api/govquests/rewarding/lib/rewarding.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ def call(event_store, command_bus)
class CommandHandler < Infra::CommandHandlerRegistry
handle "Rewarding::CreateRewardPool", aggregate: RewardPool do |pool, cmd|
pool.create(
quest_id: cmd.quest_id,
rewardable_id: cmd.rewardable_id,
rewardable_type: cmd.rewardable_type,
reward_definition: cmd.reward_definition,
initial_inventory: cmd.initial_inventory
)
Expand Down
10 changes: 8 additions & 2 deletions apps/govquests-api/govquests/rewarding/lib/rewarding/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
module Rewarding
class CreateRewardPool < Infra::Command
attribute :pool_id, Infra::Types::UUID
attribute :quest_id, Infra::Types::UUID
attribute :rewardable_id, Infra::Types::UUID
attribute :rewardable_type, Infra::Types::String
attribute :reward_definition, SharedKernel::Types::RewardDefinition
attribute :initial_inventory, Infra::Types::Integer.optional

alias_method :aggregate_id, :pool_id
alias :aggregate_id :pool_id

def validate!
raise ArgumentError, "rewardable_type must be either Quest or SpecialBadgeReadModel" unless
['Questing::QuestReadModel', 'Gamification::SpecialBadgeReadModel'].include?(rewardable_type)
end
end

class IssueReward < Infra::Command
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module Rewarding
class RewardPoolCreated < Infra::Event
attribute :pool_id, Infra::Types::UUID
attribute :quest_id, Infra::Types::UUID
attribute :rewardable_id, Infra::Types::UUID
attribute :rewardable_type, Infra::Types::String
attribute :reward_definition, SharedKernel::Types::RewardDefinition
attribute :initial_inventory, Infra::Types::Integer.optional
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ class AlreadyCreated < StandardError; end

def initialize(id)
@id = id
@quest_id = nil
@rewardable_id = nil
@rewardable_type = nil
@reward_definition = nil
@remaining_inventory = 0
@issued_rewards_receipients = Set.new
end

def create(quest_id:, reward_definition:, initial_inventory: nil)
raise AlreadyCreated if @quest_id

def create(rewardable_id:, rewardable_type:, reward_definition:, initial_inventory: nil)
raise AlreadyCreated if @rewardable_id.present?
apply RewardPoolCreated.new(data: {
pool_id: @id,
quest_id: quest_id,
rewardable_id: rewardable_id,
rewardable_type: rewardable_type,
reward_definition: reward_definition,
initial_inventory: initial_inventory
})
Expand Down Expand Up @@ -52,7 +54,8 @@ def token_reward?
end

on RewardPoolCreated do |event|
@quest_id = event.data[:quest_id]
@rewardable_id = event.data[:rewardable_id]
@rewardable_type = event.data[:rewardable_type]
@reward_definition = event.data[:reward_definition]
@remaining_inventory = event.data[:initial_inventory] if event.data[:initial_inventory]
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ def call(event)
badge_id: event.data[:badge_id],
display_data: event.data[:display_data],
badge_type: event.data[:badge_type],
badge_data: event.data[:badge_data],
points: event.data[:points]
badge_data: event.data[:badge_data]
)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def call(event_store)
event_store.subscribe(OnTokenClaimStarted, to: [Gamification::TokenClaimStarted])
event_store.subscribe(OnTokenClaimCompleted, to: [Gamification::TokenClaimCompleted])
event_store.subscribe(OnBadgeCreated, to: [Gamification::BadgeCreated])
event_store.subscribe(OnSpecialBadgeCreated, to: [Gamification::SpecialBadgeCreated])
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ class SpecialBadgeReadModel < ApplicationRecord
validates :display_data, presence: true
validates :badge_type, presence: true
validates :badge_data, presence: true
validates :points, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 0}

has_many :reward_pools,
class_name: "Rewarding::RewardPoolReadModel",
as: :rewardable

has_many :user_badges,
class_name: "Gamification::UserBadgeReadModel",
Expand All @@ -22,7 +25,6 @@ class SpecialBadgeReadModel < ApplicationRecord
# badge_data :jsonb not null
# badge_type :string not null
# display_data :jsonb not null
# points :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# badge_id :string not null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ class QuestReadModel < ApplicationRecord
has_many :quest_actions, -> { order(position: :asc) }, class_name: "Questing::QuestActionReadModel", foreign_key: "quest_id", primary_key: "quest_id"
has_many :actions, through: :quest_actions, source: :action, class_name: "ActionTracking::ActionReadModel"
has_many :user_quests, class_name: "Questing::UserQuestReadModel", foreign_key: "quest_id", primary_key: "quest_id"
has_many :reward_pools, class_name: "Rewarding::RewardPoolReadModel", foreign_key: "quest_id", primary_key: "quest_id"

has_many :reward_pools,
class_name: "Rewarding::RewardPoolReadModel",
as: :rewardable

belongs_to :track,
class_name: "Questing::TrackReadModel",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
module Rewarding
class OnRewardPoolCreated
def call(event)
rewardable_class = event.data[:rewardable_type].constantize
rewardable = case event.data[:rewardable_type]
when "Questing::QuestReadModel"
rewardable_class.find_by(quest_id: event.data[:rewardable_id])
when "Gamification::SpecialBadgeReadModel"
rewardable_class.find_by(badge_id: event.data[:rewardable_id])
end

RewardPoolReadModel.create!(
pool_id: event.data[:pool_id],
quest_id: event.data[:quest_id],
rewardable_id: rewardable.id,
rewardable_type: event.data[:rewardable_type],
reward_definition: event.data[:reward_definition],
remaining_inventory: event.data[:initial_inventory]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class RewardPoolReadModel < ApplicationRecord
through: :issued_rewards,
source: :user

belongs_to :rewardable, polymorphic: true

scope :token, -> { where("reward_definition->>'type' = 'Token'") }
end
end
Expand All @@ -22,13 +24,15 @@ class RewardPoolReadModel < ApplicationRecord
# id :bigint not null, primary key
# remaining_inventory :integer
# reward_definition :jsonb not null
# rewardable_type :string
# created_at :datetime not null
# updated_at :datetime not null
# pool_id :uuid not null
# quest_id :uuid not null
# rewardable_id :uuid not null
#
# Indexes
#
# index_reward_pools_on_pool_id (pool_id) UNIQUE
# index_reward_pools_on_quest_id (quest_id)
# index_reward_pools_on_pool_id (pool_id) UNIQUE
# index_reward_pools_on_rewardable_id (rewardable_id)
# index_reward_pools_on_rewardable_type_and_rewardable_id (rewardable_type,rewardable_id)
#
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class UpdateRewardPoolsToPolymorphic < ActiveRecord::Migration[8.1]
def change
rename_column :reward_pools, :quest_id, :rewardable_id
change_column :reward_pools, :rewardable_id, :string # Changed from UUID to string
add_column :reward_pools, :rewardable_type, :string

add_index :reward_pools, [:rewardable_type, :rewardable_id]
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class RemovePointsFromSpecialBadges < ActiveRecord::Migration[8.1]
def change
remove_column :special_badges, :points, :integer
end
end
9 changes: 5 additions & 4 deletions apps/govquests-api/rails_app/db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 81d23a3

Please sign in to comment.