Initial commit of Descrybe v2 without local scratch artifacts.

Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
"log"
"os"
"time"
"github.com/descrybe/descrybe-v2/apps/api/internal/config"
"github.com/descrybe/descrybe-v2/apps/api/internal/mail"
"github.com/google/uuid"
)
// Hook matches migrator maps/set-password-hooks.json (invite tokens for must_set_password users).
type Hook struct {
UserID uuid.UUID `json:"user_id"`
Email string `json:"email"`
CompanyID uuid.UUID `json:"company_id"`
Role string `json:"role"`
Token string `json:"token"`
ExpiresAt time.Time `json:"expires_at"`
InviteID uuid.UUID `json:"invite_id"`
}
func main() {
hooksPath := flag.String("hooks", "", "Path to set-password-hooks.json from migrator maps-dir")
dryRun := flag.Bool("dry-run", false, "Print counts without sending")
delayMS := flag.Int("delay-ms", 100, "Pause between sends (SMTP rate limit)")
flag.Parse()
if *hooksPath == "" {
log.Fatal("-hooks is required (e.g. ../../artifacts/maps/set-password-hooks.json)")
}
cfg, err := config.Load()
if err != nil {
log.Fatalf("config: %v", err)
}
raw, err := os.ReadFile(*hooksPath)
if err != nil {
log.Fatalf("read hooks: %v", err)
}
var hooks []Hook
if err := json.Unmarshal(raw, &hooks); err != nil {
log.Fatalf("parse hooks: %v", err)
}
mailer := mail.New(mail.Config{
Enabled: cfg.SMTPEnabled,
Host: cfg.SMTPHost,
Port: cfg.SMTPPort,
User: cfg.SMTPUser,
Password: cfg.SMTPPassword,
From: cfg.SMTPFrom,
})
if err := assertMailhooksReady(*dryRun, mailer.Enabled(), cfg.EmailDryRun); err != nil {
log.Fatal(err)
}
sent, skipped, failed := 0, 0, 0
now := time.Now().UTC()
for _, h := range hooks {
if h.Token == "" || h.Email == "" {
skipped++
continue
}
if !h.ExpiresAt.IsZero() && now.After(h.ExpiresAt) {
skipped++
continue
}
msg := mail.MigratedSetPasswordMessage(cfg.WebOrigin, h.Email, h.Token)
if *dryRun {
log.Printf("mailhooks: dry-run subject=%q", msg.Subject)
sent++
continue
}
if err := mailer.Send(msg); err != nil {
log.Printf("mailhooks: send failed subject=%q", msg.Subject)
failed++
continue
}
sent++
if *delayMS > 0 {
time.Sleep(time.Duration(*delayMS) * time.Millisecond)
}
}
fmt.Printf("mailhooks: sent=%d skipped=%d failed=%d smtp_enabled=%v total=%d\n",
sent, skipped, failed, mailer.Enabled(), len(hooks))
if failed > 0 {
os.Exit(1)
}
}
// assertMailhooksReady fails closed for live sends when SMTP is a no-op or EMAIL_DRY_RUN is on.
func assertMailhooksReady(dryRun, mailerEnabled, emailDryRun bool) error {
if dryRun {
return nil
}
if emailDryRun {
return errors.New("mailhooks: email dry-run is on; pass -dry-run or disable dry-run in admin platform mail settings (or EMAIL_DRY_RUN=false)")
}
if !mailerEnabled {
return errors.New("mailhooks: SMTP not configured; pass -dry-run or set platform mail SMTP in admin (smtp.enabled + host/from)")
}
return nil
}