fix: Fixed paddle subs
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.hostxtra.co.uk/mrhid6/vantage/admin/internal/db"
|
||||
@@ -210,6 +211,54 @@ func Backfill(ctx context.Context) error {
|
||||
if err := backfillEntitlements(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Pass 6: instances claimed before linked_from_placeholder_id existed have no
|
||||
// alias, and Paddle's custom_data still names the placeholder they were
|
||||
// claimed from — so their next webhook resolves to nothing. The claim wrote an
|
||||
// audit entry naming both ids, which is the only surviving record of the
|
||||
// placeholder, so reconstruct the alias from it.
|
||||
if err := backfillPlaceholderAliases(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// backfillPlaceholderAliases rebuilds linked_from_placeholder_id from the
|
||||
// instance.placeholder_linked audit entries. Idempotent by filtering on the
|
||||
// absence of the field.
|
||||
func backfillPlaceholderAliases(ctx context.Context) error {
|
||||
cur, err := db.Admin("admin_audit").Find(ctx,
|
||||
bson.M{"action": "instance.placeholder_linked"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var entries []AuditEntry
|
||||
if err := cur.All(ctx, &entries); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const prefix = "from placeholder "
|
||||
linked := 0
|
||||
for _, e := range entries {
|
||||
if e.Target == "" || !strings.HasPrefix(e.Detail, prefix) {
|
||||
continue
|
||||
}
|
||||
placeholderID := strings.TrimSpace(strings.TrimPrefix(e.Detail, prefix))
|
||||
if placeholderID == "" || placeholderID == e.Target {
|
||||
continue
|
||||
}
|
||||
res, err := db.Admin("admin_instances").UpdateOne(ctx,
|
||||
bson.M{"instance_id": e.Target,
|
||||
"linked_from_placeholder_id": bson.M{"$exists": false}},
|
||||
bson.M{"$set": bson.M{"linked_from_placeholder_id": placeholderID}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
linked += int(res.ModifiedCount)
|
||||
}
|
||||
if linked > 0 {
|
||||
log.Printf("backfill: recovered %d placeholder aliases from the audit log", linked)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -147,6 +147,13 @@ type Instance struct {
|
||||
// checkout has something to attach custom_data to, before the customer has
|
||||
// pasted their install's real UUID. Cleared when the instance is linked.
|
||||
Placeholder bool `bson:"placeholder,omitempty" json:"placeholder,omitempty"`
|
||||
// LinkedFromPlaceholderID is the id this row carried while it was a
|
||||
// self-hosted placeholder, kept forever after the claim rewrote InstanceID to
|
||||
// the install's real UUID. Paddle's copy of custom_data still names the
|
||||
// placeholder on any subscription created before the claim (and on any webhook
|
||||
// delivered while the outbound patch was failing), so this is what lets a
|
||||
// later webhook resolve to the right instance instead of erroring as unknown.
|
||||
LinkedFromPlaceholderID string `bson:"linked_from_placeholder_id,omitempty" json:"-"`
|
||||
// PendingOwnerUserID is the customer_user who bought a paid-cloud placeholder,
|
||||
// remembered so the confirmed-payment webhook can provision the instance with
|
||||
// them as owner. Cleared once provisioned. Only ever set on a cloud placeholder.
|
||||
|
||||
Reference in New Issue
Block a user