fix(web): prefill birthday in contact form for imported contacts
Docker Image bauen und veröffentlichen / docker (push) Successful in 20m27s
Docker Image bauen und veröffentlichen / docker (push) Successful in 20m27s
This commit is contained in:
@@ -14,7 +14,9 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.arnef.de/arnef/nidus/internal/birthdays"
|
||||||
"git.arnef.de/arnef/nidus/internal/store"
|
"git.arnef.de/arnef/nidus/internal/store"
|
||||||
"git.arnef.de/arnef/nidus/internal/web/templates"
|
"git.arnef.de/arnef/nidus/internal/web/templates"
|
||||||
vcard "github.com/emersion/go-vcard"
|
vcard "github.com/emersion/go-vcard"
|
||||||
@@ -490,6 +492,27 @@ func photoDataURL(card vcard.Card) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// birthdayInputValue returns birthday in the "YYYY-MM-DD" form the contact
|
||||||
|
// form's <input type="date"> renders. vCards from other clients often store
|
||||||
|
// the date in vCard 3.0's compact "YYYYMMDD" form or year-less "--MMDD"
|
||||||
|
// form; a browser date input silently ignores values it can't parse, which
|
||||||
|
// would leave the field looking empty and drop the birthday on the next
|
||||||
|
// save. A year-less value can't be shown in a year-bearing date input as-is,
|
||||||
|
// so it's pre-filled with the current year — the field still shows the
|
||||||
|
// contact's real month/day (never the blank state the bug produced), and the
|
||||||
|
// user can correct the year if they know it. Unrecognized values pass
|
||||||
|
// through unchanged (the empty string for contacts without a birthday).
|
||||||
|
func birthdayInputValue(birthday string) string {
|
||||||
|
month, day, year, ok := birthdays.ParseBirthday(birthday)
|
||||||
|
if !ok {
|
||||||
|
return birthday
|
||||||
|
}
|
||||||
|
if year == 0 {
|
||||||
|
year = time.Now().Year()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%04d-%02d-%02d", year, int(month), day)
|
||||||
|
}
|
||||||
|
|
||||||
func labeledValues(card vcard.Card, key string) []templates.LabeledValue {
|
func labeledValues(card vcard.Card, key string) []templates.LabeledValue {
|
||||||
fields := card[key]
|
fields := card[key]
|
||||||
out := make([]templates.LabeledValue, 0, len(fields))
|
out := make([]templates.LabeledValue, 0, len(fields))
|
||||||
@@ -541,7 +564,7 @@ func contactFormFromCard(book, id string, data []byte) (templates.ContactFormDat
|
|||||||
Surname: surname,
|
Surname: surname,
|
||||||
Organization: card.PreferredValue(vcard.FieldOrganization),
|
Organization: card.PreferredValue(vcard.FieldOrganization),
|
||||||
Note: card.PreferredValue(vcard.FieldNote),
|
Note: card.PreferredValue(vcard.FieldNote),
|
||||||
Birthday: card.PreferredValue(vcard.FieldBirthday),
|
Birthday: birthdayInputValue(card.PreferredValue(vcard.FieldBirthday)),
|
||||||
PhotoDataURL: photoDataURL(card),
|
PhotoDataURL: photoDataURL(card),
|
||||||
Phones: ensureAtLeastOne(labeledValues(card, vcard.FieldTelephone)),
|
Phones: ensureAtLeastOne(labeledValues(card, vcard.FieldTelephone)),
|
||||||
Emails: ensureAtLeastOne(labeledValues(card, vcard.FieldEmail)),
|
Emails: ensureAtLeastOne(labeledValues(card, vcard.FieldEmail)),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.arnef.de/arnef/nidus/internal/config"
|
"git.arnef.de/arnef/nidus/internal/config"
|
||||||
"git.arnef.de/arnef/nidus/internal/db"
|
"git.arnef.de/arnef/nidus/internal/db"
|
||||||
@@ -316,3 +318,24 @@ func TestAccountChangePassword(t *testing.T) {
|
|||||||
t.Fatal("expected password to have changed")
|
t.Fatal("expected password to have changed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBirthdayInputValueNormalizesFormats(t *testing.T) {
|
||||||
|
year := time.Now().Year()
|
||||||
|
cases := []struct {
|
||||||
|
in string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"", ""},
|
||||||
|
{"19920217", "1992-02-17"}, // vCard 3.0 compact
|
||||||
|
{"19540805", "1954-08-05"}, // compact, no VALUE param
|
||||||
|
{"--0219", fmt.Sprintf("%04d-02-19", year)}, // year-less -> current year
|
||||||
|
{"2026-09-06", "2026-09-06"}, // already dashed (web-created)
|
||||||
|
{"1604-02-27", "1604-02-27"}, // dashed, ancient year preserved
|
||||||
|
{"garbage", "garbage"}, // unrecognized passes through
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
if got := birthdayInputValue(c.in); got != c.want {
|
||||||
|
t.Errorf("birthdayInputValue(%q) = %q, want %q", c.in, got, c.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user