Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Now we can use flag genesis=true to specify that only one referral mu… #21

Merged
merged 3 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,46 @@ not allow it interactions with the system, although it is technically possible
to do other actions.

Path: `/integrations/rarime-points-svc/v1/private/referrals`
Query parameters:
- `did` - user DID to create or edit referrals for
- `count` - number of referrals to set

Example to set 200 referrals for user `did:example:123`:
```shell
curl -X POST "http://localhost/integrations/rarime-points-svc/v1/private/referrals?did=did:example:123&count=200"
Body:
```json
{
"nullifier": "0x0000000000000000000000000000000000000000000000000000000000000000",
"count": 2,
"genesis": true
}
```
Response variants:
```json
{
"added_ref": "kPRQYQUcWzW",
"usage_left": 2
}
```
or
```json
{
"added_referrals":[
"kPRQYQUcWzW",
"kPRQYQUcaaa",
"kPRQYQUcbbb",
"kPRQYQUcccc"
]
}
```
Parameters:
- `nullifier` - nullifier to create or edit referrals for
- `count` - number of referrals to set/number of referral usage for genesis
- `genesis` - specify add many referrals with one usage or one referral with many usage


Behavior:
a) User does not exist -> create a _System user_ with the specified number of
referrals (if count == 0, do not create)
b) User exists, `N` > `count` -> add `N - count` active referrals
c) User exists, `N` < `count` -> consume `count - N` active referrals (not delete!)
d) User exists, `N` = `count` -> do nothing
f) Flag `genesis = true` that mean that will be created only one referral with
`usage_count = count`. Referrals which have `usage_count <= 0` is inactive

Where `N` is the current number of active referrals for the user, `count` is
query parameter value.
Expand Down
33 changes: 33 additions & 0 deletions internal/assets/migrations/002_genesis_referrals.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-- +migrate Up
ALTER TABLE referrals
RENAME COLUMN is_consumed TO usage_left;

ALTER TABLE referrals ALTER COLUMN usage_left DROP DEFAULT;

ALTER TABLE referrals
ALTER usage_left TYPE INTEGER
USING
CASE
WHEN usage_left=TRUE THEN 0
ELSE 1
END;

ALTER TABLE referrals ALTER COLUMN usage_left SET DEFAULT 1;

ALTER TABLE balances DROP CONSTRAINT balances_referred_by_key;

-- +migrate Down
ALTER TABLE referrals ALTER COLUMN usage_left DROP DEFAULT;

ALTER TABLE referrals
ALTER usage_left TYPE BOOLEAN
USING
CASE
WHEN usage_left > 0 THEN FALSE
ELSE TRUE
END;

ALTER TABLE referrals
RENAME COLUMN usage_left TO is_consumed;

ALTER TABLE referrals ALTER COLUMN is_consumed SET DEFAULT FALSE;
10 changes: 5 additions & 5 deletions internal/data/pg/referrals.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func NewReferrals(db *pgdb.DB) data.ReferralsQ {
return &referrals{
db: db,
selector: squirrel.Select("*").From(referralsTable),
updater: squirrel.Update(referralsTable).Set("is_consumed", true),
updater: squirrel.Update(referralsTable).Set("usage_left", squirrel.Expr("usage_left - 1")),
counter: squirrel.Select("COUNT(*) as count").From(referralsTable),
}
}
Expand All @@ -37,9 +37,9 @@ func (q *referrals) Insert(referrals ...data.Referral) error {
return nil
}

stmt := squirrel.Insert(referralsTable).Columns("id", "nullifier")
stmt := squirrel.Insert(referralsTable).Columns("id", "nullifier", "usage_left")
for _, ref := range referrals {
stmt = stmt.Values(ref.ID, ref.Nullifier)
stmt = stmt.Values(ref.ID, ref.Nullifier, ref.UsageLeft)
}

if err := q.db.Exec(stmt); err != nil {
Expand Down Expand Up @@ -122,8 +122,8 @@ func (q *referrals) FilterByNullifier(nullifier string) data.ReferralsQ {
return q.applyCondition(squirrel.Eq{"nullifier": nullifier})
}

func (q *referrals) FilterByIsConsumed(isConsumed bool) data.ReferralsQ {
return q.applyCondition(squirrel.Eq{"is_consumed": isConsumed})
func (q *referrals) FilterConsumed() data.ReferralsQ {
return q.applyCondition(squirrel.Gt{"usage_left": 0})
}

func (q *referrals) applyCondition(cond squirrel.Sqlizer) data.ReferralsQ {
Expand Down
9 changes: 4 additions & 5 deletions internal/data/referrals.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package data

type Referral struct {
ID string `db:"id"`
Nullifier string `db:"nullifier"`
IsConsumed bool `db:"is_consumed"`
CreatedAt int32 `db:"created_at"`
violog marked this conversation as resolved.
Show resolved Hide resolved
ID string `db:"id"`
Nullifier string `db:"nullifier"`
UsageLeft int32 `db:"usage_left"`
}

type ReferralsQ interface {
Expand All @@ -18,5 +17,5 @@ type ReferralsQ interface {
Count() (uint64, error)

FilterByNullifier(string) ReferralsQ
FilterByIsConsumed(bool) ReferralsQ
FilterConsumed() ReferralsQ
}
2 changes: 1 addition & 1 deletion internal/service/handlers/activate_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func ActivateBalance(w http.ResponseWriter, r *http.Request) {
return
}

referral, err := ReferralsQ(r).FilterByIsConsumed(false).Get(req.Data.Attributes.ReferredBy)
referral, err := ReferralsQ(r).FilterConsumed().Get(req.Data.Attributes.ReferredBy)
if err != nil {
Log(r).WithError(err).Error("Failed to get referral by ID")
ape.RenderErr(w, problems.InternalError())
Expand Down
2 changes: 1 addition & 1 deletion internal/service/handlers/create_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func CreateBalance(w http.ResponseWriter, r *http.Request) {
return
}

referral, err := ReferralsQ(r).FilterByIsConsumed(false).Get(req.Data.Attributes.ReferredBy)
referral, err := ReferralsQ(r).FilterConsumed().Get(req.Data.Attributes.ReferredBy)
if err != nil {
Log(r).WithError(err).Error("Failed to get referral by ID")
ape.RenderErr(w, problems.InternalError())
Expand Down
31 changes: 30 additions & 1 deletion internal/service/handlers/edit_referrals.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ func EditReferrals(w http.ResponseWriter, r *http.Request) {
}
}

if req.Genesis {
count, err := ReferralsQ(r).FilterByNullifier(req.Nullifier).Count()
if err != nil {
Log(r).WithError(err).Error("Failed to get referrals count")
ape.RenderErr(w, problems.InternalError())
return
}

referral := referralid.New(req.Nullifier, count)

err = ReferralsQ(r).Insert(data.Referral{
ID: referral,
Nullifier: req.Nullifier,
UsageLeft: int32(*req.Count),
})
if err != nil {
Log(r).WithError(err).Error("Failed to insert genesis referral")
ape.RenderErr(w, problems.InternalError())
return
}

ape.Render(w, struct {
Ref string `json:"added_ref"`
UsageLeft int `json:"usage_left"`
}{referral, int(*req.Count)})
return
}

added, err := adjustReferralsCount(req, r)
if err != nil {
Log(r).WithError(err).Error("Failed to adjust referrals count")
Expand All @@ -59,14 +87,15 @@ func prepareReferralsToAdd(nullifier string, count, index uint64) []data.Referra
refs[i] = data.Referral{
ID: code,
Nullifier: nullifier,
UsageLeft: 1,
}
}

return refs
}

func adjustReferralsCount(req requests.EditReferralsRequest, r *http.Request) (refsAdded []string, err error) {
active, err := ReferralsQ(r).FilterByNullifier(req.Nullifier).FilterByIsConsumed(false).Count()
active, err := ReferralsQ(r).FilterByNullifier(req.Nullifier).FilterConsumed().Count()
if err != nil {
return nil, fmt.Errorf("count active referrals: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/service/handlers/get_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func newBalanceResponse(balance data.Balance, referrals []data.Referral) resourc
resp.Data.Attributes.IsDisabled = !balance.ReferredBy.Valid

for _, ref := range referrals {
if ref.IsConsumed {
if ref.UsageLeft == 0 {
consumedCodes = append(consumedCodes, ref.ID)
continue
}
Expand Down
1 change: 1 addition & 0 deletions internal/service/requests/edit_referrals.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
type EditReferralsRequest struct {
Nullifier string `json:"nullifier"`
Count *uint64 `json:"count"`
Genesis bool `json:"genesis"`
}

func NewEditReferrals(r *http.Request) (req EditReferralsRequest, err error) {
Expand Down
Loading