forked from tangled.org/core
this repo has no description

appview: settings: add email preference setting

Signed-off-by: Seongmin Lee <boltlessengineer@proton.me>

boltless.me 4a8e0e3c cad6e912

verified
Changed files
+144 -17
appview
db
email
pages
templates
user
settings
settings
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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) {