2019-11-05 12:58:09 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package rewards
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-11-12 13:43:03 +00:00
|
|
|
"encoding/base32"
|
2019-11-05 12:58:09 +00:00
|
|
|
"path"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
"go.uber.org/zap"
|
2019-11-26 11:12:37 +00:00
|
|
|
|
2019-12-27 11:48:47 +00:00
|
|
|
"storj.io/common/useragent"
|
2019-11-05 12:58:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2019-11-06 18:37:53 +00:00
|
|
|
// ErrPartners is the default error class for partners package.
|
|
|
|
ErrPartners = errs.Class("partners")
|
2019-11-05 12:58:09 +00:00
|
|
|
|
2019-11-06 18:37:53 +00:00
|
|
|
// ErrPartnerNotExist is returned when a particular partner does not exist.
|
|
|
|
ErrPartnerNotExist = errs.Class("partner does not exist")
|
2019-11-05 12:58:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// PartnersDB allows access to partners database.
|
|
|
|
//
|
|
|
|
// architecture: Database
|
|
|
|
type PartnersDB interface {
|
|
|
|
// All returns all partners.
|
|
|
|
All(ctx context.Context) ([]PartnerInfo, error)
|
|
|
|
// ByName returns partner definitions for a given name.
|
|
|
|
ByName(ctx context.Context, name string) (PartnerInfo, error)
|
|
|
|
// ByID returns partner definition corresponding to an id.
|
|
|
|
ByID(ctx context.Context, id string) (PartnerInfo, error)
|
|
|
|
// ByUserAgent returns partner definition corresponding to an user agent string.
|
|
|
|
ByUserAgent(ctx context.Context, agent string) (PartnerInfo, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// PartnersService allows manipulating and accessing partner information.
|
|
|
|
//
|
|
|
|
// architecture: Service
|
|
|
|
type PartnersService struct {
|
|
|
|
log *zap.Logger
|
|
|
|
db PartnersDB
|
|
|
|
domains []string
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPartnersService returns a service for handling partner information.
|
|
|
|
func NewPartnersService(log *zap.Logger, db PartnersDB, domains []string) *PartnersService {
|
|
|
|
return &PartnersService{
|
|
|
|
log: log,
|
|
|
|
db: db,
|
|
|
|
domains: domains,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// parnterIDEncoding is base32 without padding.
|
2019-11-12 13:43:03 +00:00
|
|
|
var parnterIDEncoding = base32.StdEncoding.WithPadding(base32.NoPadding)
|
|
|
|
|
|
|
|
// GeneratePartnerLink returns partner referral link.
|
2019-11-05 12:58:09 +00:00
|
|
|
func (service *PartnersService) GeneratePartnerLink(ctx context.Context, offerName string) ([]string, error) {
|
|
|
|
partner, err := service.db.ByName(ctx, offerName)
|
|
|
|
if err != nil {
|
2019-11-06 18:37:53 +00:00
|
|
|
return nil, ErrPartners.Wrap(err)
|
2019-11-05 12:58:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var links []string
|
|
|
|
for _, domain := range service.domains {
|
2019-11-12 13:43:03 +00:00
|
|
|
encoded := parnterIDEncoding.EncodeToString([]byte(partner.ID))
|
2019-11-05 12:58:09 +00:00
|
|
|
links = append(links, path.Join(domain, "ref", encoded))
|
|
|
|
}
|
|
|
|
|
|
|
|
return links, nil
|
|
|
|
}
|
|
|
|
|
2019-11-06 18:37:53 +00:00
|
|
|
// GetActiveOffer returns an offer that is active based on its type.
|
2019-11-05 12:58:09 +00:00
|
|
|
func (service *PartnersService) GetActiveOffer(ctx context.Context, offers Offers, offerType OfferType, partnerID string) (offer *Offer, err error) {
|
|
|
|
if len(offers) < 1 {
|
2019-11-06 18:37:53 +00:00
|
|
|
return nil, ErrOfferNotExist.New("no active offers")
|
2019-11-05 12:58:09 +00:00
|
|
|
}
|
|
|
|
switch offerType {
|
|
|
|
case Partner:
|
|
|
|
if partnerID == "" {
|
|
|
|
return nil, errs.New("partner ID is empty")
|
|
|
|
}
|
|
|
|
partnerInfo, err := service.db.ByID(ctx, partnerID)
|
|
|
|
if err != nil {
|
2019-11-06 18:37:53 +00:00
|
|
|
return nil, ErrPartnerNotExist.Wrap(err)
|
2019-11-05 12:58:09 +00:00
|
|
|
}
|
|
|
|
for i := range offers {
|
|
|
|
if offers[i].Name == partnerInfo.Name {
|
|
|
|
offer = &offers[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
if len(offers) > 1 {
|
|
|
|
return nil, errs.New("multiple active offers found")
|
|
|
|
}
|
|
|
|
offer = &offers[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
return offer, nil
|
|
|
|
}
|
|
|
|
|
2019-11-26 11:12:37 +00:00
|
|
|
// ByName looks up partner by name.
|
|
|
|
func (service *PartnersService) ByName(ctx context.Context, name string) (PartnerInfo, error) {
|
2019-11-05 12:58:09 +00:00
|
|
|
return service.db.ByName(ctx, name)
|
|
|
|
}
|
|
|
|
|
2019-11-26 11:12:37 +00:00
|
|
|
// ByUserAgent looks up partner by user agent.
|
|
|
|
func (service *PartnersService) ByUserAgent(ctx context.Context, userAgentString string) (PartnerInfo, error) {
|
|
|
|
info, err := useragent.Parse(userAgentString)
|
|
|
|
if err != nil {
|
|
|
|
return PartnerInfo{}, ErrPartners.Wrap(err)
|
|
|
|
}
|
|
|
|
|
2020-07-28 15:23:17 +01:00
|
|
|
return service.db.ByUserAgent(ctx, info.Product.Name)
|
2019-11-26 11:12:37 +00:00
|
|
|
}
|
|
|
|
|
2019-11-05 12:58:09 +00:00
|
|
|
// All returns all partners.
|
|
|
|
func (service *PartnersService) All(ctx context.Context) ([]PartnerInfo, error) {
|
|
|
|
return service.db.All(ctx)
|
|
|
|
}
|