feat: Changes to self hosted purchase
Chart Release / chart (push) Successful in 12s
Server Deploy / deploy (push) Successful in 9m18s

This commit is contained in:
2026-08-11 09:30:19 +01:00
parent 3acbf01d46
commit a228ab24a0
20 changed files with 150 additions and 433 deletions
-61
View File
@@ -182,67 +182,6 @@ func runOnce(ctx context.Context) {
if err := Run(runCtx); err != nil {
log.Printf("lifecycle: %v", err)
}
sweepAwaitingLink(runCtx)
}
// Awaiting-link reminder keys.
const (
noticeLink24 = "link_24"
noticeLink72 = "link_72"
)
// sweepAwaitingLink chases self-hosted instances that were paid for but never
// linked: the subscription exists, the instance is still a placeholder. It
// emails a reminder at 24h and again at 72h. The staff dashboard already flags
// 48h; this is the active chasing on top of that. It never issues or deletes.
func sweepAwaitingLink(ctx context.Context) {
cur, err := db.Admin("admin_instances").Find(ctx, bson.M{
"deployment": license.DeploymentSelfHosted,
"placeholder": true,
"status": models.StatusAwaitingLink,
})
if err != nil {
return
}
var instances []models.Instance
if err := cur.All(ctx, &instances); err != nil {
return
}
now := time.Now().UTC()
for _, inst := range instances {
// Only chase placeholders a customer has actually paid for.
n, err := db.Admin("subscriptions").CountDocuments(ctx,
bson.M{"instance_id": inst.InstanceID, "status": models.SubActive})
if err != nil || n == 0 {
continue
}
if !mail.Enabled() {
continue
}
to := accountEmail(ctx, inst.AccountID)
if to == "" {
continue
}
age := now.Sub(inst.CreatedAt)
var due string
if age > 72*time.Hour && !slices.Contains(inst.NoticesSent, noticeLink72) {
due = noticeLink72
} else if age > 24*time.Hour && !slices.Contains(inst.NoticesSent, noticeLink24) {
due = noticeLink24
}
if due == "" {
continue
}
if err := mail.Default.SendLinkReminder(to, inst.Name); err != nil {
log.Printf("lifecycle: link reminder %s for %s: %v", due, inst.InstanceID, err)
continue
}
if _, err := db.Admin("admin_instances").UpdateOne(ctx,
bson.M{"instance_id": inst.InstanceID},
bson.M{"$addToSet": bson.M{"notices_sent": due}}); err != nil {
log.Printf("lifecycle: record link notice %s for %s: %v", due, inst.InstanceID, err)
}
}
}
func accountEmail(ctx context.Context, accountID string) string {