+7
appview/db/db.go
+7
appview/db/db.go
···
703
703
return err
704
704
})
705
705
706
+
runMigration(conn, "add-email-notif-preference-to-profile", func(tx *sql.Tx) error {
707
+
_, err := tx.Exec(`
708
+
alter table profile add column email_notif_preference integer not null default 0 check (email_notif_preference in (0, 1, 2)); -- disable, metion, enable
709
+
`)
710
+
return err
711
+
})
712
+
706
713
return &DB{db}, nil
707
714
}
708
715
+22
appview/db/email.go
+22
appview/db/email.go
···
299
299
_, err := e.Exec(query, code, did, email)
300
300
return err
301
301
}
302
+
303
+
func GetUserEmailPreference(e Execer, did string) (EmailPreference, error) {
304
+
var preference EmailPreference
305
+
err := e.QueryRow(`
306
+
select email_notif_preference
307
+
from profile
308
+
where did = ?
309
+
`, did).Scan(&preference)
310
+
if err != nil {
311
+
return preference, err
312
+
}
313
+
return preference, nil
314
+
}
315
+
316
+
func UpdateSettingsEmailPreference(e Execer, did string, preference EmailPreference) error {
317
+
_, err := e.Exec(`
318
+
update profile
319
+
set email_notif_preference = ?
320
+
where did = ?
321
+
`, preference, did)
322
+
return err
323
+
}
+32
-6
appview/db/profile.go
+32
-6
appview/db/profile.go
···
183
183
Links [5]string
184
184
Stats [2]VanityStat
185
185
PinnedRepos [6]syntax.ATURI
186
+
187
+
// settings
188
+
EmailNotifPreference EmailPreference
189
+
}
190
+
191
+
type EmailPreference int
192
+
193
+
const (
194
+
EmailNotifDisabled EmailPreference = iota
195
+
EmailNotifMention
196
+
EmailNotifEnabled
197
+
)
198
+
199
+
func (p EmailPreference) IsDisabled() bool {
200
+
return p == EmailNotifDisabled
201
+
}
202
+
203
+
func (p EmailPreference) IsMention() bool {
204
+
return p == EmailNotifMention
205
+
}
206
+
207
+
func (p EmailPreference) IsEnabled() bool {
208
+
return p == EmailNotifEnabled
186
209
}
187
210
188
211
func (p Profile) IsLinksEmpty() bool {
···
280
303
did,
281
304
description,
282
305
include_bluesky,
283
-
location
306
+
location,
307
+
email_notif_preference
284
308
)
285
-
values (?, ?, ?, ?)`,
309
+
values (?, ?, ?, ?, ?)`,
286
310
profile.Did,
287
311
profile.Description,
288
312
includeBskyValue,
289
313
profile.Location,
314
+
profile.EmailNotifPreference,
290
315
)
291
316
292
317
if err != nil {
···
367
392
did,
368
393
description,
369
394
include_bluesky,
370
-
location
395
+
location,
396
+
email_notif_preference
371
397
from
372
398
profile
373
399
%s`,
···
383
409
var profile Profile
384
410
var includeBluesky int
385
411
386
-
err = rows.Scan(&profile.ID, &profile.Did, &profile.Description, &includeBluesky, &profile.Location)
412
+
err = rows.Scan(&profile.ID, &profile.Did, &profile.Description, &includeBluesky, &profile.Location, &profile.EmailNotifPreference)
387
413
if err != nil {
388
414
return nil, err
389
415
}
···
457
483
458
484
includeBluesky := 0
459
485
err := e.QueryRow(
460
-
`select description, include_bluesky, location from profile where did = ?`,
486
+
`select description, include_bluesky, location, email_notif_preference from profile where did = ?`,
461
487
did,
462
-
).Scan(&profile.Description, &includeBluesky, &profile.Location)
488
+
).Scan(&profile.Description, &includeBluesky, &profile.Location, &profile.EmailNotifPreference)
463
489
if err == sql.ErrNoRows {
464
490
profile := Profile{}
465
491
profile.Did = did
+14
-2
appview/email/notifier.go
+14
-2
appview/email/notifier.go
···
71
71
72
72
func (n *EmailNotifier) gatherRecipientEmails(ctx context.Context, handles []string) []string {
73
73
recipients := []string{}
74
-
resolvedIdents := n.idResolver.ResolveIdents(ctx, handles)
75
-
for _, id := range resolvedIdents {
74
+
for _, handle := range handles {
75
+
id, err := n.idResolver.ResolveIdent(ctx, handle)
76
+
if err != nil {
77
+
log.Println("failed to resolve handle:", err)
78
+
continue
79
+
}
80
+
emailPreference, err := db.GetUserEmailPreference(n.db, id.DID.String())
81
+
if err != nil {
82
+
log.Println("failed to get user email preference:", err)
83
+
continue
84
+
}
85
+
if emailPreference == db.EmailNotifDisabled {
86
+
continue
87
+
}
76
88
email, err := db.GetPrimaryEmail(n.db, id.DID.String())
77
89
if err != nil {
78
90
log.Println("failed to get primary email:", err)
+5
-4
appview/pages/pages.go
+5
-4
appview/pages/pages.go
···
328
328
}
329
329
330
330
type UserEmailsSettingsParams struct {
331
-
LoggedInUser *oauth.User
332
-
Emails []db.Email
333
-
Tabs []map[string]any
334
-
Tab string
331
+
LoggedInUser *oauth.User
332
+
Emails []db.Email
333
+
NotifPreference db.EmailPreference
334
+
Tabs []map[string]any
335
+
Tab string
335
336
}
336
337
337
338
func (p *Pages) UserEmailsSettings(w io.Writer, params UserEmailsSettingsParams) error {
+31
-1
appview/pages/templates/user/settings/emails.html
+31
-1
appview/pages/templates/user/settings/emails.html
···
11
11
</div>
12
12
<div class="col-span-1 md:col-span-3 flex flex-col gap-6">
13
13
{{ template "emailSettings" . }}
14
+
{{ template "emailList" . }}
14
15
</div>
15
16
</section>
16
17
</div>
17
18
{{ end }}
18
19
19
20
{{ define "emailSettings" }}
21
+
<form
22
+
hx-post="/settings/email/preference"
23
+
hx-swap="none"
24
+
hx-indicator="#email-preference-spinner"
25
+
class="grid grid-cols-1 md:grid-cols-3 gap-4"
26
+
>
27
+
<div class="col-span-1 md:col-span-2">
28
+
<h2 class="text-sm pb-2 uppercase font-bold">Email Notifications</h2>
29
+
</div>
30
+
<select
31
+
name="preference"
32
+
class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600"
33
+
>
34
+
<option value="enable" {{ if .NotifPreference.IsEnabled }}selected{{ end }}>Enable</option>
35
+
<option value="mention" {{ if .NotifPreference.IsMention }}selected{{ end }}>Only on Mentions</option>
36
+
<option value="disable" {{ if .NotifPreference.IsDisabled }}selected{{ end }}>Disable</option>
37
+
</select>
38
+
<div class="md:col-start-2 col-span-2 flex justify-end">
39
+
<button type="submit" class="btn text-base">
40
+
<span>Save Preference</span>
41
+
<span id="email-preference-spinner" class="group">
42
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
43
+
</span>
44
+
</button>
45
+
</div>
46
+
</form>
47
+
{{ end }}
48
+
49
+
{{ define "emailList" }}
20
50
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 items-center">
21
51
<div class="col-span-1 md:col-span-2">
22
52
<h2 class="text-sm pb-2 uppercase font-bold">Email Addresses</h2>
···
91
121
<div id="settings-emails-error" class="text-red-500 dark:text-red-400"></div>
92
122
<div id="settings-emails-success" class="text-green-500 dark:text-green-400"></div>
93
123
</form>
94
-
{{ end }}
124
+
{{ end }}
+33
-4
appview/settings/settings.go
+33
-4
appview/settings/settings.go
···
58
58
r.Delete("/", s.keys)
59
59
})
60
60
61
+
r.Post("/email/preference", s.emailPreference)
62
+
61
63
r.Route("/emails", func(r chi.Router) {
62
64
r.Get("/", s.emailsSettings)
63
65
r.Put("/", s.emails)
···
97
99
98
100
func (s *Settings) emailsSettings(w http.ResponseWriter, r *http.Request) {
99
101
user := s.OAuth.GetUser(r)
102
+
preference, err := db.GetUserEmailPreference(s.Db, user.Did)
103
+
100
104
emails, err := db.GetAllEmails(s.Db, user.Did)
101
105
if err != nil {
102
106
log.Println(err)
103
107
}
104
108
105
109
s.Pages.UserEmailsSettings(w, pages.UserEmailsSettingsParams{
106
-
LoggedInUser: user,
107
-
Emails: emails,
108
-
Tabs: settingsTabs,
109
-
Tab: "emails",
110
+
LoggedInUser: user,
111
+
Emails: emails,
112
+
NotifPreference: preference,
113
+
Tabs: settingsTabs,
114
+
Tab: "emails",
110
115
})
111
116
}
112
117
···
374
379
}
375
380
376
381
s.Pages.HxLocation(w, "/settings/emails")
382
+
}
383
+
384
+
func (s *Settings) emailPreference(w http.ResponseWriter, r *http.Request) {
385
+
did := s.OAuth.GetDid(r)
386
+
preferenceValue := r.FormValue("preference")
387
+
var preference db.EmailPreference
388
+
switch preferenceValue {
389
+
case "enable":
390
+
preference = db.EmailNotifEnabled
391
+
case "mention":
392
+
preference = db.EmailNotifMention
393
+
case "disable":
394
+
preference = db.EmailNotifDisabled
395
+
default:
396
+
log.Printf("Incorrect email preference value")
397
+
return
398
+
}
399
+
400
+
err := db.UpdateSettingsEmailPreference(s.Db, did, preference)
401
+
if err != nil {
402
+
log.Printf("failed to update email preference setting: %v", err)
403
+
s.Pages.Notice(w, "settings-keys", "Failed to update email preference. Try again later.")
404
+
return
405
+
}
377
406
}
378
407
379
408
func (s *Settings) keys(w http.ResponseWriter, r *http.Request) {