Skip to content

Commit

Permalink
Merge pull request #5 from rarimo/feature/referral-event-change
Browse files Browse the repository at this point in the history
Feature: be_referred event behaviour changes
  • Loading branch information
violog authored Jul 8, 2024
2 parents b2a0e43 + 4819331 commit 948a60d
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 27 deletions.
6 changes: 6 additions & 0 deletions internal/data/evtypes/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ func FilterByFrequency(f models.Frequency) func(models.EventType) bool {
}
}

func FilterByAutoClaim(autoClaim bool) func(models.EventType) bool {
return func(ev models.EventType) bool {
return ev.AutoClaim != autoClaim
}
}

func FilterByNames(names ...string) func(models.EventType) bool {
return func(ev models.EventType) bool {
if len(names) == 0 {
Expand Down
21 changes: 12 additions & 9 deletions internal/service/handlers/create_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,20 @@ func CreateBalance(w http.ResponseWriter, r *http.Request) {
ape.RenderErr(w, problems.InternalError())
return
}

if referral == nil {
ape.RenderErr(w, problems.NotFound())
return
}

events := prepareEventsWithRef(nullifier, req.Data.Attributes.ReferredBy, r)
refBalance, err := BalancesQ(r).FilterByNullifier(referral.Nullifier).Get()
if err != nil || refBalance == nil { // must exist due to FK constraint
Log(r).WithError(err).Error("Failed to get referrer balance by nullifier")
ape.RenderErr(w, problems.InternalError())
return
}
isGenesisRef := refBalance.ReferredBy == nil

events := prepareEventsWithRef(nullifier, req.Data.Attributes.ReferredBy, isGenesisRef, r)
if err = createBalanceWithEventsAndReferrals(nullifier, &req.Data.Attributes.ReferredBy, events, r); err != nil {
Log(r).WithError(err).Error("Failed to create balance with events")
ape.RenderErr(w, problems.InternalError())
Expand Down Expand Up @@ -84,15 +91,11 @@ func CreateBalance(w http.ResponseWriter, r *http.Request) {
ape.Render(w, newBalanceResponse(*balance, &referrals[0]))
}

func prepareEventsWithRef(nullifier, refBy string, r *http.Request) []data.Event {
func prepareEventsWithRef(nullifier, refBy string, isGenesisRef bool, r *http.Request) []data.Event {
events := EventTypes(r).PrepareEvents(nullifier, evtypes.FilterNotOpenable)
if refBy == "" {
return events
}

refType := EventTypes(r).Get(models.TypeBeReferred, evtypes.FilterInactive)
if refType == nil {
Log(r).Debug("`Be referred` event is inactive, skipping it")

if refBy == "" || isGenesisRef || refType == nil {
return events
}

Expand Down
2 changes: 1 addition & 1 deletion internal/service/handlers/edit_referrals.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func EditReferrals(w http.ResponseWriter, r *http.Request) {

var code string
err = EventsQ(r).Transaction(func() error {
events := prepareEventsWithRef(req.Nullifier, "", r)
events := prepareEventsWithRef(req.Nullifier, "", true, r)
if err = createBalanceWithEvents(req.Nullifier, nil, events, r); err != nil {
return fmt.Errorf("failed to create balance with events: %w", err)
}
Expand Down
41 changes: 41 additions & 0 deletions internal/service/handlers/verify_passport.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ func doPassportScanUpdates(r *http.Request, balance data.Balance, anonymousID st
return fmt.Errorf("failed to claim referral specific events: %w", err)
}

// Be referred event is a welcome bonus when you created balance with non-genesis referral code
if err = claimBeReferredEvent(r, balance); err != nil {
return fmt.Errorf("failed to claim be referred event: %w", err)
}

// Adds a friend event for the referrer. If the event
// is inactive, then nothing happens. If active, the
// fulfilled event is added and, if possible, the event claimed
Expand Down Expand Up @@ -356,6 +361,42 @@ func claimReferralSpecificEvents(r *http.Request, evTypeRef *models.EventType, n
return nil
}

func claimBeReferredEvent(r *http.Request, balance data.Balance) error {
evTypeBeRef := EventTypes(r).Get(models.TypeBeReferred, evtypes.FilterInactive)
if evTypeBeRef == nil || !evTypeBeRef.AutoClaim {
return nil
}

event, err := EventsQ(r).FilterByNullifier(balance.Nullifier).
FilterByType(models.TypeBeReferred).
FilterByStatus(data.EventFulfilled).
Get()
if err != nil {
return fmt.Errorf("get fulfilled be referred event: %w", err)
}
if event == nil {
Log(r).Debug("User is not eligible for be_referred event")
return nil
}

_, err = EventsQ(r).FilterByID(event.ID).Update(data.EventClaimed, nil, &evTypeBeRef.Reward)
if err != nil {
return fmt.Errorf("update event status: %w", err)
}

err = DoClaimEventUpdates(
Levels(r),
ReferralsQ(r),
BalancesQ(r),
balance,
evTypeBeRef.Reward)
if err != nil {
return fmt.Errorf("do claim event updates for be_referred: %w", err)
}

return nil
}

func addEventForReferrer(r *http.Request, evTypeRef *models.EventType, balance data.Balance) error {
if evTypeRef == nil {
return nil
Expand Down
49 changes: 32 additions & 17 deletions internal/service/workers/nooneisforgotten/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func Run(cfg config.Config, sig chan struct{}) {
}

if err := pg.NewEvents(db).Transaction(func() error {
return claimReferralSpecificEvents(db, cfg.EventTypes(), cfg.Levels())
return autoClaimEvents(db, cfg.EventTypes(), cfg.Levels())
}); err != nil {
panic(fmt.Errorf("failed to claim referral specific events: %w", err))
}
Expand Down Expand Up @@ -131,23 +131,24 @@ func updateReferralUserEvents(db *pgdb.DB, types *evtypes.Types) error {
return nil
}

// claimReferralSpecificEvents claim fulfilled events for invited
// friends which have passport scanned, if it possible
func claimReferralSpecificEvents(db *pgdb.DB, types *evtypes.Types, levels config.Levels) error {
evType := types.Get(models.TypeReferralSpecific, evtypes.FilterInactive)
if evType == nil || !evType.AutoClaim {
// autoClaimEvents claim fulfilled events which have auto-claim enabled. This is
// useful if some events were inactive, then became active and must be claimed
// automatically.
func autoClaimEvents(db *pgdb.DB, types *evtypes.Types, levels config.Levels) error {
claimTypes := types.Names(evtypes.FilterByAutoClaim(true))
if len(claimTypes) == 0 {
return nil
}

events, err := pg.NewEvents(db).
FilterByType(models.TypeReferralSpecific).
FilterByType(claimTypes...).
FilterByStatus(data.EventFulfilled).
Select()
if err != nil {
return fmt.Errorf("failed to select passport scan events: %w", err)
return fmt.Errorf("failed to select fulfilled events: %w", err)
}

// we need to have maps which link nullifiers to events slice
// nullifiers var is used only for selection, so we don't care about duplicates
nullifiers := make([]string, 0, len(events))
for _, event := range events {
nullifiers = append(nullifiers, event.Nullifier)
Expand All @@ -164,24 +165,38 @@ func claimReferralSpecificEvents(db *pgdb.DB, types *evtypes.Types, levels confi
return errors.New("critical: events present, but no balances with nullifier")
}

toClaim := make([]string, 0, len(events))
// select events to claim only for verified balances
// select events to claim only for verified balances, group by type name
claimByTypes := make(map[string][]data.Event, len(claimTypes))
for _, event := range events {
for _, balance := range balances {
if event.Nullifier != balance.Nullifier || !balance.IsVerified {
continue
}
toClaim = append(toClaim, event.ID)
claimByTypes[event.Type] = append(claimByTypes[event.Type], event)
break
}
}
if len(toClaim) == 0 {
if len(claimByTypes) == 0 {
return nil
}

_, err = pg.NewEvents(db).FilterByID(toClaim...).Update(data.EventClaimed, nil, &evType.Reward)
if err != nil {
return fmt.Errorf("update event status: %w", err)
rewardByNullifier := make(map[string]int64, len(balances))
for _, evType := range types.List(evtypes.FilterByAutoClaim(true)) {
byType := claimByTypes[evType.Name]
if len(byType) == 0 {
continue
}

ids := make([]string, 0, len(byType))
for _, ev := range byType {
ids = append(ids, ev.ID)
rewardByNullifier[ev.Nullifier] += evType.Reward
}

_, err = pg.NewEvents(db).FilterByID(ids...).Update(data.EventClaimed, nil, &evType.Reward)
if err != nil {
return fmt.Errorf("update event status: %w", err)
}
}

for _, balance := range balances {
Expand All @@ -190,7 +205,7 @@ func claimReferralSpecificEvents(db *pgdb.DB, types *evtypes.Types, levels confi
pg.NewReferrals(db),
pg.NewBalances(db),
balance,
evType.Reward)
rewardByNullifier[balance.Nullifier])
if err != nil {
return fmt.Errorf("failed to do claim event updates for referral specific event: %w", err)
}
Expand Down

0 comments on commit 948a60d

Please sign in to comment.