mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 22:37:28 +00:00
CreatePremiumCharge/VerifyPremium now POST /payments/create and GET /payments/:id against the CoinPay API (Bearer COINPAY_API_KEY, business_id = AGENTBBS_COINPAY_MERCHANT_ID), so the droplet needs no coinpay CLI installed. The created payment id is stored (store: User.PremiumPayID + premium_pay_id col + SetPremiumPayment); ensurePremium verifies that id on a later connect and grants premium on confirmed/forwarded status. Removed the CLI command-template env knobs; added AGENTBBS_COINPAY_API_URL. Tests: httptest-backed payments_test + store SetPremiumPayment test. Build/vet/gofmt/test green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
89 lines
2.5 KiB
Go
89 lines
2.5 KiB
Go
package store
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestConfirmEmailCode(t *testing.T) {
|
|
st, err := Open(filepath.Join(t.TempDir(), "t.db"))
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
defer st.Close()
|
|
|
|
u, err := st.EnsureUser("bob", "member", "SHA256:bbb")
|
|
if err != nil {
|
|
t.Fatalf("ensure: %v", err)
|
|
}
|
|
if err := st.SetEmailVerification(u.ID, "bob@example.com", "123456"); err != nil {
|
|
t.Fatalf("set: %v", err)
|
|
}
|
|
|
|
// Empty and wrong codes are clean misses.
|
|
if _, ok, err := st.ConfirmEmailCode(u.ID, ""); ok || err != nil {
|
|
t.Fatalf("empty code: ok=%v err=%v", ok, err)
|
|
}
|
|
if _, ok, _ := st.ConfirmEmailCode(u.ID, "000000"); ok {
|
|
t.Fatal("wrong code should not confirm")
|
|
}
|
|
// The right code belonging to another user must not confirm (codes are
|
|
// scoped per-user since they are short and collide).
|
|
other, _ := st.EnsureUser("carol", "member", "SHA256:ccc")
|
|
if _, ok, _ := st.ConfirmEmailCode(other.ID, "123456"); ok {
|
|
t.Fatal("code must be scoped to its own user")
|
|
}
|
|
|
|
// Correct code for the right user verifies, and is single-use.
|
|
vu, ok, err := st.ConfirmEmailCode(u.ID, "123456")
|
|
if err != nil || !ok || !vu.EmailVerified {
|
|
t.Fatalf("confirm: ok=%v err=%v verified=%v", ok, err, vu.EmailVerified)
|
|
}
|
|
if _, ok, _ := st.ConfirmEmailCode(u.ID, "123456"); ok {
|
|
t.Fatal("code should be consumed after first use")
|
|
}
|
|
}
|
|
|
|
func TestGrantPremium(t *testing.T) {
|
|
st, err := Open(filepath.Join(t.TempDir(), "t.db"))
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
defer st.Close()
|
|
|
|
u, _ := st.EnsureUser("dave", "member", "SHA256:ddd")
|
|
if u.Premium {
|
|
t.Fatal("new user must not be premium")
|
|
}
|
|
if err := st.GrantPremium(u.ID, "abbs-premium-deadbeef"); err != nil {
|
|
t.Fatalf("grant: %v", err)
|
|
}
|
|
got, _, _ := st.UserByFingerprint("SHA256:ddd")
|
|
if !got.Premium {
|
|
t.Fatalf("user should be premium after grant: %+v", got)
|
|
}
|
|
// Idempotent.
|
|
if err := st.GrantPremium(u.ID, "abbs-premium-deadbeef"); err != nil {
|
|
t.Fatalf("re-grant: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSetPremiumPayment(t *testing.T) {
|
|
st, err := Open(filepath.Join(t.TempDir(), "t.db"))
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
defer st.Close()
|
|
|
|
u, _ := st.EnsureUser("erin", "member", "SHA256:eee")
|
|
if u.PremiumPayID != "" {
|
|
t.Fatal("new user must have no premium pay id")
|
|
}
|
|
if err := st.SetPremiumPayment(u.ID, "pay_abc123"); err != nil {
|
|
t.Fatalf("set: %v", err)
|
|
}
|
|
got, _, _ := st.UserByFingerprint("SHA256:eee")
|
|
if got.PremiumPayID != "pay_abc123" {
|
|
t.Fatalf("PremiumPayID = %q", got.PremiumPayID)
|
|
}
|
|
}
|