mirror of
https://github.com/mxpv/podsync.git
synced 2024-05-11 05:55:04 +00:00
Merge pull request #23 from mxpv/pledge_check
Improve pledge verification
This commit is contained in:
+6
-2
@@ -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
@@ -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
|
||||
@@ -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}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
Reference in New Issue
Block a user