Skip to content

Commit

Permalink
Remove billing code
Browse files Browse the repository at this point in the history
  • Loading branch information
arp242 committed Jun 24, 2022
1 parent 97f56b2 commit fba6e82
Show file tree
Hide file tree
Showing 53 changed files with 129 additions and 1,817 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@ the *"why?"* of this project.

There's a live demo at [https://stats.arp242.net](https://stats.arp242.net).

Please consider [contributing financially][sponsor] if you're self-hosting
GoatCounter so I can pay my rent :-) GoatCounter is sponsored by a grant from
[NLnet's NGI Zero PET fund][nlnet].
Please consider [contributing financially][sponsor] if you're using
goatcounter.com to pay for the server costs.

[nlnet]: https://nlnet.nl/project/GoatCounter/
[sponsor]: http://www.goatcounter.com/contribute
[www]: https://www.goatcounter.com

Expand Down
28 changes: 7 additions & 21 deletions bosmang.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,16 @@ import (
"zgo.at/zdb"
"zgo.at/zstd/zjson"
"zgo.at/zstd/zruntime"
"zgo.at/zstd/ztype"
)

type BosmangStat struct {
ID int64 `db:"site_id"`
Codes string `db:"codes"`
Stripe *string `db:"stripe"`
BillingAmount *string `db:"billing_amount"`
Email string `db:"email"`
CreatedAt time.Time `db:"created_at"`
Plan string `db:"plan"`
LastMonth int `db:"last_month"`
Total int `db:"total"`
Avg int `db:"avg"`
ID int64 `db:"site_id"`
Codes string `db:"codes"`
Email string `db:"email"`
CreatedAt time.Time `db:"created_at"`
LastMonth int `db:"last_month"`
Total int `db:"total"`
Avg int `db:"avg"`
}

type BosmangStats []BosmangStat
Expand All @@ -40,22 +36,13 @@ func (a *BosmangStats) List(ctx context.Context) error {
if err != nil {
return errors.Wrap(err, "BosmangStats.List")
}

curr := strings.NewReplacer("EUR ", "€", "USD ", "$")
aa := *a
for i := range aa {
if aa[i].BillingAmount != nil {
aa[i].BillingAmount = ztype.Ptr[string](curr.Replace(*aa[i].BillingAmount))
}
}
return nil
}

type BosmangSiteStat struct {
Account Site
Sites Sites
Users Users
Usage AccountUsage
}

// ByID gets stats for a single site.
Expand All @@ -80,7 +67,6 @@ func (a *BosmangSiteStat) ByID(ctx context.Context, id int64) error {
return errors.Wrap(err, "BosmangSiteStats.ByID")
}

err = a.Usage.Get(WithSite(ctx, &a.Account))
return errors.Wrap(err, "BosmangSiteStats.ByID")
}

Expand Down
8 changes: 3 additions & 5 deletions cmd/goatcounter/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ create and update commands:
-access* Access to give this user:
readonly Can't change any settings.
settings Can change settings, except billing and
site/user management.
settings Can change settings, except site/user
management.
admin Full access.
superuser Full access, including the "server
management" page.
Expand Down Expand Up @@ -701,11 +701,9 @@ func cmdDBSiteCreate(ctx context.Context, vhost, email, link, pwd string) error
s := goatcounter.Site{
Code: "serve-" + zcrypto.Secret64(),
Cname: &vhost,
Plan: goatcounter.PlanBusinessPlus,
}
if account.ID > 0 {
s.Parent, s.Settings, s.UserDefaults, s.Plan =
&account.ID, account.Settings, account.UserDefaults, goatcounter.PlanChild
s.Parent, s.Settings, s.UserDefaults = &account.ID, account.Settings, account.UserDefaults
}
err := s.Insert(ctx)
if err != nil {
Expand Down
42 changes: 2 additions & 40 deletions cmd/goatcounter/saas.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (
"zgo.at/zli"
"zgo.at/zlog"
"zgo.at/zstd/znet"
"zgo.at/zstd/zstring"
"zgo.at/zstripe"
"zgo.at/zvalidate"
)

Expand All @@ -41,19 +39,17 @@ func cmdSaas(f zli.Flags, ready chan<- struct{}, stop chan struct{}) error {

var (
domain = f.String("goatcounter.localhost:8081,static.goatcounter.localhost:8081", "domain").Pointer()
stripe = f.String("", "stripe").Pointer()
)
dbConnect, dbConn, dev, automigrate, listen, flagTLS, from, websocket, err := flagsServe(f, &v)
if err != nil {
return err
}

return func(domain, stripe string) error {
return func(domain string) error {
if flagTLS == "" {
flagTLS = map[bool]string{true: "http", false: "acme"}[dev]
}

flagStripe(stripe, &v)
domain, domainStatic, domainCount, urlStatic := flagDomain(domain, &v)
from = flagFrom(from, domain, &v)
if !dev && domain != "goatcounter.com" {
Expand Down Expand Up @@ -94,41 +90,7 @@ func cmdSaas(f zli.Flags, ready chan<- struct{}, stop chan struct{}) error {
zlog.Printf("serving %q on %q; dev=%t", domain, listen, dev)
ready <- struct{}{}
})
}(*domain, *stripe)
}

func flagStripe(stripe string, v *zvalidate.Validator) {
if stripe == "" {
v.Required("-stripe", stripe)
return
}

if zstring.ContainsAny(zlog.Config.Debug, "stripe", "all") {
zstripe.DebugURL = true
zstripe.DebugRespBody = true
zstripe.DebugReqBody = true
}

zstripe.StripeVersion = "2020-08-27"
for _, k := range zstring.Fields(stripe, ":") {
switch {
case strings.HasPrefix(k, "sk_"):
zstripe.SecretKey = k
case strings.HasPrefix(k, "pk_"):
zstripe.PublicKey = k
case strings.HasPrefix(k, "whsec_"):
zstripe.SignSecret = k
}
}
if zstripe.SecretKey == "" {
v.Append("-stripe", "missing secret key (sk_)")
}
if zstripe.PublicKey == "" {
v.Append("-stripe", "missing public key (pk_)")
}
if zstripe.SignSecret == "" {
v.Append("-stripe", "missing signing secret (whsec_)")
}
}(*domain)
}

func flagDomain(domain string, v *zvalidate.Validator) (string, string, string, string) {
Expand Down
1 change: 0 additions & 1 deletion cmd/goatcounter/saas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ func TestSaas(t *testing.T) {
"-debug=all",
"-domain=goatcounter.com,a.a",
"-listen=localhost:31874",
"-stripe=sk_test_x:pk_test_x:whsec_x",
"-tls=http")
}()
<-ready
Expand Down
15 changes: 0 additions & 15 deletions cmd/goatcounter/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ func cmdServe(f zli.Flags, ready chan<- struct{}, stop chan struct{}) error {
}

return doServe(ctx, db, listen, listenTLS, tlsc, hosts, stop, func() {
banner()
startupMsg(db)
zlog.Printf("ready; serving %d sites on %q; dev=%t; sites: %s",
len(cnames), listen, dev, strings.Join(cnames, ", "))
Expand Down Expand Up @@ -465,20 +464,6 @@ func lsSites(ctx context.Context) ([]string, error) {
return cnames, nil
}

func banner() {
fmt.Fprint(zli.Stdout, `
┏━━━━━━━━━━━━━━━━━━━━━ Thank you for using GoatCounter! ━━━━━━━━━━━━━━━━━━━━━━┓
┃ ┃
┃ Great you're choosing to self-host GoatCounter! Please consider making a ┃
┃ financial contribution according to your means if this is useful for you to ┃
┃ ensure the long-term viability. Thank you :-) ┃
┃ ┃
┃ https://www.goatcounter.com/contribute ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
`)
}

func startupMsg(db zdb.DB) {
var msg string
err := db.Get(context.Background(), &msg, `select value from store where key='display-once'`)
Expand Down
4 changes: 2 additions & 2 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ func MustGetSite(ctx context.Context) *Site {
return s
}

// GetAccount gets this site's "account site" on which the users, billing, etc.
// are stored.
// GetAccount gets this site's "account site" on which the users, etc. are
// stored.
func GetAccount(ctx context.Context) (*Site, error) {
s := MustGetSite(ctx)
if s.Parent == nil {
Expand Down
2 changes: 0 additions & 2 deletions cron/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@ var Tasks = []Task{
{"vacuum pageviews (data retention)", DataRetention, 1 * time.Hour},
{"renew ACME certs", renewACME, 2 * time.Hour},
{"vacuum soft-deleted sites", vacuumDeleted, 12 * time.Hour},
{"process scheduled plan changes", cancelPlan, 12 * time.Hour},
{"rm old exports", oldExports, 1 * time.Hour},
{"cycle sessions", sessions, 1 * time.Minute},
{"report usage", reportUsage, 12 * time.Hour},
{"send email reports", EmailReports, 1 * time.Hour},
}

Expand Down
4 changes: 3 additions & 1 deletion cron/email_reports.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ func reportText(ctx context.Context, site goatcounter.Site, user goatcounter.Use
return nil, nil, "", err
}

diffs, err := args.Pages.DiffTotal(ctx, rng)
d := -rng.End.Sub(rng.Start)
prev := ztime.NewRange(rng.Start.Add(d)).To(rng.End.Add(d))
diffs, err := args.Pages.Diff(ctx, rng, prev)
if err != nil {
return nil, nil, "", err
}
Expand Down
73 changes: 0 additions & 73 deletions cron/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"context"
"fmt"
"os"
"strconv"
"strings"
"sync"
"time"
Expand All @@ -20,7 +19,6 @@ import (
"zgo.at/zdb"
"zgo.at/zlog"
"zgo.at/zstd/ztime"
"zgo.at/zstripe"
)

func oldExports(ctx context.Context) error {
Expand Down Expand Up @@ -243,79 +241,8 @@ func vacuumDeleted(ctx context.Context) error {
return nil
}

// Unset plans after cancellation
func cancelPlan(ctx context.Context) error {
var sites goatcounter.Sites
err := sites.ExpiredPlans(ctx)
if err != nil {
return errors.Errorf("cancelPlans: %w", err)
}

for _, s := range sites {
s.BillingAmount = nil
s.Plan = goatcounter.PlanFree
s.PlanPending = nil
s.PlanCancelAt = nil
err := s.UpdateStripe(ctx)
if err != nil {
return err
}
}
return nil
}

func sessions(ctx context.Context) error {
goatcounter.Memstore.EvictSessions()
goatcounter.Memstore.RefreshSalt()
return nil
}

// Report usage to Strip; the pricing plan is set up to use the highest value,
// so just report the current value.
func reportUsage(ctx context.Context) error {
var sites goatcounter.Sites
err := sites.UnscopedList(ctx)
if err != nil {
return err
}

for _, s := range sites {
if s.ExtraPageviews == nil {
continue
}
if s.ExtraPageviewsSub == nil {
zlog.Errorf("ExtraPageviewsSub == nil for site %d", s.ID)
continue
}

var usage goatcounter.AccountUsage
err := usage.Get(goatcounter.WithSite(ctx, &s))
if err != nil {
zlog.Error(err)
continue
}

if usage.Plan.MonthlyHits > usage.Total.ThisPeriod {
continue
}

charge := (usage.Total.ThisPeriod - usage.Plan.MonthlyHits) / 10_000
if *s.ExtraPageviews > 0 && float64(charge)*0.20 > float64(*s.ExtraPageviews) {
charge = int(float64(*s.ExtraPageviews) / 0.20)
fmt.Println("XX MAX", charge)
}

zlog.Printf("reporting usage for %d: %d (€%.2f)", s.ID, charge, float64(charge)*0.20)

_, err = zstripe.Request(nil, "POST", "/v1/subscription_items/"+*s.ExtraPageviewsSub+"/usage_records", zstripe.Body{
"quantity": strconv.Itoa(charge),
"timestamp": strconv.FormatInt(ztime.Now().UTC().Unix(), 10),
"action": "set",
}.Encode())
if err != nil {
zlog.Error(err)
}
}

return nil
}
3 changes: 1 addition & 2 deletions cron/tasks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ import (
func TestDataRetention(t *testing.T) {
ctx := gctest.DB(t)

site := goatcounter.Site{Code: "bbbb", Plan: goatcounter.PlanPersonal,
Settings: goatcounter.SiteSettings{DataRetention: 31}}
site := goatcounter.Site{Code: "bbbb", Settings: goatcounter.SiteSettings{DataRetention: 31}}
err := site.Insert(ctx)
if err != nil {
t.Fatal(err)
Expand Down
9 changes: 9 additions & 0 deletions db/migrate/2022-02-16-1-rm-billing.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
alter table sites drop column if exists plan;
alter table sites drop column if exists plan_pending;
alter table sites drop column if exists plan_cancel_at;
alter table sites drop column if exists stripe;
alter table sites drop column if exists billing_amount;
alter table sites drop column if exists billing_anchor;
alter table sites drop column if exists extra_pageviews;
alter table sites drop column if exists extra_pageviews_sub;
alter table sites drop column if exists notes;
3 changes: 0 additions & 3 deletions db/query/bosmang.List.sql
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ select
grouped.total,
grouped.codes,
created_at,
billing_amount,
plan,
stripe,
grouped.last_month,
(coalesce(total, 0) / greatest(extract('days' from now() - created_at), 1) * 30.5)::int as avg
from grouped
Expand Down
12 changes: 0 additions & 12 deletions db/schema.gotxt
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,6 @@ create table sites (
settings {{jsonb}} not null,
user_defaults {{jsonb}} not null default '{}',
received_data integer not null default 0,

-- Billing related stuff.
plan varchar not null,
plan_pending varchar null,
plan_cancel_at timestamp,
stripe varchar null,
billing_amount varchar,
billing_anchor timestamp,
notes text not null default '',
extra_pageviews int,
extra_pageviews_sub varchar,

state varchar not null default 'a' check(state in ('a', 'd')),
created_at timestamp not null {{check_timestamp "created_at"}},
updated_at timestamp {{check_timestamp "updated_at"}},
Expand Down
1 change: 0 additions & 1 deletion docs/sbom.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ Direct dependencies:
| zgo.at/zli | MIT | CLI conveniences |
| zgo.at/zlog | MIT | Logging library. |
| zgo.at/zstd | MIT | Extensions to stdlib. |
| zgo.at/zstripe | MIT | Stripe integration |
| zgo.at/zvalidate | MIT | Validate values |

Testing dependencies:
Expand Down
Loading

0 comments on commit fba6e82

Please sign in to comment.