From aa4e1c8e215e7cdab638e41dbd48fbb34e1f982e Mon Sep 17 00:00:00 2001 From: Bruno Michel <bmichel@menfin.info> Date: Fri, 26 Feb 2021 14:21:10 +0100 Subject: [PATCH] Show the local time for new connection mail When sending the new connection mail, the stack will look at the geodb to find the timezone of the user and will use it to format the time of the connection in the mail. --- assets/locales/en.po | 3 +++ assets/locales/fr.po | 3 +++ go.mod | 1 + go.sum | 6 ++---- model/session/login_history.go | 25 +++++++++++++++++++++---- pkg/i18n/i18n.go | 31 +++++++++++++++++++++++++++++++ 6 files changed, 61 insertions(+), 8 deletions(-) diff --git a/assets/locales/en.po b/assets/locales/en.po index c14f30a22..289ad68b9 100644 --- a/assets/locales/en.po +++ b/assets/locales/en.po @@ -3,6 +3,9 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +msgid "Time Format Long" +msgstr "the Jan 2 2006 at 15h04" + msgid "Tree Administrative" msgstr "Administrative" diff --git a/assets/locales/fr.po b/assets/locales/fr.po index 641c8a5e3..412f1fd17 100644 --- a/assets/locales/fr.po +++ b/assets/locales/fr.po @@ -16,6 +16,9 @@ msgstr "" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +msgid "Time Format Long" +msgstr "le 2 Jan 2006 à 15h04" + msgid "Tree Administrative" msgstr "Administratif" diff --git a/go.mod b/go.mod index c0be49911..1078e36b0 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/gofrs/uuid v3.4.0+incompatible github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f + github.com/goodsign/monday v1.0.0 github.com/google/go-querystring v1.0.0 github.com/google/gops v0.3.14 github.com/gorilla/websocket v1.4.2 diff --git a/go.sum b/go.sum index ca03ae963..2074f47bf 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,6 @@ github.com/cozy/goexif2 v0.0.0-20200819113101-00e1cc8cc9d3 h1:5suSF3q7eNhzpwjs+k github.com/cozy/goexif2 v0.0.0-20200819113101-00e1cc8cc9d3/go.mod h1:PWaQhEQb7UWuVUvXxpFBscfsXmUASdlmMgq97QGcTwU= github.com/cozy/gomail v0.0.0-20170313100128-1395d9a6a6c0 h1:bQVNaGvnUI7m8J8k3hklFVXRT1F+WJcIV6hYHIgjKHE= github.com/cozy/gomail v0.0.0-20170313100128-1395d9a6a6c0/go.mod h1:DlX8Rq7OKA0F9I1e0tz6+PCOXkKZ/l6aD+bWxCC6Qfo= -github.com/cozy/httpcache v0.0.0-20180914105234-d3dc4988de66 h1:b7VTmlsWlhYzJqGLjfhvIiVOpRpNCsOIoV4h0krSkyE= -github.com/cozy/httpcache v0.0.0-20180914105234-d3dc4988de66/go.mod h1:rLnjIcybyvs+PoCzi4+GmpOVp0+q+qdcuZKnKUKJoF4= github.com/cozy/httpcache v0.0.0-20210224123405-3f334f841945 h1:EfeD2CzaZclMHyFxSuaA1BTfqVTLaFwqlASiNNil4nE= github.com/cozy/httpcache v0.0.0-20210224123405-3f334f841945/go.mod h1:rLnjIcybyvs+PoCzi4+GmpOVp0+q+qdcuZKnKUKJoF4= github.com/cozy/prosemirror-go v0.4.9 h1:urukelN1w2qBP+mU2pz2jGEdF/hCJ2C0/1VgjSV1FCw= @@ -201,6 +199,8 @@ github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/goodsign/monday v1.0.0 h1:Yyk/s/WgudMbAJN6UWSU5xAs8jtNewfqtVblAlw0yoc= +github.com/goodsign/monday v1.0.0/go.mod h1:r4T4breXpoFwspQNM+u2sLxJb2zyTaxVGqUfTBjWOu8= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -515,7 +515,6 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -689,7 +688,6 @@ golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191224085550-c709ea063b76 h1:Dho5nD6R3PcW2SH1or8vS0dszDaXRxIw55lBX7XiE5g= golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/model/session/login_history.go b/model/session/login_history.go index a386fb43c..3858cdb4a 100644 --- a/model/session/login_history.go +++ b/model/session/login_history.go @@ -1,6 +1,7 @@ package session import ( + "fmt" "net" "net/http" "net/url" @@ -13,6 +14,7 @@ import ( "github.com/cozy/cozy-stack/pkg/consts" "github.com/cozy/cozy-stack/pkg/couchdb" "github.com/cozy/cozy-stack/pkg/couchdb/mango" + "github.com/cozy/cozy-stack/pkg/i18n" "github.com/cozy/cozy-stack/pkg/logger" "github.com/mssola/user_agent" maxminddb "github.com/oschwald/maxminddb-golang" @@ -58,7 +60,7 @@ func (l *LoginEntry) Clone() couchdb.Doc { return &clone } -func lookupIP(ip, locale string) (city, subdivision, country string) { +func lookupIP(ip, locale string) (city, subdivision, country, timezone string) { geodb := config.GetConfig().GeoDB if geodb == "" { return @@ -80,6 +82,9 @@ func lookupIP(ip, locale string) (city, subdivision, country string) { Country struct { Names map[string]string `maxminddb:"names"` } `maxminddb:"country"` + Location struct { + TimeZone string `maxminddb:"time_zone"` + } `maxminddb:"location"` } err = db.Lookup(net.ParseIP(ip), &record) @@ -104,6 +109,7 @@ func lookupIP(ip, locale string) (city, subdivision, country string) { } else if c, ok := record.Country.Names["en"]; ok { country = c } + timezone = record.Location.TimeZone return } @@ -118,12 +124,20 @@ func StoreNewLoginEntry(i *instance.Instance, sessionID, clientID string, req *h ip = strings.Split(req.RemoteAddr, ":")[0] } - city, subdivision, country := lookupIP(ip, i.Locale) + city, subdivision, country, timezone := lookupIP(ip, i.Locale) ua := user_agent.New(req.UserAgent()) browser, _ := ua.Browser() os := ua.OS() + createdAt := time.Now() + if timezone != "" { + if loc, err := time.LoadLocation(timezone); err == nil { + createdAt = createdAt.In(loc) + fmt.Printf("createdAt = %v\n", createdAt) + } + } + l := &LoginEntry{ IP: ip, SessionID: sessionID, @@ -134,7 +148,7 @@ func StoreNewLoginEntry(i *instance.Instance, sessionID, clientID string, req *h OS: os, Browser: browser, ClientRegistration: clientID != "", - CreatedAt: time.Now(), + CreatedAt: createdAt, } if err := couchdb.CreateDoc(i, l); err != nil { @@ -183,8 +197,11 @@ func sendLoginNotification(i *instance.Instance, l *LoginEntry) error { activateTwoFALink = settingsURL.String() } + layout := i.Translate("Time Format Long") + time := i18n.LocalizeTime(l.CreatedAt, i.Locale, layout) + templateValues := map[string]interface{}{ - "Time": l.CreatedAt.Format("2006-01-02 15:04:05Z07:00"), + "Time": time, "IP": l.IP, "Browser": l.Browser, "OS": l.OS, diff --git a/pkg/i18n/i18n.go b/pkg/i18n/i18n.go index 4e6bf32cb..41543d7dd 100644 --- a/pkg/i18n/i18n.go +++ b/pkg/i18n/i18n.go @@ -3,9 +3,11 @@ package i18n import ( "fmt" "strings" + "time" "github.com/cozy/cozy-stack/pkg/consts" "github.com/cozy/cozy-stack/pkg/logger" + "github.com/goodsign/monday" "github.com/leonelquinteros/gotext" ) @@ -46,3 +48,32 @@ func Translate(key, locale string, vars ...interface{}) string { } return fmt.Sprintf(key, vars...) } + +// LocalizeTime transforms a date+time in a string for the given locale. +// The layout is in the same format as the one given to time.Format. +func LocalizeTime(t time.Time, locale, layout string) string { + return monday.Format(t, layout, mondayLocale(locale)) +} + +func mondayLocale(locale string) monday.Locale { + switch locale { + case "de", "de_DE": + return monday.LocaleDeDE + case "es", "es_ES": + return monday.LocaleEsES + case "fr", "fr_FR": + return monday.LocaleFrFR + case "it", "it_IT": + return monday.LocaleItIT + case "ja", "ja_JP": + return monday.LocaleJaJP + case "nl", "nl_NL": + return monday.LocaleNlNL + case "pt", "pt_PT": + return monday.LocalePtPT + case "ru", "ru_RU": + return monday.LocaleRuRU + default: + return monday.LocaleEnUS + } +} -- GitLab