Jelajahi Sumber

Make it easy to build without Stripe

binwiederhier 6 bulan lalu
induk
melakukan
ea338ae4fa

+ 4 - 3
cmd/serve.go

@@ -16,10 +16,10 @@ import (
 	"syscall"
 	"time"
 
-	"github.com/stripe/stripe-go/v74"
 	"github.com/urfave/cli/v2"
 	"github.com/urfave/cli/v2/altsrc"
 	"heckel.io/ntfy/v2/log"
+	"heckel.io/ntfy/v2/payments"
 	"heckel.io/ntfy/v2/server"
 	"heckel.io/ntfy/v2/user"
 	"heckel.io/ntfy/v2/util"
@@ -320,6 +320,8 @@ func execServe(c *cli.Context) error {
 		return errors.New("cannot set enable-signup, enable-login, enable-reserve-topics, or stripe-secret-key if auth-file is not set")
 	} else if enableSignup && !enableLogin {
 		return errors.New("cannot set enable-signup without also setting enable-login")
+	} else if !payments.Available && (stripeSecretKey != "" || stripeWebhookKey != "") {
+		return errors.New("cannot set stripe-secret-key or stripe-webhook-key, support for payments is not available in this build (nopayments)")
 	} else if stripeSecretKey != "" && (stripeWebhookKey == "" || baseURL == "") {
 		return errors.New("if stripe-secret-key is set, stripe-webhook-key and base-url must also be set")
 	} else if twilioAccount != "" && (twilioAuthToken == "" || twilioPhoneNumber == "" || twilioVerifyService == "" || baseURL == "" || authFile == "") {
@@ -396,8 +398,7 @@ func execServe(c *cli.Context) error {
 
 	// Stripe things
 	if stripeSecretKey != "" {
-		stripe.EnableTelemetry = false // Whoa!
-		stripe.Key = stripeSecretKey
+		payments.Setup(stripeSecretKey)
 	}
 
 	// Add default forbidden topics

+ 23 - 10
main.go

@@ -3,9 +3,11 @@ package main
 import (
 	"fmt"
 	"github.com/urfave/cli/v2"
+	"go/build"
 	"heckel.io/ntfy/v2/cmd"
 	"os"
 	"runtime"
+	"strings"
 )
 
 var (
@@ -15,16 +17,7 @@ var (
 )
 
 func main() {
-	cli.AppHelpTemplate += fmt.Sprintf(`
-Try 'ntfy COMMAND --help' or https://ntfy.sh/docs/ for more information.
-
-To report a bug, open an issue on GitHub: https://github.com/binwiederhier/ntfy/issues.
-If you want to chat, simply join the Discord server (https://discord.gg/cT7ECsZj9w), or
-the Matrix room (https://matrix.to/#/#ntfy:matrix.org).
-
-ntfy %s (%s), runtime %s, built at %s
-Copyright (C) Philipp C. Heckel, licensed under Apache License 2.0 & GPLv2
-`, version, commit[:7], runtime.Version(), date)
+	cli.AppHelpTemplate += buildHelp()
 
 	app := cmd.New()
 	app.Version = version
@@ -34,3 +27,23 @@ Copyright (C) Philipp C. Heckel, licensed under Apache License 2.0 & GPLv2
 		os.Exit(1)
 	}
 }
+
+func buildHelp() string {
+	if len(commit) > 7 {
+		commit = commit[:7]
+	}
+	var tags string
+	if len(build.Default.BuildTags) > 0 {
+		tags = ", with tags " + strings.Join(build.Default.BuildTags, ", ")
+	}
+	return fmt.Sprintf(`
+Try 'ntfy COMMAND --help' or https://ntfy.sh/docs/ for more information.
+
+To report a bug, open an issue on GitHub: https://github.com/binwiederhier/ntfy/issues.
+If you want to chat, simply join the Discord server (https://discord.gg/cT7ECsZj9w), or
+the Matrix room (https://matrix.to/#/#ntfy:matrix.org).
+
+ntfy %s (%s), runtime %s, built at %s%s
+Copyright (C) Philipp C. Heckel, licensed under Apache License 2.0 & GPLv2
+`, version, commit, runtime.Version(), date, tags)
+}

+ 16 - 0
payments/payments.go

@@ -0,0 +1,16 @@
+//go:build !nopayments
+
+package payments
+
+import "github.com/stripe/stripe-go/v74"
+
+const Available = true
+
+type SubscriptionStatus stripe.SubscriptionStatus
+
+type PriceRecurringInterval stripe.PriceRecurringInterval
+
+func Setup(stripeSecretKey string) {
+	stripe.EnableTelemetry = false // Whoa!
+	stripe.Key = stripeSecretKey
+}

+ 13 - 0
payments/payments_dummy.go

@@ -0,0 +1,13 @@
+//go:build nopayments
+
+package payments
+
+const Available = false
+
+type SubscriptionStatus string
+
+type PriceRecurringInterval string
+
+func Setup(stripeSecretKey string) {
+	// Nothing to see here
+}

+ 2 - 1
server/server.go

@@ -10,6 +10,7 @@ import (
 	"errors"
 	"fmt"
 	"gopkg.in/yaml.v2"
+	"heckel.io/ntfy/v2/payments"
 	"io"
 	"net"
 	"net/http"
@@ -165,7 +166,7 @@ func New(conf *Config) (*Server, error) {
 		mailer = &smtpSender{config: conf}
 	}
 	var stripe stripeAPI
-	if hasStripe && conf.StripeSecretKey != "" {
+	if payments.Available && conf.StripeSecretKey != "" {
 		stripe = newStripeAPI()
 	}
 	messageCache, err := createMessageCache(conf)

+ 3 - 4
server/server_payments.go

@@ -14,6 +14,7 @@ import (
 	"github.com/stripe/stripe-go/v74/subscription"
 	"github.com/stripe/stripe-go/v74/webhook"
 	"heckel.io/ntfy/v2/log"
+	"heckel.io/ntfy/v2/payments"
 	"heckel.io/ntfy/v2/user"
 	"heckel.io/ntfy/v2/util"
 	"io"
@@ -44,8 +45,6 @@ import (
 //      This is used to keep the local user database fields up to date. Stripe is the source of truth.
 //      What Stripe says is mirrored and not questioned.
 
-const hasStripe = true
-
 var (
 	errNotAPaidTier                 = errors.New("tier does not have billing price identifier")
 	errMultipleBillingSubscriptions = errors.New("cannot have multiple billing subscriptions")
@@ -468,8 +467,8 @@ func (s *Server) updateSubscriptionAndTier(r *http.Request, v *visitor, u *user.
 	billing := &user.Billing{
 		StripeCustomerID:            customerID,
 		StripeSubscriptionID:        subscriptionID,
-		StripeSubscriptionStatus:    stripe.SubscriptionStatus(status),
-		StripeSubscriptionInterval:  stripe.PriceRecurringInterval(interval),
+		StripeSubscriptionStatus:    payments.SubscriptionStatus(status),
+		StripeSubscriptionInterval:  payments.PriceRecurringInterval(interval),
 		StripeSubscriptionPaidUntil: time.Unix(paidUntil, 0),
 		StripeSubscriptionCancelAt:  time.Unix(cancelAt, 0),
 	}

+ 15 - 9
server/server_payments_dummy.go

@@ -2,7 +2,21 @@
 
 package server
 
-const hasStripe = false
+import (
+	"net/http"
+)
+
+type stripeAPI interface {
+	CancelSubscription(id string) (string, error)
+}
+
+func newStripeAPI() stripeAPI {
+	return nil
+}
+
+func (s *Server) fetchStripePrices() (map[string]int64, error) {
+	return nil, errHTTPNotFound
+}
 
 func (s *Server) handleBillingTiersGet(w http.ResponseWriter, _ *http.Request, _ *visitor) error {
 	return errHTTPNotFound
@@ -31,11 +45,3 @@ func (s *Server) handleAccountBillingPortalSessionCreate(w http.ResponseWriter,
 func (s *Server) handleAccountBillingWebhook(_ http.ResponseWriter, r *http.Request, v *visitor) error {
 	return errHTTPNotFound
 }
-
-func (s *Server) handleAccountBillingWebhookSubscriptionUpdated(r *http.Request, v *visitor, event stripe.Event) error {
-	return errHTTPNotFound
-}
-
-func (s *Server) handleAccountBillingWebhookSubscriptionDeleted(r *http.Request, v *visitor, event stripe.Event) error {
-	return errHTTPNotFound
-}

+ 0 - 1
stripe/types.go

@@ -1 +0,0 @@
-package stripe

+ 7 - 7
user/manager.go

@@ -7,9 +7,9 @@ import (
 	"errors"
 	"fmt"
 	"github.com/mattn/go-sqlite3"
-	"github.com/stripe/stripe-go/v74"
 	"golang.org/x/crypto/bcrypt"
 	"heckel.io/ntfy/v2/log"
+	"heckel.io/ntfy/v2/payments"
 	"heckel.io/ntfy/v2/util"
 	"net/netip"
 	"path/filepath"
@@ -1242,12 +1242,12 @@ func (a *Manager) readUser(rows *sql.Rows) (*User, error) {
 			Calls:    calls,
 		},
 		Billing: &Billing{
-			StripeCustomerID:            stripeCustomerID.String,                                          // May be empty
-			StripeSubscriptionID:        stripeSubscriptionID.String,                                      // May be empty
-			StripeSubscriptionStatus:    stripe.SubscriptionStatus(stripeSubscriptionStatus.String),       // May be empty
-			StripeSubscriptionInterval:  stripe.PriceRecurringInterval(stripeSubscriptionInterval.String), // May be empty
-			StripeSubscriptionPaidUntil: time.Unix(stripeSubscriptionPaidUntil.Int64, 0),                  // May be zero
-			StripeSubscriptionCancelAt:  time.Unix(stripeSubscriptionCancelAt.Int64, 0),                   // May be zero
+			StripeCustomerID:            stripeCustomerID.String,                                            // May be empty
+			StripeSubscriptionID:        stripeSubscriptionID.String,                                        // May be empty
+			StripeSubscriptionStatus:    payments.SubscriptionStatus(stripeSubscriptionStatus.String),       // May be empty
+			StripeSubscriptionInterval:  payments.PriceRecurringInterval(stripeSubscriptionInterval.String), // May be empty
+			StripeSubscriptionPaidUntil: time.Unix(stripeSubscriptionPaidUntil.Int64, 0),                    // May be zero
+			StripeSubscriptionCancelAt:  time.Unix(stripeSubscriptionCancelAt.Int64, 0),                     // May be zero
 		},
 		Deleted: deleted.Valid,
 	}

+ 3 - 3
user/manager_test.go

@@ -4,8 +4,8 @@ import (
 	"database/sql"
 	"fmt"
 	"github.com/stretchr/testify/require"
-	"github.com/stripe/stripe-go/v74"
 	"golang.org/x/crypto/bcrypt"
+	"heckel.io/ntfy/v2/payments"
 	"heckel.io/ntfy/v2/util"
 	"net/netip"
 	"path/filepath"
@@ -164,8 +164,8 @@ func TestManager_AddUser_And_Query(t *testing.T) {
 	require.Nil(t, a.ChangeBilling("user", &Billing{
 		StripeCustomerID:            "acct_123",
 		StripeSubscriptionID:        "sub_123",
-		StripeSubscriptionStatus:    stripe.SubscriptionStatusActive,
-		StripeSubscriptionInterval:  stripe.PriceRecurringIntervalMonth,
+		StripeSubscriptionStatus:    payments.SubscriptionStatusActive,
+		StripeSubscriptionInterval:  payments.PriceRecurringIntervalMonth,
 		StripeSubscriptionPaidUntil: time.Now().Add(time.Hour),
 		StripeSubscriptionCancelAt:  time.Unix(0, 0),
 	}))

+ 3 - 3
user/types.go

@@ -2,8 +2,8 @@ package user
 
 import (
 	"errors"
-	"github.com/stripe/stripe-go/v74"
 	"heckel.io/ntfy/v2/log"
+	"heckel.io/ntfy/v2/payments"
 	"net/netip"
 	"strings"
 	"time"
@@ -140,8 +140,8 @@ type Stats struct {
 type Billing struct {
 	StripeCustomerID            string
 	StripeSubscriptionID        string
-	StripeSubscriptionStatus    stripe.SubscriptionStatus
-	StripeSubscriptionInterval  stripe.PriceRecurringInterval
+	StripeSubscriptionStatus    payments.SubscriptionStatus
+	StripeSubscriptionInterval  payments.PriceRecurringInterval
 	StripeSubscriptionPaidUntil time.Time
 	StripeSubscriptionCancelAt  time.Time
 }