Go · 2518 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package web
4
5 import (
6 "errors"
7 "io/fs"
8 "log/slog"
9 "net/http"
10 "os"
11 "time"
12
13 "github.com/jackc/pgx/v5/pgxpool"
14
15 "github.com/tenseleyFlow/shithub/internal/auth/audit"
16 "github.com/tenseleyFlow/shithub/internal/auth/email"
17 "github.com/tenseleyFlow/shithub/internal/auth/secretbox"
18 "github.com/tenseleyFlow/shithub/internal/infra/config"
19 "github.com/tenseleyFlow/shithub/internal/infra/storage"
20 orgshandlers "github.com/tenseleyFlow/shithub/internal/web/handlers/orgs"
21 "github.com/tenseleyFlow/shithub/internal/web/render"
22 )
23
24 // buildOrgHandlers wires the S30 organization handler set. Owns its
25 // own renderer (same pattern as the search/notif builders).
26 func buildOrgHandlers(
27 cfg config.Config,
28 pool *pgxpool.Pool,
29 objectStore storage.ObjectStore,
30 tmplFS fs.FS,
31 logger *slog.Logger,
32 ) (*orgshandlers.Handlers, error) {
33 rr, err := render.New(tmplFS, render.Options{Octicons: render.BuiltinOcticons()})
34 if err != nil {
35 return nil, err
36 }
37 sender, _ := pickOrgsEmailSender(cfg)
38 var box *secretbox.Box
39 if cfg.Auth.TOTPKeyB64 != "" {
40 if b, err := secretbox.FromBase64(cfg.Auth.TOTPKeyB64); err == nil {
41 box = b
42 } else if logger != nil {
43 logger.Warn("orgs: actions secretbox unavailable",
44 "hint", "set Auth.TOTPKeyB64 to a base64 32-byte key",
45 "error", err)
46 }
47 }
48 return orgshandlers.New(orgshandlers.Deps{
49 Logger: logger,
50 Render: rr,
51 Pool: pool,
52 EmailSender: sender,
53 EmailFrom: cfg.Auth.EmailFrom,
54 SiteName: cfg.Auth.SiteName,
55 BaseURL: cfg.Auth.BaseURL,
56 ObjectStore: objectStore,
57 SecretBox: box,
58 Audit: audit.NewRecorder(),
59 })
60 }
61
62 // pickOrgsEmailSender mirrors pickEmailSender in auth_wiring.go.
63 // Kept local so a missing/misconfigured email backend doesn't crash
64 // the org surface — invitations still land in the DB; the email side
65 // is best-effort.
66 func pickOrgsEmailSender(cfg config.Config) (email.Sender, error) {
67 switch cfg.Auth.EmailBackend {
68 case "stdout":
69 return email.NewStdoutSender(os.Stdout), nil
70 case "smtp":
71 return &email.SMTPSender{
72 Addr: cfg.Auth.SMTP.Addr,
73 From: cfg.Auth.EmailFrom,
74 Username: cfg.Auth.SMTP.Username,
75 Password: cfg.Auth.SMTP.Password,
76 }, nil
77 case "postmark":
78 return &email.PostmarkSender{
79 ServerToken: cfg.Auth.Postmark.ServerToken,
80 From: cfg.Auth.EmailFrom,
81 HTTP: &http.Client{Timeout: 10 * time.Second},
82 }, nil
83 default:
84 return nil, errors.New("orgs: unknown email_backend")
85 }
86 }
87