Merge pull request #23 from mxpv/pledge_check

Improve pledge verification
This commit is contained in:
Maksym Pavlenko
2017-11-02 18:38:34 -07:00
committed by GitHub
co-authored by GitHub
11 changed files with 239 additions and 134 deletions
+6 -2
View File
@@ -20,6 +20,7 @@ import (
"github.com/mxpv/podsync/pkg/handler"
"github.com/mxpv/podsync/pkg/id"
"github.com/mxpv/podsync/pkg/storage"
"github.com/mxpv/podsync/pkg/support"
"github.com/pkg/errors"
)
@@ -47,11 +48,13 @@ func main() {
panic(err)
}
pg, err := createPg(cfg.PostgresConnectionURL)
database, err := createPg(cfg.PostgresConnectionURL)
if err != nil {
panic(err)
}
patreon := support.NewPatreon(database)
// Builders
youtube, err := builders.NewYouTubeBuilder(cfg.YouTubeApiKey)
@@ -73,7 +76,7 @@ func main() {
srv := http.Server{
Addr: fmt.Sprintf(":%d", 5001),
Handler: handler.New(feed, pg, cfg),
Handler: handler.New(feed, patreon, cfg),
}
go func() {
@@ -88,6 +91,7 @@ func main() {
log.Printf("shutting down server")
srv.Shutdown(ctx)
database.Close()
log.Printf("server gracefully stopped")
}
+17 -4
View File
@@ -13,9 +13,22 @@ const (
maxPageSize = 150
)
type idService interface {
Generate(feed *api.Feed) (string, error)
}
type storageService interface {
CreateFeed(feed *api.Feed) error
GetFeed(hashId string) (*api.Feed, error)
}
type builder interface {
Build(feed *api.Feed) (podcast *itunes.Podcast, err error)
}
type service struct {
id id
storage storage
id idService
storage storageService
builders map[api.Provider]builder
}
@@ -85,13 +98,13 @@ func (s *service) GetMetadata(hashId string) (*api.Feed, error) {
type feedOption func(*service)
func WithStorage(storage storage) feedOption {
func WithStorage(storage storageService) feedOption {
return func(service *service) {
service.storage = storage
}
}
func WithIdGen(id id) feedOption {
func WithIdGen(id idService) feedOption {
return func(service *service) {
service.id = id
}
@@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: interfaces.go
// Source: feeds.go
package feeds
@@ -10,31 +10,31 @@ import (
reflect "reflect"
)
// Mockid is a mock of id interface
type Mockid struct {
// MockidService is a mock of idService interface
type MockidService struct {
ctrl *gomock.Controller
recorder *MockidMockRecorder
recorder *MockidServiceMockRecorder
}
// MockidMockRecorder is the mock recorder for Mockid
type MockidMockRecorder struct {
mock *Mockid
// MockidServiceMockRecorder is the mock recorder for MockidService
type MockidServiceMockRecorder struct {
mock *MockidService
}
// NewMockid creates a new mock instance
func NewMockid(ctrl *gomock.Controller) *Mockid {
mock := &Mockid{ctrl: ctrl}
mock.recorder = &MockidMockRecorder{mock}
// NewMockidService creates a new mock instance
func NewMockidService(ctrl *gomock.Controller) *MockidService {
mock := &MockidService{ctrl: ctrl}
mock.recorder = &MockidServiceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (_m *Mockid) EXPECT() *MockidMockRecorder {
func (_m *MockidService) EXPECT() *MockidServiceMockRecorder {
return _m.recorder
}
// Generate mocks base method
func (_m *Mockid) Generate(feed *api.Feed) (string, error) {
func (_m *MockidService) Generate(feed *api.Feed) (string, error) {
ret := _m.ctrl.Call(_m, "Generate", feed)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
@@ -42,47 +42,47 @@ func (_m *Mockid) Generate(feed *api.Feed) (string, error) {
}
// Generate indicates an expected call of Generate
func (_mr *MockidMockRecorder) Generate(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "Generate", reflect.TypeOf((*Mockid)(nil).Generate), arg0)
func (_mr *MockidServiceMockRecorder) Generate(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "Generate", reflect.TypeOf((*MockidService)(nil).Generate), arg0)
}
// Mockstorage is a mock of storage interface
type Mockstorage struct {
// MockstorageService is a mock of storageService interface
type MockstorageService struct {
ctrl *gomock.Controller
recorder *MockstorageMockRecorder
recorder *MockstorageServiceMockRecorder
}
// MockstorageMockRecorder is the mock recorder for Mockstorage
type MockstorageMockRecorder struct {
mock *Mockstorage
// MockstorageServiceMockRecorder is the mock recorder for MockstorageService
type MockstorageServiceMockRecorder struct {
mock *MockstorageService
}
// NewMockstorage creates a new mock instance
func NewMockstorage(ctrl *gomock.Controller) *Mockstorage {
mock := &Mockstorage{ctrl: ctrl}
mock.recorder = &MockstorageMockRecorder{mock}
// NewMockstorageService creates a new mock instance
func NewMockstorageService(ctrl *gomock.Controller) *MockstorageService {
mock := &MockstorageService{ctrl: ctrl}
mock.recorder = &MockstorageServiceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (_m *Mockstorage) EXPECT() *MockstorageMockRecorder {
func (_m *MockstorageService) EXPECT() *MockstorageServiceMockRecorder {
return _m.recorder
}
// CreateFeed mocks base method
func (_m *Mockstorage) CreateFeed(feed *api.Feed) error {
func (_m *MockstorageService) CreateFeed(feed *api.Feed) error {
ret := _m.ctrl.Call(_m, "CreateFeed", feed)
ret0, _ := ret[0].(error)
return ret0
}
// CreateFeed indicates an expected call of CreateFeed
func (_mr *MockstorageMockRecorder) CreateFeed(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "CreateFeed", reflect.TypeOf((*Mockstorage)(nil).CreateFeed), arg0)
func (_mr *MockstorageServiceMockRecorder) CreateFeed(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "CreateFeed", reflect.TypeOf((*MockstorageService)(nil).CreateFeed), arg0)
}
// GetFeed mocks base method
func (_m *Mockstorage) GetFeed(hashId string) (*api.Feed, error) {
func (_m *MockstorageService) GetFeed(hashId string) (*api.Feed, error) {
ret := _m.ctrl.Call(_m, "GetFeed", hashId)
ret0, _ := ret[0].(*api.Feed)
ret1, _ := ret[1].(error)
@@ -90,8 +90,8 @@ func (_m *Mockstorage) GetFeed(hashId string) (*api.Feed, error) {
}
// GetFeed indicates an expected call of GetFeed
func (_mr *MockstorageMockRecorder) GetFeed(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "GetFeed", reflect.TypeOf((*Mockstorage)(nil).GetFeed), arg0)
func (_mr *MockstorageServiceMockRecorder) GetFeed(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "GetFeed", reflect.TypeOf((*MockstorageService)(nil).GetFeed), arg0)
}
// Mockbuilder is a mock of builder interface
+5 -5
View File
@@ -1,4 +1,4 @@
//go:generate mockgen -source=interfaces.go -destination=interfaces_mock_test.go -package=feeds
//go:generate mockgen -source=feeds.go -destination=feeds_mock_test.go -package=feeds
package feeds
@@ -14,10 +14,10 @@ func TestService_CreateFeed(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
id := NewMockid(ctrl)
id := NewMockidService(ctrl)
id.EXPECT().Generate(gomock.Any()).Times(1).Return("123", nil)
storage := NewMockstorage(ctrl)
storage := NewMockstorageService(ctrl)
storage.EXPECT().CreateFeed(gomock.Any()).Times(1).Return(nil)
s := service{
@@ -44,7 +44,7 @@ func TestService_GetFeed(t *testing.T) {
feed := &api.Feed{Provider: api.Youtube}
storage := NewMockstorage(ctrl)
storage := NewMockstorageService(ctrl)
storage.EXPECT().GetFeed("123").Times(1).Return(feed, nil)
bld := NewMockbuilder(ctrl)
@@ -63,7 +63,7 @@ func TestService_GetMetadata(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
storage := NewMockstorage(ctrl)
storage := NewMockstorageService(ctrl)
storage.EXPECT().GetFeed("123").Times(1).Return(&api.Feed{}, nil)
s := service{storage: storage}
-19
View File
@@ -1,19 +0,0 @@
package feeds
import (
itunes "github.com/mxpv/podcast"
"github.com/mxpv/podsync/pkg/api"
)
type id interface {
Generate(feed *api.Feed) (string, error)
}
type storage interface {
CreateFeed(feed *api.Feed) error
GetFeed(hashId string) (*api.Feed, error)
}
type builder interface {
Build(feed *api.Feed) (podcast *itunes.Podcast, err error)
}
+20 -31
View File
@@ -10,32 +10,34 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/go-pg/pg"
"github.com/mxpv/patreon-go"
patreon "github.com/mxpv/patreon-go"
itunes "github.com/mxpv/podcast"
"github.com/mxpv/podsync/pkg/api"
"github.com/mxpv/podsync/pkg/config"
"github.com/mxpv/podsync/pkg/session"
"github.com/mxpv/podsync/pkg/webhook"
"golang.org/x/oauth2"
)
const (
creatorID = "2822191"
maxHashIDLength = 16
)
type feed interface {
type feedService interface {
CreateFeed(req *api.CreateFeedRequest, identity *api.Identity) (string, error)
GetFeed(hashId string) (*itunes.Podcast, error)
GetMetadata(hashId string) (*api.Feed, error)
}
type patreonService interface {
Hook(pledge *patreon.Pledge, event string) error
GetFeatureLevel(patronID string) int
}
type handler struct {
feed feed
cfg *config.AppConfig
oauth2 oauth2.Config
hook *webhook.Handler
feed feedService
cfg *config.AppConfig
oauth2 oauth2.Config
patreon patreonService
}
func (h handler) index(c *gin.Context) {
@@ -90,23 +92,7 @@ func (h handler) patreonCallback(c *gin.Context) {
}
// Determine feature level
level := api.DefaultFeatures
if user.Data.ID == creatorID {
level = api.PodcasterFeature
} else {
amount := 0
for _, item := range user.Included.Items {
pledge, ok := item.(*patreon.Pledge)
if ok {
amount += pledge.Attributes.AmountCents
}
}
if amount >= 100 {
level = api.ExtendedFeatures
}
}
level := h.patreon.GetFeatureLevel(user.Data.ID)
identity := &api.Identity{
UserId: user.Data.ID,
@@ -145,6 +131,9 @@ func (h handler) create(c *gin.Context) {
return
}
// Check feature level again if user deleted pledge by still logged in
identity.FeatureLevel = h.patreon.GetFeatureLevel(identity.UserId)
hashId, err := h.feed.CreateFeed(req, identity)
if err != nil {
c.JSON(internalError(err))
@@ -235,7 +224,7 @@ func (h handler) webhook(c *gin.Context) {
return
}
if err := h.hook.Handle(&pledge.Data, eventName); err != nil {
if err := h.patreon.Hook(&pledge.Data, eventName); err != nil {
log.Printf("failed to process patreon event %s (%s): %v", pledge.Data.ID, eventName, err)
c.JSON(internalError(err))
return
@@ -244,7 +233,7 @@ func (h handler) webhook(c *gin.Context) {
log.Printf("sucessfully processed patreon event %s (%s)", pledge.Data.ID, eventName)
}
func New(feed feed, db *pg.DB, cfg *config.AppConfig) http.Handler {
func New(feed feedService, support patreonService, cfg *config.AppConfig) http.Handler {
r := gin.New()
r.Use(gin.Recovery())
@@ -264,9 +253,9 @@ func New(feed feed, db *pg.DB, cfg *config.AppConfig) http.Handler {
}
h := handler{
feed: feed,
cfg: cfg,
hook: webhook.NewHookHandler(db),
feed: feed,
patreon: support,
cfg: cfg,
}
// OAuth 2 configuration
+68 -20
View File
@@ -5,36 +5,37 @@ package handler
import (
gomock "github.com/golang/mock/gomock"
patreon_go "github.com/mxpv/patreon-go"
podcast "github.com/mxpv/podcast"
api "github.com/mxpv/podsync/pkg/api"
reflect "reflect"
)
// Mockfeed is a mock of feed interface
type Mockfeed struct {
// MockfeedService is a mock of feedService interface
type MockfeedService struct {
ctrl *gomock.Controller
recorder *MockfeedMockRecorder
recorder *MockfeedServiceMockRecorder
}
// MockfeedMockRecorder is the mock recorder for Mockfeed
type MockfeedMockRecorder struct {
mock *Mockfeed
// MockfeedServiceMockRecorder is the mock recorder for MockfeedService
type MockfeedServiceMockRecorder struct {
mock *MockfeedService
}
// NewMockfeed creates a new mock instance
func NewMockfeed(ctrl *gomock.Controller) *Mockfeed {
mock := &Mockfeed{ctrl: ctrl}
mock.recorder = &MockfeedMockRecorder{mock}
// NewMockfeedService creates a new mock instance
func NewMockfeedService(ctrl *gomock.Controller) *MockfeedService {
mock := &MockfeedService{ctrl: ctrl}
mock.recorder = &MockfeedServiceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (_m *Mockfeed) EXPECT() *MockfeedMockRecorder {
func (_m *MockfeedService) EXPECT() *MockfeedServiceMockRecorder {
return _m.recorder
}
// CreateFeed mocks base method
func (_m *Mockfeed) CreateFeed(req *api.CreateFeedRequest, identity *api.Identity) (string, error) {
func (_m *MockfeedService) CreateFeed(req *api.CreateFeedRequest, identity *api.Identity) (string, error) {
ret := _m.ctrl.Call(_m, "CreateFeed", req, identity)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
@@ -42,12 +43,12 @@ func (_m *Mockfeed) CreateFeed(req *api.CreateFeedRequest, identity *api.Identit
}
// CreateFeed indicates an expected call of CreateFeed
func (_mr *MockfeedMockRecorder) CreateFeed(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "CreateFeed", reflect.TypeOf((*Mockfeed)(nil).CreateFeed), arg0, arg1)
func (_mr *MockfeedServiceMockRecorder) CreateFeed(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "CreateFeed", reflect.TypeOf((*MockfeedService)(nil).CreateFeed), arg0, arg1)
}
// GetFeed mocks base method
func (_m *Mockfeed) GetFeed(hashId string) (*podcast.Podcast, error) {
func (_m *MockfeedService) GetFeed(hashId string) (*podcast.Podcast, error) {
ret := _m.ctrl.Call(_m, "GetFeed", hashId)
ret0, _ := ret[0].(*podcast.Podcast)
ret1, _ := ret[1].(error)
@@ -55,12 +56,12 @@ func (_m *Mockfeed) GetFeed(hashId string) (*podcast.Podcast, error) {
}
// GetFeed indicates an expected call of GetFeed
func (_mr *MockfeedMockRecorder) GetFeed(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "GetFeed", reflect.TypeOf((*Mockfeed)(nil).GetFeed), arg0)
func (_mr *MockfeedServiceMockRecorder) GetFeed(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "GetFeed", reflect.TypeOf((*MockfeedService)(nil).GetFeed), arg0)
}
// GetMetadata mocks base method
func (_m *Mockfeed) GetMetadata(hashId string) (*api.Feed, error) {
func (_m *MockfeedService) GetMetadata(hashId string) (*api.Feed, error) {
ret := _m.ctrl.Call(_m, "GetMetadata", hashId)
ret0, _ := ret[0].(*api.Feed)
ret1, _ := ret[1].(error)
@@ -68,6 +69,53 @@ func (_m *Mockfeed) GetMetadata(hashId string) (*api.Feed, error) {
}
// GetMetadata indicates an expected call of GetMetadata
func (_mr *MockfeedMockRecorder) GetMetadata(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "GetMetadata", reflect.TypeOf((*Mockfeed)(nil).GetMetadata), arg0)
func (_mr *MockfeedServiceMockRecorder) GetMetadata(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "GetMetadata", reflect.TypeOf((*MockfeedService)(nil).GetMetadata), arg0)
}
// MockpatreonService is a mock of patreonService interface
type MockpatreonService struct {
ctrl *gomock.Controller
recorder *MockpatreonServiceMockRecorder
}
// MockpatreonServiceMockRecorder is the mock recorder for MockpatreonService
type MockpatreonServiceMockRecorder struct {
mock *MockpatreonService
}
// NewMockpatreonService creates a new mock instance
func NewMockpatreonService(ctrl *gomock.Controller) *MockpatreonService {
mock := &MockpatreonService{ctrl: ctrl}
mock.recorder = &MockpatreonServiceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (_m *MockpatreonService) EXPECT() *MockpatreonServiceMockRecorder {
return _m.recorder
}
// Hook mocks base method
func (_m *MockpatreonService) Hook(pledge *patreon_go.Pledge, event string) error {
ret := _m.ctrl.Call(_m, "Hook", pledge, event)
ret0, _ := ret[0].(error)
return ret0
}
// Hook indicates an expected call of Hook
func (_mr *MockpatreonServiceMockRecorder) Hook(arg0, arg1 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "Hook", reflect.TypeOf((*MockpatreonService)(nil).Hook), arg0, arg1)
}
// GetFeatureLevel mocks base method
func (_m *MockpatreonService) GetFeatureLevel(patronID string) int {
ret := _m.ctrl.Call(_m, "GetFeatureLevel", patronID)
ret0, _ := ret[0].(int)
return ret0
}
// GetFeatureLevel indicates an expected call of GetFeatureLevel
func (_mr *MockpatreonServiceMockRecorder) GetFeatureLevel(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCallWithMethodType(_mr.mock, "GetFeatureLevel", reflect.TypeOf((*MockpatreonService)(nil).GetFeatureLevel), arg0)
}
+8 -5
View File
@@ -29,10 +29,13 @@ func TestCreateFeed(t *testing.T) {
Format: api.AudioFormat,
}
feed := NewMockfeed(ctrl)
feed := NewMockfeedService(ctrl)
feed.EXPECT().CreateFeed(gomock.Eq(req), gomock.Any()).Times(1).Return("456", nil)
srv := httptest.NewServer(New(feed, nil, cfg))
patreon := NewMockpatreonService(ctrl)
patreon.EXPECT().GetFeatureLevel(gomock.Any()).Return(api.DefaultFeatures)
srv := httptest.NewServer(New(feed, patreon, cfg))
defer srv.Close()
query := `{"url": "https://youtube.com/channel/123", "page_size": 55, "quality": "low", "format": "audio"}`
@@ -47,7 +50,7 @@ func TestCreateInvalidFeed(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
srv := httptest.NewServer(New(NewMockfeed(ctrl), nil, cfg))
srv := httptest.NewServer(New(NewMockfeedService(ctrl), nil, cfg))
defer srv.Close()
query := `{}`
@@ -97,7 +100,7 @@ func TestGetFeed(t *testing.T) {
podcast := itunes.New("", "", "", nil, nil)
feed := NewMockfeed(ctrl)
feed := NewMockfeedService(ctrl)
feed.EXPECT().GetFeed("123").Return(&podcast, nil)
srv := httptest.NewServer(New(feed, nil, cfg))
@@ -112,7 +115,7 @@ func TestGetMetadata(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
feed := NewMockfeed(ctrl)
feed := NewMockfeedService(ctrl)
feed.EXPECT().GetMetadata("123").Times(1).Return(&api.Feed{}, nil)
srv := httptest.NewServer(New(feed, nil, cfg))
+1 -1
View File
@@ -2,7 +2,7 @@ BEGIN;
CREATE TABLE IF NOT EXISTS pledges (
pledge_id BIGSERIAL PRIMARY KEY,
patron_id BIGINT NOT NULL ,
patron_id BIGINT NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL,
declined_since TIMESTAMPTZ NULL,
amount_cents INT NOT NULL,
+49 -7
View File
@@ -1,20 +1,26 @@
package webhook
package support
import (
"fmt"
"log"
"strconv"
"github.com/go-pg/pg"
"github.com/mxpv/patreon-go"
"github.com/mxpv/podsync/pkg/api"
"github.com/mxpv/podsync/pkg/models"
"github.com/pkg/errors"
)
type Handler struct {
const (
creatorID = "2822191"
)
type Patreon struct {
db *pg.DB
}
func (h Handler) toModel(pledge *patreon.Pledge) (*models.Pledge, error) {
func (h Patreon) toModel(pledge *patreon.Pledge) (*models.Pledge, error) {
pledgeID, err := strconv.ParseInt(pledge.ID, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse pledge id: %s", pledge.ID)
@@ -56,7 +62,7 @@ func (h Handler) toModel(pledge *patreon.Pledge) (*models.Pledge, error) {
return model, nil
}
func (h Handler) Handle(pledge *patreon.Pledge, event string) error {
func (h Patreon) Hook(pledge *patreon.Pledge, event string) error {
model, err := h.toModel(pledge)
if err != nil {
return err
@@ -68,12 +74,48 @@ func (h Handler) Handle(pledge *patreon.Pledge, event string) error {
case patreon.EventUpdatePledge:
return h.db.Update(model)
case patreon.EventDeletePledge:
return h.db.Delete(model)
err := h.db.Delete(model)
if err == pg.ErrNoRows {
return nil
}
return err
default:
return fmt.Errorf("unknown event: %s", event)
}
}
func NewHookHandler(db *pg.DB) *Handler {
return &Handler{db: db}
func (h Patreon) FindPledge(patronID string) (*models.Pledge, error) {
p := &models.Pledge{}
return p, h.db.Model(p).Where("patron_id = ?", patronID).Limit(1).Select()
}
func (h Patreon) GetFeatureLevel(patronID string) (level int) {
level = api.DefaultFeatures
if patronID == creatorID {
level = api.PodcasterFeature
return
}
pledge, err := h.FindPledge(patronID)
if err != nil {
log.Printf("! can't find pledge for user %s: %v", patronID, err)
return
}
// Check pledge is valid
if pledge.DeclinedSince.IsZero() && !pledge.IsPaused {
// Check the amount of pledge
if pledge.AmountCents >= 100 {
level = api.ExtendedFeatures
return
}
}
return
}
func NewPatreon(db *pg.DB) *Patreon {
return &Patreon{db: db}
}
@@ -1,4 +1,4 @@
package webhook
package support
import (
"testing"
@@ -6,6 +6,7 @@ import (
"github.com/go-pg/pg"
"github.com/mxpv/patreon-go"
"github.com/mxpv/podsync/pkg/api"
"github.com/mxpv/podsync/pkg/models"
"github.com/stretchr/testify/require"
)
@@ -14,7 +15,7 @@ func TestCreate(t *testing.T) {
pledge := createPledge()
hook := createHandler(t)
err := hook.Handle(pledge, patreon.EventCreatePledge)
err := hook.Hook(pledge, patreon.EventCreatePledge)
require.NoError(t, err)
model := &models.Pledge{PledgeID: 12345}
@@ -27,12 +28,12 @@ func TestUpdate(t *testing.T) {
pledge := createPledge()
hook := createHandler(t)
err := hook.Handle(pledge, patreon.EventCreatePledge)
err := hook.Hook(pledge, patreon.EventCreatePledge)
require.NoError(t, err)
pledge.Attributes.AmountCents = 999
err = hook.Handle(pledge, patreon.EventUpdatePledge)
err = hook.Hook(pledge, patreon.EventUpdatePledge)
require.NoError(t, err)
model := &models.Pledge{PledgeID: 12345}
@@ -45,14 +46,38 @@ func TestDelete(t *testing.T) {
pledge := createPledge()
hook := createHandler(t)
err := hook.Handle(pledge, patreon.EventCreatePledge)
err := hook.Hook(pledge, patreon.EventCreatePledge)
require.NoError(t, err)
err = hook.Handle(pledge, patreon.EventDeletePledge)
err = hook.Hook(pledge, patreon.EventDeletePledge)
require.NoError(t, err)
}
func createHandler(t *testing.T) *Handler {
func TestFindPledge(t *testing.T) {
pledge := createPledge()
hook := createHandler(t)
err := hook.Hook(pledge, patreon.EventCreatePledge)
require.NoError(t, err)
res, err := hook.FindPledge("67890")
require.NoError(t, err)
require.Equal(t, res.AmountCents, pledge.Attributes.AmountCents)
}
func TestGetFeatureLevel(t *testing.T) {
pledge := createPledge()
hook := createHandler(t)
err := hook.Hook(pledge, patreon.EventCreatePledge)
require.NoError(t, err)
require.Equal(t, api.PodcasterFeature, hook.GetFeatureLevel(creatorID))
require.Equal(t, api.DefaultFeatures, hook.GetFeatureLevel("xyz"))
require.Equal(t, api.ExtendedFeatures, hook.GetFeatureLevel(pledge.Relationships.Patron.Data.ID))
}
func createHandler(t *testing.T) *Patreon {
opts, err := pg.ParseURL("postgres://postgres:@localhost/podsync?sslmode=disable")
if err != nil {
require.NoError(t, err)
@@ -63,7 +88,7 @@ func createHandler(t *testing.T) *Handler {
_, err = db.Model(&models.Pledge{}).Where("1=1").Delete()
require.NoError(t, err)
return NewHookHandler(db)
return NewPatreon(db)
}
func createPledge() *patreon.Pledge {