aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Ovchinnikov <v@postbox.nz>2023-06-17 15:23:06 +0300
committerRobin Jarry <robin@jarry.cc>2023-06-29 16:25:00 +0200
commit69094e332779a71ddd47b88bced0992c290d67e7 (patch)
treeb9c2b01aa7441c6eb089015c209680f5edefdae1
parent320d961dc87084add8c0c254f77be7f4fc76732d (diff)
downloadaerc-69094e332779a71ddd47b88bced0992c290d67e7.tar.gz
templates: process reversed names better
Change the behavior of `names`, `firstnames` and `initials` functions in templates so they better process names formatted like this: "Last Name, First Name" Basically, if the name contains one (and only one) comma, its parts are flipped so the first name always goes first. This helps to do "Hello Name" in templates regardless of the name format in email address. Also if the template uses a full name it will make it "Hello FirstName LastName" instead of "Hello LastName, FirstName". Add tests to cover more complex names in the future. Signed-off-by: Vitaly Ovchinnikov <v@postbox.nz> Acked-by: Robin Jarry <robin@jarry.cc>
-rw-r--r--CHANGELOG.md1
-rw-r--r--lib/templates/functions.go15
-rw-r--r--lib/templates/functions_test.go123
3 files changed, 136 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9db8acd..74105ee8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
+- Names formatted like "Last Name, First Name" are better supported in templates
- Composing an email is now aborted if the text editor exits with an error
(e.g. with `vim`, abort an email with `:cq`).
diff --git a/lib/templates/functions.go b/lib/templates/functions.go
index 9380bc7b..f083c8fb 100644
--- a/lib/templates/functions.go
+++ b/lib/templates/functions.go
@@ -110,10 +110,18 @@ func toLocal(t time.Time) time.Time {
return time.Time.In(t, time.Local)
}
+func rearrangeNameWithComma(name string) string {
+ parts := strings.SplitN(name, ",", 3)
+ if len(parts) == 2 {
+ return fmt.Sprintf("%s %s", strings.TrimSpace(parts[1]), strings.TrimSpace(parts[0]))
+ }
+ return name
+}
+
func names(addresses []*mail.Address) []string {
n := make([]string, len(addresses))
for i, addr := range addresses {
- name := addr.Name
+ name := rearrangeNameWithComma(addr.Name)
if name == "" {
parts := strings.SplitN(addr.Address, "@", 2)
name = parts[0]
@@ -132,8 +140,9 @@ func firstnames(addresses []*mail.Address) []string {
parts = strings.SplitN(parts[0], ".", 2)
name = parts[0]
} else {
- parts := strings.SplitN(addr.Name, " ", 2)
- name = parts[0]
+ name = rearrangeNameWithComma(addr.Name)
+ name = strings.SplitN(name, " ", 2)[0] // split by spaces and get the first word
+ name = strings.SplitN(name, ",", 2)[0] // split by commas and get the first word
}
n[i] = name
}
diff --git a/lib/templates/functions_test.go b/lib/templates/functions_test.go
new file mode 100644
index 00000000..492aad01
--- /dev/null
+++ b/lib/templates/functions_test.go
@@ -0,0 +1,123 @@
+package templates
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/emersion/go-message/mail"
+)
+
+func TestTemplates_DifferentNamesFormats(t *testing.T) {
+ type testCase struct {
+ address mail.Address
+ name string
+ }
+
+ cases := []testCase{
+ {address: mail.Address{Name: "", Address: "john@doe.com"}, name: "john"},
+ {address: mail.Address{Name: "", Address: "bill.john.doe@doe.com"}, name: "bill.john.doe"},
+ {address: mail.Address{Name: "John", Address: "john@doe.com"}, name: "John"},
+ {address: mail.Address{Name: "John Doe", Address: "john@doe.com"}, name: "John Doe"},
+ {address: mail.Address{Name: "Bill John Doe", Address: "john@doe.com"}, name: "Bill John Doe"},
+ {address: mail.Address{Name: "Doe, John", Address: "john@doe.com"}, name: "John Doe"},
+ {address: mail.Address{Name: "Doe, Bill John", Address: "john@doe.com"}, name: "Bill John Doe"},
+ {address: mail.Address{Name: "Schröder, Gerhard", Address: "s@g.de"}, name: "Gerhard Schröder"},
+ {address: mail.Address{Name: "Buhl-Freiherr von und zu Guttenberg, Karl-Theodor Maria Nikolaus Johann Jacob Philipp Franz Joseph Sylvester", Address: "long@email.com"}, name: "Karl-Theodor Maria Nikolaus Johann Jacob Philipp Franz Joseph Sylvester Buhl-Freiherr von und zu Guttenberg"},
+ {address: mail.Address{Name: "Dr. Őz-Szűcs Villő, MD, PhD, MBA (Üllői úti Klinika, Budapest, Hungary)", Address: "a@b.com"}, name: "Dr. Őz-Szűcs Villő, MD, PhD, MBA (Üllői úti Klinika, Budapest, Hungary)"},
+ {address: mail.Address{Name: "International Important Conference, 2023", Address: "a@b.com"}, name: "2023 International Important Conference"},
+ {address: mail.Address{Name: "A. B.C. Muscat", Address: "a@b.com"}, name: "A. B.C. Muscat"},
+ {address: mail.Address{Name: "Wertram, te, K.W.", Address: "a@b.com"}, name: "Wertram, te, K.W."},
+ {address: mail.Address{Name: "Harvard, John, Dr. CDC/MIT/SYSOPSYS", Address: "a@b.com"}, name: "Harvard, John, Dr. CDC/MIT/SYSOPSYS"},
+ }
+
+ for _, c := range cases {
+ names := names([]*mail.Address{&c.address})
+ assert.Len(t, names, 1)
+ assert.Equal(t, c.name, names[0])
+ }
+}
+
+func TestTemplates_DifferentFirstnamesFormats(t *testing.T) {
+ type testCase struct {
+ address mail.Address
+ firstname string
+ }
+
+ cases := []testCase{
+ {address: mail.Address{Name: "", Address: "john@doe.com"}, firstname: "john"},
+ {address: mail.Address{Name: "", Address: "bill.john.doe@doe.com"}, firstname: "bill"},
+ {address: mail.Address{Name: "John", Address: "john@doe.com"}, firstname: "John"},
+ {address: mail.Address{Name: "John Doe", Address: "john@doe.com"}, firstname: "John"},
+ {address: mail.Address{Name: "Bill John Doe", Address: "john@doe.com"}, firstname: "Bill"},
+ {address: mail.Address{Name: "Doe, John", Address: "john@doe.com"}, firstname: "John"},
+ {address: mail.Address{Name: "Schröder, Gerhard", Address: "s@g.de"}, firstname: "Gerhard"},
+ {address: mail.Address{Name: "Buhl-Freiherr von und zu Guttenberg, Karl-Theodor Maria Nikolaus Johann Jacob Philipp Franz Joseph Sylvester", Address: "long@email.com"}, firstname: "Karl-Theodor"},
+ {address: mail.Address{Name: "Dr. Őz-Szűcs Villő, MD, PhD, MBA (Üllői úti Klinika, Budapest, Hungary)", Address: "a@b.com"}, firstname: "Dr."},
+ {address: mail.Address{Name: "International Important Conference, 2023", Address: "a@b.com"}, firstname: "2023"},
+ {address: mail.Address{Name: "A. B.C. Muscat", Address: "a@b.com"}, firstname: "A."},
+ {address: mail.Address{Name: "Wertram, te, K.W.", Address: "a@b.com"}, firstname: "Wertram"},
+ {address: mail.Address{Name: "Harvard, John, Dr. CDC/MIT/SYSOPSYS", Address: "a@b.com"}, firstname: "Harvard"},
+ }
+
+ for _, c := range cases {
+ names := firstnames([]*mail.Address{&c.address})
+ assert.Len(t, names, 1)
+ assert.Equal(t, c.firstname, names[0])
+ }
+}
+
+func TestTemplates_InternalRearrangeNamesWithComma(t *testing.T) {
+ type testCase struct {
+ source string
+ res string
+ }
+
+ cases := []testCase{
+ {source: "John.Doe", res: "John.Doe"},
+ {source: "John Doe", res: "John Doe"},
+ {source: "John Bill Doe", res: "John Bill Doe"},
+ {source: "Doe, John Bill", res: "John Bill Doe"},
+ {source: "Doe, John-Bill", res: "John-Bill Doe"},
+ {source: "Doe John, Bill", res: "Bill Doe John"},
+ {source: "Schröder, Gerhard", res: "Gerhard Schröder"},
+ // do not touch names with more than one comma
+ {source: "One, Two, Three", res: "One, Two, Three"},
+ {source: "One, Two, Three, Four", res: "One, Two, Three, Four"},
+ }
+
+ for _, c := range cases {
+ res := rearrangeNameWithComma(c.source)
+ assert.Equal(t, c.res, res)
+ }
+}
+
+func TestTemplates_DifferentInitialsFormats(t *testing.T) {
+ type testCase struct {
+ address mail.Address
+ initials string
+ }
+
+ cases := []testCase{
+ {address: mail.Address{Name: "", Address: "john@doe.com"}, initials: "j"},
+ {address: mail.Address{Name: "", Address: "bill.john.doe@doe.com"}, initials: "b"},
+ {address: mail.Address{Name: "John", Address: "john@doe.com"}, initials: "J"},
+ {address: mail.Address{Name: "John Doe", Address: "john@doe.com"}, initials: "JD"},
+ {address: mail.Address{Name: "Bill John Doe", Address: "john@doe.com"}, initials: "BJD"},
+ {address: mail.Address{Name: "Doe, John", Address: "john@doe.com"}, initials: "JD"},
+ {address: mail.Address{Name: "Doe, John Bill", Address: "john@doe.com"}, initials: "JBD"},
+ {address: mail.Address{Name: "Schröder, Gerhard", Address: "s@g.de"}, initials: "GS"},
+ {address: mail.Address{Name: "Buhl-Freiherr von und zu Guttenberg, Karl-Theodor Maria Nikolaus Johann Jacob Philipp Franz Joseph Sylvester", Address: "long@email.com"}, initials: "KMNJJPFJSBvuzG"},
+ {address: mail.Address{Name: "Dr. Őz-Szűcs Villő, MD, PhD, MBA (Üllői úti Klinika, Budapest, Hungary)", Address: "a@b.com"}, initials: "DŐVMPM(úKBH"},
+ {address: mail.Address{Name: "International Important Conference, 2023", Address: "a@b.com"}, initials: "2IIC"},
+ {address: mail.Address{Name: "A. B.C. Muscat", Address: "a@b.com"}, initials: "ABM"},
+ {address: mail.Address{Name: "Wertram, te, K.W.", Address: "a@b.com"}, initials: "WtK"},
+ {address: mail.Address{Name: "Harvard, John, Dr. CDC/MIT/SYSOPSYS", Address: "a@b.com"}, initials: "HJDC"},
+ }
+
+ for _, c := range cases {
+ intls := initials([]*mail.Address{&c.address})
+ assert.Len(t, intls, 1)
+ assert.Equal(t, c.initials, intls[0])
+ }
+}