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

FIx list events #12

Merged
merged 4 commits into from
Jul 10, 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
5 changes: 5 additions & 0 deletions docs/spec/components/schemas/Balance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ allOf:
description: Referral codes. Returned only for the single user.
items:
$ref: '#/components/schemas/ReferralCode'
referred_users_count:
type: integer
format: int
description: Number of invited users
example: 13
level:
type: integer
format: int
Expand Down
5 changes: 5 additions & 0 deletions docs/spec/components/schemas/EventStaticMeta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,8 @@ properties:
type: string
description: Base64-encoded QR code. Must match the code provided in event type.
example: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABaElEQVR4AWP4//8/AyUYw"
usage_count:
type: integer
format: int
description: Number of uses. Only available to the administrator.
example: 1002
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
get:
tags:
- Event types
summary: List QR event types
description: |
Returns configuration of all event types with QR-code.
Basically, it is event static metadata (model `EventStaticMeta`)
for each event type in the system.
Requires **admin** role in JWT.
operationId: getQREventTypes
parameters:
- in: query
name: 'count'
description: Іpecifies whether to return the number of uses of the event
required: false
schema:
type: bool
example: true
- in: query
name: 'filter[name]'
description: Filter by type name. Possible values should be hard-coded in the client.
required: false
schema:
type: array
items:
type: string
example: "passport_scan"
- in: query
name: 'filter[name][not]'
description: |
Inverted filter by type name: excludes provided values
required: false
schema:
type: array
items:
type: string
example: "referral_specific"
- in: query
name: 'filter[flag]'
description: Filter by configuration flags. Values are disjunctive (OR).
required: false
schema:
type: array
items:
type: string
enum:
- active
- not_started
- expired
- disabled
responses:
200:
description: Success
content:
application/vnd.api+json:
schema:
type: object
required:
- data
properties:
data:
type: array
items:
$ref: '#/components/schemas/EventType'
500:
$ref: '#/components/responses/internalError'

post:
tags:
- Event types
summary: Create event type
description: |
Creates a new event type. Requires **admin** role in JWT.
The type must not be present in the system.
operationId: createEventType
requestBody:
required: true
content:
application/vnd.api+json:
schema:
type: object
required:
- data
properties:
data:
$ref: '#/components/schemas/EventType'
responses:
204:
description: No content
400:
$ref: '#/components/responses/invalidParameter'
401:
$ref: '#/components/responses/invalidAuth'
409:
description: Event type already exists
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/Errors'
500:
$ref: '#/components/responses/internalError'
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ patch:
schema:
type: string
example: "059c81dd-2a54-44a8-8142-c15ad8f88949"
- in: header
name: Signature
description: Signature of the request
required: true
schema:
type: string
pattern: '^[a-f0-9]{64}$'
requestBody:
required: true
content:
Expand Down
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2118,10 +2118,6 @@ github.com/rarimo/geo-auth-svc v0.2.0 h1:yQvcIBNx+Tc1jJdtpWDfyLc0HogU+okA08HEZ55
github.com/rarimo/geo-auth-svc v0.2.0/go.mod h1:SB4bo1xHYDAsBaQGX2+FoEgD3xxqYmcgr4XTTjy4/OM=
github.com/rarimo/saver-grpc-lib v1.0.0 h1:MGUVjYg7unmodYczVsLqlqZNkT4CIgKqdo6aQtL1qdE=
github.com/rarimo/saver-grpc-lib v1.0.0/go.mod h1:DpugWK5B7Hi0bdC3MPe/9FD2zCxaRwsyykdwxtF1Zgg=
github.com/rarimo/zkverifier-kit v1.0.0 h1:zMW85hyDP3Uk6p9Dk9U4TBzOf0Pry+RNlWpli1tUZ1Q=
github.com/rarimo/zkverifier-kit v1.0.0/go.mod h1:3YDg5dTkDRr4IdfaDHGYetopd6gS/2SuwSeseYTWwNw=
github.com/rarimo/zkverifier-kit v1.1.0-rc.0 h1:5JkObPkEUGwgq4SKJAGInaTBDBILQUHMP4VKZuYPcsM=
github.com/rarimo/zkverifier-kit v1.1.0-rc.0/go.mod h1:3YDg5dTkDRr4IdfaDHGYetopd6gS/2SuwSeseYTWwNw=
github.com/rarimo/zkverifier-kit v1.1.0-rc.1 h1:xtmrFEl7eLAE6mi7IQYOOMKFdwXC3gbe39fYQdvKVZg=
github.com/rarimo/zkverifier-kit v1.1.0-rc.1/go.mod h1:3YDg5dTkDRr4IdfaDHGYetopd6gS/2SuwSeseYTWwNw=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
Expand Down
1 change: 1 addition & 0 deletions internal/data/evtypes/models/event_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func (e EventType) Resource() resources.EventStaticMeta {
ExpiresAt: e.ExpiresAt,
AutoClaim: e.AutoClaim,
ActionUrl: e.ActionURL,
Disabled: e.Disabled,
Logo: e.Logo,
Flag: e.Flag(),
}
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 @@ -86,7 +86,7 @@ func CreateBalance(w http.ResponseWriter, r *http.Request) {
return
}

ape.Render(w, newBalanceResponse(*balance, referrals))
ape.Render(w, newBalanceResponse(*balance, referrals, 0))
}

func prepareEventsWithRef(nullifier, refBy string, isGenesisRef bool, r *http.Request) []data.Event {
Expand Down
15 changes: 0 additions & 15 deletions internal/service/handlers/fulfill_qr_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package handlers
import (
"net/http"

"github.com/labstack/gommon/log"
"github.com/rarimo/geo-auth-svc/pkg/auth"
"github.com/rarimo/geo-points-svc/internal/data"
"github.com/rarimo/geo-points-svc/internal/data/evtypes"
Expand Down Expand Up @@ -36,20 +35,6 @@ func FulfillQREvent(w http.ResponseWriter, r *http.Request) {
return
}

gotSig := r.Header.Get("Signature")
wantSig, err := SigCalculator(r).QREventSignature(event.Nullifier, event.ID, req.Data.Attributes.QrCode)
if err != nil { // must never happen due to preceding validation
Log(r).WithError(err).Error("Failed to calculate HMAC signature")
ape.RenderErr(w, problems.InternalError())
return
}

if gotSig != wantSig {
log.Warnf("QR event fulfillment unauthorized access: HMAC signature mismatch: got %s, want %s", gotSig, wantSig)
ape.RenderErr(w, problems.Forbidden())
return
}

evType := EventTypes(r).Get(event.Type, evtypes.FilterInactive)
if evType == nil {
Log(r).Infof("Event type %s is inactive", event.Type)
Expand Down
23 changes: 21 additions & 2 deletions internal/service/handlers/get_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func GetBalance(w http.ResponseWriter, r *http.Request) {
}

var referrals []data.Referral
var referredUsers int
if req.ReferralCodes {
referrals, err = ReferralsQ(r).
FilterByNullifier(req.Nullifier).
Expand All @@ -52,9 +53,26 @@ func GetBalance(w http.ResponseWriter, r *http.Request) {
ape.RenderErr(w, problems.InternalError())
return
}

// Infinite referral codes initially have 0 uses and,
// accordingly, after use, this value will decrease,
// i.e. the number of invited users for this code will
// be an absolute value
//
// A one-time code is considered used if it has 0 uses,
// because the initial value is 1
for _, ref := range referrals {
if ref.Infinity {
referredUsers += -int(ref.UsageLeft)
continue
}
if ref.UsageLeft == 0 {
referredUsers++
}
}
}

ape.Render(w, newBalanceResponse(*balance, referrals))
ape.Render(w, newBalanceResponse(*balance, referrals, referredUsers))
}

// newBalanceModel forms a balance response without referral fields, which must
Expand All @@ -75,12 +93,13 @@ func newBalanceModel(balance data.Balance) resources.Balance {
}
}

func newBalanceResponse(balance data.Balance, referrals []data.Referral) resources.BalanceResponse {
func newBalanceResponse(balance data.Balance, referrals []data.Referral, referredUsers int) resources.BalanceResponse {
resp := resources.BalanceResponse{Data: newBalanceModel(balance)}
boolP := func(b bool) *bool { return &b }

resp.Data.Attributes.IsDisabled = boolP(balance.ReferredBy == nil)
resp.Data.Attributes.IsVerified = boolP(balance.IsVerified)
resp.Data.Attributes.ReferredUsersCount = &referredUsers

if len(referrals) == 0 {
return resp
Expand Down
61 changes: 61 additions & 0 deletions internal/service/handlers/list_qr_event_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package handlers

import (
"net/http"

"github.com/rarimo/geo-auth-svc/pkg/auth"
"github.com/rarimo/geo-points-svc/internal/data"
"github.com/rarimo/geo-points-svc/internal/data/evtypes"
"github.com/rarimo/geo-points-svc/internal/data/evtypes/models"
"github.com/rarimo/geo-points-svc/internal/service/requests"
"github.com/rarimo/geo-points-svc/resources"
"gitlab.com/distributed_lab/ape"
"gitlab.com/distributed_lab/ape/problems"
)

func ListQREventTypes(w http.ResponseWriter, r *http.Request) {
req, err := requests.NewListEventTypes(r)
if err != nil {
ape.RenderErr(w, problems.BadRequest(err)...)
return
}

if !auth.Authenticates(UserClaims(r), auth.AdminGrant) {
ape.RenderErr(w, problems.Unauthorized())
return
}

types := EventTypes(r).List(
func(ev models.EventType) bool {
return ev.QRCodeValue == nil
},
evtypes.FilterByNames(req.FilterName...),
evtypes.FilterByFlags(req.FilterFlag...),
func(ev models.EventType) bool {
return len(req.FilterNotName) > 0 && !evtypes.FilterByNames(req.FilterNotName...)(ev)
},
)

resTypes := make([]resources.EventType, len(types))
for i, t := range types {
resTypes[i] = resources.EventType{
Key: resources.Key{
ID: t.Name,
Type: resources.EVENT_TYPE,
},
Attributes: t.Resource(),
}
resTypes[i].Attributes.QrCodeValue = t.QRCodeValue
if req.Count {
evCount, err := EventsQ(r).FilterByType(t.Name).FilterByStatus(data.EventFulfilled, data.EventClaimed).Count()
if err != nil {
Log(r).WithError(err).Errorf("failed to get %s event usage count", t.Name)
ape.RenderErr(w, problems.InternalError())
return
}
resTypes[i].Attributes.UsageCount = &evCount
}
}

ape.Render(w, resources.EventTypeListResponse{Data: resTypes})
}
4 changes: 3 additions & 1 deletion internal/service/handlers/update_event_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ func UpdateEventType(w http.ResponseWriter, r *http.Request) {
}

EventTypes(r).Push(typeModel)
ape.Render(w, newEventTypeResponse(res[0]))
resp := newEventTypeResponse(res[0])
resp.Data.Attributes.QrCodeValue = typeModel.QRCodeValue
ape.Render(w, resp)
}

func newEventTypeResponse(evType models.EventType) resources.EventTypeResponse {
Expand Down
1 change: 1 addition & 0 deletions internal/service/requests/list_event_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type ListExpiredEvents struct {
FilterName []string `filter:"name"`
FilterFlag []string `filter:"flag"`
FilterNotName []string `url:"filter[name][not]"`
Count bool `url:"count"`
}

func NewListEventTypes(r *http.Request) (req ListExpiredEvents, err error) {
Expand Down
1 change: 1 addition & 0 deletions internal/service/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func Run(ctx context.Context, cfg config.Config) {
})
r.Get("/balances", handlers.Leaderboard)
r.Route("/event_types", func(r chi.Router) {
r.With(authMW).Get("/qr", handlers.ListQREventTypes)
r.Get("/", handlers.ListEventTypes)
r.With(authMW).Post("/", handlers.CreateEventType)
r.Get("/{name}", handlers.GetEventType)
Expand Down
2 changes: 2 additions & 0 deletions resources/model_balance_attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type BalanceAttributes struct {
Rank *int `json:"rank,omitempty"`
// Referral codes. Returned only for the single user.
ReferralCodes *[]ReferralCode `json:"referral_codes,omitempty"`
// Number of invited users
ReferredUsersCount *int `json:"referred_users_count,omitempty"`
// Unix timestamp of the last points accruing
UpdatedAt int32 `json:"updated_at"`
}
2 changes: 2 additions & 0 deletions resources/model_event_static_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ type EventStaticMeta struct {
// General event starting date (UTC RFC3339)
StartsAt *time.Time `json:"starts_at,omitempty"`
Title string `json:"title"`
// Number of uses. Only available to the administrator.
UsageCount *int `json:"usage_count,omitempty"`
}
Loading