From 2a26d857574f2160e3ee5538ad3a84ec47082f86 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Thu, 21 Jan 2016 12:14:17 -0500 Subject: Generalize analytics server functions and begin componentizing client analytics controls --- api/admin.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'api') diff --git a/api/admin.go b/api/admin.go index 72a95ba6a..e19616986 100644 --- a/api/admin.go +++ b/api/admin.go @@ -27,6 +27,7 @@ func InitAdmin(r *mux.Router) { sr.Handle("/client_props", ApiAppHandler(getClientConfig)).Methods("GET") sr.Handle("/log_client", ApiAppHandler(logClient)).Methods("POST") sr.Handle("/analytics/{id:[A-Za-z0-9]+}/{name:[A-Za-z0-9_]+}", ApiAppHandler(getAnalytics)).Methods("GET") + sr.Handle("/analytics/{name:[A-Za-z0-9_]+}", ApiAppHandler(getAnalytics)).Methods("GET") } func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { @@ -153,13 +154,15 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { name := params["name"] if name == "standard" { - var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 3) + var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 4) rows[0] = &model.AnalyticsRow{"channel_open_count", 0} rows[1] = &model.AnalyticsRow{"channel_private_count", 0} rows[2] = &model.AnalyticsRow{"post_count", 0} + rows[3] = &model.AnalyticsRow{"unique_user_count", 0} openChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_OPEN) privateChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_PRIVATE) postChan := Srv.Store.Post().AnalyticsPostCount(teamId) + userChan := Srv.Store.User().AnalyticsUniqueUserCount(teamId) if r := <-openChan; r.Err != nil { c.Err = r.Err @@ -182,6 +185,13 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { rows[2].Value = float64(r.Data.(int64)) } + if r := <-userChan; r.Err != nil { + c.Err = r.Err + return + } else { + rows[3].Value = float64(r.Data.(int64)) + } + w.Write([]byte(rows.ToJson())) } else if name == "post_counts_day" { if r := <-Srv.Store.Post().AnalyticsPostCountsByDay(teamId); r.Err != nil { -- cgit v1.2.3-1-g7c22 From bbcf00f02e469bcf04a45c1cdf8a7932e30ccfc0 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 22 Jan 2016 09:53:17 -0500 Subject: Add create_at back to profile fields to fix analytics --- api/license.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'api') diff --git a/api/license.go b/api/license.go index 5b3809651..fc2fd4384 100644 --- a/api/license.go +++ b/api/license.go @@ -5,6 +5,7 @@ package api import ( "bytes" + "fmt" l4g "github.com/alecthomas/log4go" "github.com/gorilla/mux" "github.com/mattermost/platform/model" @@ -63,6 +64,18 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) { if success, licenseStr := utils.ValidateLicense(data); success { license = model.LicenseFromJson(strings.NewReader(licenseStr)) + if result := <-Srv.Store.User().AnalyticsUniqueUserCount(""); result.Err != nil { + c.Err = model.NewAppError("addLicense", "Unable to count total unique users.", fmt.Sprintf("err=%v", result.Err.Error())) + return + } else { + uniqueUserCount := result.Data.(int64) + + if uniqueUserCount > int64(*license.Features.Users) { + c.Err = model.NewAppError("addLicense", fmt.Sprintf("This license only supports %d users, when your system has %d unique users. Unique users are counted distinctly by email address. You can see total user count under Site Reports -> View Statistics.", *license.Features.Users, uniqueUserCount), "") + return + } + } + if ok := utils.SetLicense(license); !ok { c.LogAudit("failed - expired or non-started license") c.Err = model.NewAppError("addLicense", "License is either expired or has not yet started.", "") -- cgit v1.2.3-1-g7c22 From 0d239a1a9e82a1279685b8962920eaf5c1b8f571 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 22 Jan 2016 10:19:02 -0500 Subject: Added unit test and fixed errors --- api/admin_test.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 7 deletions(-) (limited to 'api') diff --git a/api/admin_test.go b/api/admin_test.go index f7b6a7eeb..c2f4e9c76 100644 --- a/api/admin_test.go +++ b/api/admin_test.go @@ -151,7 +151,7 @@ func TestEmailTest(t *testing.T) { } } -func TestGetAnalyticsStandard(t *testing.T) { +func TestGetTeamAnalyticsStandard(t *testing.T) { Setup() team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} @@ -169,7 +169,7 @@ func TestGetAnalyticsStandard(t *testing.T) { post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"} post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post) - if _, err := Client.GetAnalytics(team.Id, "standard"); err == nil { + if _, err := Client.GetTeamAnalytics(team.Id, "standard"); err == nil { t.Fatal("Shouldn't have permissions") } @@ -180,7 +180,7 @@ func TestGetAnalyticsStandard(t *testing.T) { Client.LoginByEmail(team.Name, user.Email, "pwd") - if result, err := Client.GetAnalytics(team.Id, "standard"); err != nil { + if result, err := Client.GetTeamAnalytics(team.Id, "standard"); err != nil { t.Fatal(err) } else { rows := result.Data.(model.AnalyticsRows) @@ -214,6 +214,62 @@ func TestGetAnalyticsStandard(t *testing.T) { t.Log(rows.ToJson()) t.Fatal() } + + if rows[3].Name != "unique_user_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[3].Value != 1 { + t.Log(rows.ToJson()) + t.Fatal() + } + } + + if result, err := Client.GetSystemAnalytics("standard"); err != nil { + t.Fatal(err) + } else { + rows := result.Data.(model.AnalyticsRows) + + if rows[0].Name != "channel_open_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[0].Value < 2 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[1].Name != "channel_private_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[1].Value == 0 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[2].Name != "post_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[2].Value == 0 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[3].Name != "unique_user_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[3].Value == 0 { + t.Log(rows.ToJson()) + t.Fatal() + } } } @@ -239,7 +295,7 @@ func TestGetPostCount(t *testing.T) { Srv.Store.(*store.SqlStore).GetMaster().Exec("UPDATE Posts SET CreateAt = :CreateAt WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channel1.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())}) - if _, err := Client.GetAnalytics(team.Id, "post_counts_day"); err == nil { + if _, err := Client.GetTeamAnalytics(team.Id, "post_counts_day"); err == nil { t.Fatal("Shouldn't have permissions") } @@ -250,7 +306,7 @@ func TestGetPostCount(t *testing.T) { Client.LoginByEmail(team.Name, user.Email, "pwd") - if result, err := Client.GetAnalytics(team.Id, "post_counts_day"); err != nil { + if result, err := Client.GetTeamAnalytics(team.Id, "post_counts_day"); err != nil { t.Fatal(err) } else { rows := result.Data.(model.AnalyticsRows) @@ -284,7 +340,7 @@ func TestUserCountsWithPostsByDay(t *testing.T) { Srv.Store.(*store.SqlStore).GetMaster().Exec("UPDATE Posts SET CreateAt = :CreateAt WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channel1.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())}) - if _, err := Client.GetAnalytics(team.Id, "user_counts_with_posts_day"); err == nil { + if _, err := Client.GetTeamAnalytics(team.Id, "user_counts_with_posts_day"); err == nil { t.Fatal("Shouldn't have permissions") } @@ -295,7 +351,7 @@ func TestUserCountsWithPostsByDay(t *testing.T) { Client.LoginByEmail(team.Name, user.Email, "pwd") - if result, err := Client.GetAnalytics(team.Id, "user_counts_with_posts_day"); err != nil { + if result, err := Client.GetTeamAnalytics(team.Id, "user_counts_with_posts_day"); err != nil { t.Fatal(err) } else { rows := result.Data.(model.AnalyticsRows) -- cgit v1.2.3-1-g7c22 From eb58e631e74d9a5ff0992a67cd9452b3a525c5e6 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sat, 23 Jan 2016 10:25:10 -0300 Subject: PLT-7: Refactoring api to use translations (chunk 3) - Add spanish translations - Not included tests and templates --- api/web_conn.go | 7 ++++--- api/web_hub.go | 3 ++- api/web_socket.go | 7 ++++--- api/web_team_hub.go | 3 ++- api/webhook.go | 24 ++++++++++++------------ 5 files changed, 24 insertions(+), 20 deletions(-) (limited to 'api') diff --git a/api/web_conn.go b/api/web_conn.go index 2b0e29038..515a8ab31 100644 --- a/api/web_conn.go +++ b/api/web_conn.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/websocket" "github.com/mattermost/platform/model" "github.com/mattermost/platform/store" + "github.com/mattermost/platform/utils" "time" ) @@ -33,11 +34,11 @@ func NewWebConn(ws *websocket.Conn, teamId string, userId string, sessionId stri pchan := Srv.Store.User().UpdateLastPingAt(userId, model.GetMillis()) if result := <-achan; result.Err != nil { - l4g.Error("Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v", userId, sessionId, result.Err) + l4g.Error(utils.T("api.web_conn.new_web_conn.last_activity.error"), userId, sessionId, result.Err) } if result := <-pchan; result.Err != nil { - l4g.Error("Failed to updated LastPingAt for user_id=%v, err=%v", userId, result.Err) + l4g.Error(utils.T("api.web_conn.new_web_conn.last_ping.error"), userId, result.Err) } }() @@ -56,7 +57,7 @@ func (c *WebConn) readPump() { go func() { if result := <-Srv.Store.User().UpdateLastPingAt(c.UserId, model.GetMillis()); result.Err != nil { - l4g.Error("Failed to updated LastPingAt for user_id=%v, err=%v", c.UserId, result.Err) + l4g.Error(utils.T("api.web_conn.new_web_conn.last_ping.error"), c.UserId, result.Err) } }() diff --git a/api/web_hub.go b/api/web_hub.go index 4361d1035..5fe9d6ae8 100644 --- a/api/web_hub.go +++ b/api/web_hub.go @@ -6,6 +6,7 @@ package api import ( l4g "github.com/alecthomas/log4go" "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" ) type Hub struct { @@ -86,7 +87,7 @@ func (h *Hub) Start() { nh.broadcast <- msg } case s := <-h.stop: - l4g.Debug("stopping %v connections", s) + l4g.Debug(utils.T("api.web_hub.start.stopping.debug"), s) for _, v := range h.teamHubs { v.Stop() } diff --git a/api/web_socket.go b/api/web_socket.go index 995e2a677..7590e6646 100644 --- a/api/web_socket.go +++ b/api/web_socket.go @@ -8,11 +8,12 @@ import ( "github.com/gorilla/mux" "github.com/gorilla/websocket" "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" "net/http" ) func InitWebSocket(r *mux.Router) { - l4g.Debug("Initializing web socket api routes") + l4g.Debug(utils.T("api.web_socket.init.debug")) r.Handle("/websocket", ApiUserRequired(connect)).Methods("GET") hub.Start() } @@ -28,8 +29,8 @@ func connect(c *Context, w http.ResponseWriter, r *http.Request) { ws, err := upgrader.Upgrade(w, r, nil) if err != nil { - l4g.Error("websocket connect err: %v", err) - c.Err = model.NewAppError("connect", "Failed to upgrade websocket connection", "") + l4g.Error(utils.T("api.web_socket.connect.error"), err) + c.Err = model.NewLocAppError("connect", "api.web_socket.connect.upgrade.app_error", nil, "") return } diff --git a/api/web_team_hub.go b/api/web_team_hub.go index bb9ed9526..55300c828 100644 --- a/api/web_team_hub.go +++ b/api/web_team_hub.go @@ -6,6 +6,7 @@ package api import ( l4g "github.com/alecthomas/log4go" "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" ) type TeamHub struct { @@ -65,7 +66,7 @@ func (h *TeamHub) Start() { case s := <-h.stop: if s { - l4g.Debug("team hub stopping for teamId=%v", h.teamId) + l4g.Debug(utils.T("api.web_team_hun.start.debug"), h.teamId) for webCon := range h.connections { webCon.WebSocket.Close() diff --git a/api/webhook.go b/api/webhook.go index a9a88b7b8..1372fe335 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -12,7 +12,7 @@ import ( ) func InitWebhook(r *mux.Router) { - l4g.Debug("Initializing webhook api routes") + l4g.Debug(utils.T("api.webhook.init.debug")) sr := r.PathPrefix("/hooks").Subrouter() sr.Handle("/incoming/create", ApiUserRequired(createIncomingHook)).Methods("POST") @@ -27,7 +27,7 @@ func InitWebhook(r *mux.Router) { func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("createIncomingHook", "Incoming webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("createIncomingHook", "api.webhook.create_incoming.disabled.app_errror", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -74,7 +74,7 @@ func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("deleteIncomingHook", "Incoming webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("deleteIncomingHook", "api.webhook.delete_incoming.disabled.app_errror", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -95,7 +95,7 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { } else { if c.Session.UserId != result.Data.(*model.IncomingWebhook).UserId && !c.IsTeamAdmin() { c.LogAudit("fail - inappropriate permissions") - c.Err = model.NewAppError("deleteIncomingHook", "Inappropriate permissions to delete incoming webhook", "user_id="+c.Session.UserId) + c.Err = model.NewLocAppError("deleteIncomingHook", "api.webhook.delete_incoming.permissions.app_errror", nil, "user_id="+c.Session.UserId) return } } @@ -111,7 +111,7 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("getIncomingHooks", "Incoming webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("getIncomingHooks", "api.webhook.get_incoming.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -127,7 +127,7 @@ func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) { func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks { - c.Err = model.NewAppError("createOutgoingHook", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("createOutgoingHook", "api.webhook.create_outgoing.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -167,7 +167,7 @@ func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { } } } else if len(hook.TriggerWords) == 0 { - c.Err = model.NewAppError("createOutgoingHook", "Either trigger_words or channel_id must be set", "") + c.Err = model.NewLocAppError("createOutgoingHook", "api.webhook.create_outgoing.triggers.app_error", nil, "") return } @@ -183,7 +183,7 @@ func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { func getOutgoingHooks(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks { - c.Err = model.NewAppError("getOutgoingHooks", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("getOutgoingHooks", "api.webhook.get_outgoing.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -199,7 +199,7 @@ func getOutgoingHooks(c *Context, w http.ResponseWriter, r *http.Request) { func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("deleteOutgoingHook", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("deleteOutgoingHook", "api.webhook.delete_outgoing.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -220,7 +220,7 @@ func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { } else { if c.Session.UserId != result.Data.(*model.OutgoingWebhook).CreatorId && !c.IsTeamAdmin() { c.LogAudit("fail - inappropriate permissions") - c.Err = model.NewAppError("deleteOutgoingHook", "Inappropriate permissions to delete outcoming webhook", "user_id="+c.Session.UserId) + c.Err = model.NewLocAppError("deleteOutgoingHook", "api.webhook.delete_outgoing.permissions.app_error", nil, "user_id="+c.Session.UserId) return } } @@ -236,7 +236,7 @@ func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("regenOutgoingHookToken", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("regenOutgoingHookToken", "api.webhook.regen_outgoing_token.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -260,7 +260,7 @@ func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request) if c.Session.UserId != hook.CreatorId && !c.IsTeamAdmin() { c.LogAudit("fail - inappropriate permissions") - c.Err = model.NewAppError("regenOutgoingHookToken", "Inappropriate permissions to regenerate outcoming webhook token", "user_id="+c.Session.UserId) + c.Err = model.NewLocAppError("regenOutgoingHookToken", "api.webhook.regen_outgoing_token.permissions.app_error", nil, "user_id="+c.Session.UserId) return } } -- cgit v1.2.3-1-g7c22 From 470349d105642d7a293983a8a1f8a369dc789621 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sun, 24 Jan 2016 17:10:54 -0300 Subject: PLT-7: Refactoring api to use translations (chunk 4) - Translation for api templates english and spanish --- api/api.go | 12 ++- api/context.go | 7 ++ api/post.go | 35 ++++--- api/team.go | 48 ++++++---- api/templates/email_change_body.html | 4 +- api/templates/email_change_subject.html | 2 +- api/templates/email_change_verify_body.html | 6 +- api/templates/email_change_verify_subject.html | 2 +- api/templates/email_footer.html | 2 +- api/templates/email_info.html | 4 +- api/templates/error.html | 4 +- api/templates/find_teams_body.html | 10 +- api/templates/find_teams_subject.html | 2 +- api/templates/invite_body.html | 8 +- api/templates/invite_subject.html | 2 +- api/templates/password_change_body.html | 4 +- api/templates/password_change_subject.html | 2 +- api/templates/post_body.html | 6 +- api/templates/post_subject.html | 2 +- api/templates/reset_body.html | 6 +- api/templates/reset_subject.html | 2 +- api/templates/signin_change_body.html | 4 +- api/templates/signin_change_subject.html | 2 +- api/templates/signup_team_body.html | 6 +- api/templates/signup_team_subject.html | 2 +- api/templates/verify_body.html | 6 +- api/templates/verify_subject.html | 2 +- api/templates/welcome_body.html | 10 +- api/templates/welcome_subject.html | 2 +- api/user.go | 121 +++++++++++++++---------- 30 files changed, 187 insertions(+), 138 deletions(-) (limited to 'api') diff --git a/api/api.go b/api/api.go index f537bbfdc..d202172d0 100644 --- a/api/api.go +++ b/api/api.go @@ -19,17 +19,25 @@ var ServerTemplates *template.Template type ServerTemplatePage Page -func NewServerTemplatePage(templateName string) *ServerTemplatePage { +func NewServerTemplatePage(templateName, locale string) *ServerTemplatePage { return &ServerTemplatePage{ TemplateName: templateName, Props: make(map[string]string), + Extra: make(map[string]string), + Html: make(map[string]template.HTML), ClientCfg: utils.ClientCfg, - Locale: model.DEFAULT_LOCALE, + Locale: locale, } } func (me *ServerTemplatePage) Render() string { var text bytes.Buffer + + T := utils.GetUserTranslations(me.Locale) + me.Props["Footer"] = T("api.templates.email_footer") + me.Html["EmailInfo"] = template.HTML(T("api.templates.email_info", + map[string]interface{}{"FeedbackEmail": me.ClientCfg["FeedbackEmail"], "SiteName": me.ClientCfg["SiteName"]})) + if err := ServerTemplates.ExecuteTemplate(&text, me.TemplateName, me); err != nil { l4g.Error(utils.T("api.api.render.error"), me.TemplateName, err) } diff --git a/api/context.go b/api/context.go index f47ed1c30..41a52fa0c 100644 --- a/api/context.go +++ b/api/context.go @@ -5,6 +5,7 @@ package api import ( "fmt" + "html/template" "net" "net/http" "net/url" @@ -37,6 +38,8 @@ type Context struct { type Page struct { TemplateName string Props map[string]string + Extra map[string]string + Html map[string]template.HTML ClientCfg map[string]string ClientLicense map[string]string User *model.User @@ -507,6 +510,10 @@ func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) props["SiteURL"] = GetProtocol(r) + "://" + r.Host } + T, _ := utils.GetTranslationsAndLocale(w, r) + props["Title"] = T("api.templates.error.title", map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]}) + props["Link"] = T("api.templates.error.link") + w.WriteHeader(err.StatusCode) ServerTemplates.ExecuteTemplate(w, "error.html", Page{Props: props, ClientCfg: utils.ClientCfg}) } diff --git a/api/post.go b/api/post.go index bb6bcb337..d3807653d 100644 --- a/api/post.go +++ b/api/post.go @@ -10,6 +10,7 @@ import ( "github.com/mattermost/platform/model" "github.com/mattermost/platform/store" "github.com/mattermost/platform/utils" + "html/template" "net/http" "net/url" "path/filepath" @@ -593,28 +594,26 @@ func sendNotificationsAndForget(c *Context, post *model.Post, team *model.Team, channelName = channel.DisplayName } - subjectPage := NewServerTemplatePage("post_subject") - subjectPage.Props["SiteURL"] = c.GetSiteURL() - subjectPage.Props["TeamDisplayName"] = team.DisplayName - subjectPage.Props["SubjectText"] = subjectText - subjectPage.Props["Month"] = tm.Month().String()[:3] - subjectPage.Props["Day"] = fmt.Sprintf("%d", tm.Day()) - subjectPage.Props["Year"] = fmt.Sprintf("%d", tm.Year()) + month := userLocale(tm.Month().String()) + day := fmt.Sprintf("%d", tm.Day()) + year := fmt.Sprintf("%d", tm.Year()) + zone, _ := tm.Zone() - bodyPage := NewServerTemplatePage("post_body") + subjectPage := NewServerTemplatePage("post_subject", c.Locale) + subjectPage.Props["Subject"] = userLocale("api.templates.post_subject", + map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName, + "Month": month[:3], "Day": day, "Year": year}) + + bodyPage := NewServerTemplatePage("post_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage.Props["Nickname"] = profileMap[id].FirstName - bodyPage.Props["TeamDisplayName"] = team.DisplayName - bodyPage.Props["ChannelName"] = channelName - bodyPage.Props["BodyText"] = bodyText - bodyPage.Props["SenderName"] = senderName - bodyPage.Props["Hour"] = fmt.Sprintf("%02d", tm.Hour()) - bodyPage.Props["Minute"] = fmt.Sprintf("%02d", tm.Minute()) - bodyPage.Props["Month"] = tm.Month().String()[:3] - bodyPage.Props["Day"] = fmt.Sprintf("%d", tm.Day()) - bodyPage.Props["TimeZone"], _ = tm.Zone() bodyPage.Props["PostMessage"] = model.ClearMentionTags(post.Message) bodyPage.Props["TeamLink"] = teamURL + "/channels/" + channel.Name + bodyPage.Props["BodyText"] = bodyText + bodyPage.Props["Button"] = userLocale("api.templates.post_body.button") + bodyPage.Html["Info"] = template.HTML(userLocale("api.templates.post_body.info", + map[string]interface{}{"ChannelName": channelName, "SenderName": senderName, + "Hour": fmt.Sprintf("%02d", tm.Hour()), "Minute": fmt.Sprintf("%02d", tm.Minute()), + "TimeZone": zone, "Month": month, "Day": day})) // attempt to fill in a message body if the post doesn't have any text if len(strings.TrimSpace(bodyPage.Props["PostMessage"])) == 0 && len(post.Filenames) > 0 { diff --git a/api/team.go b/api/team.go index 57a0e0bd2..779a6affe 100644 --- a/api/team.go +++ b/api/team.go @@ -11,6 +11,7 @@ import ( "github.com/mattermost/platform/model" "github.com/mattermost/platform/store" "github.com/mattermost/platform/utils" + "html/template" "net/http" "net/url" "strconv" @@ -57,10 +58,16 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } - subjectPage := NewServerTemplatePage("signup_team_subject") - subjectPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage := NewServerTemplatePage("signup_team_body") + subjectPage := NewServerTemplatePage("signup_team_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.signup_team_subject", + map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("signup_team_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() + bodyPage.Props["Title"] = c.T("api.templates.signup_team_body.title") + bodyPage.Props["Button"] = c.T("api.templates.signup_team_body.button") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.signup_team_body.button", + map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]})) props := make(map[string]string) props["email"] = email @@ -427,10 +434,16 @@ func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) { return } - subjectPage := NewServerTemplatePage("find_teams_subject") - subjectPage.ClientCfg["SiteURL"] = c.GetSiteURL() - bodyPage := NewServerTemplatePage("find_teams_body") - bodyPage.ClientCfg["SiteURL"] = c.GetSiteURL() + siteURL := c.GetSiteURL() + subjectPage := NewServerTemplatePage("find_teams_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.find_teams_subject", + map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("find_teams_body", c.Locale) + bodyPage.Props["SiteURL"] = siteURL + bodyPage.Props["Title"] = c.T("api.templates.find_teams_body.title") + bodyPage.Props["Found"] = c.T("api.templates.find_teams_body.found") + bodyPage.Props["NotFound"] = c.T("api.templates.find_teams_body.not_found") if result := <-Srv.Store.Team().GetTeamsForEmail(email); result.Err != nil { c.Err = result.Err @@ -442,7 +455,7 @@ func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) { for _, team := range teams { props[team.Name] = c.GetTeamURLFromTeam(team) } - bodyPage.Props = props + bodyPage.Extra = props if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.team.email_teams.sending.error"), err) @@ -511,16 +524,19 @@ func InviteMembers(c *Context, team *model.Team, user *model.User, invites []str senderRole = c.T("api.team.invite_members.member") } - subjectPage := NewServerTemplatePage("invite_subject") - subjectPage.Props["SenderName"] = sender - subjectPage.Props["TeamDisplayName"] = team.DisplayName + subjectPage := NewServerTemplatePage("invite_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.invite_subject", + map[string]interface{}{"SenderName": sender, "TeamDisplayName": team.DisplayName, "SiteName": utils.ClientCfg["SiteName"]}) - bodyPage := NewServerTemplatePage("invite_body") + bodyPage := NewServerTemplatePage("invite_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage.Props["TeamURL"] = c.GetTeamURL() - bodyPage.Props["TeamDisplayName"] = team.DisplayName - bodyPage.Props["SenderName"] = sender - bodyPage.Props["SenderStatus"] = senderRole + bodyPage.Props["Title"] = c.T("api.templates.invite_body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.invite_body.info", + map[string]interface{}{"SenderStatus": senderRole, "SenderName": sender, "TeamDisplayName": team.DisplayName})) + bodyPage.Props["Button"] = c.T("api.templates.invite_body.button") + bodyPage.Html["ExtraInfo"] = template.HTML(c.T("api.templates.invite_body.extra_info", + map[string]interface{}{"TeamDisplayName": team.DisplayName, "TeamURL": c.GetTeamURL()})) + props := make(map[string]string) props["email"] = invite props["id"] = team.Id diff --git a/api/templates/email_change_body.html b/api/templates/email_change_body.html index 7349aee6f..4f28584c4 100644 --- a/api/templates/email_change_body.html +++ b/api/templates/email_change_body.html @@ -17,8 +17,8 @@ diff --git a/api/templates/email_change_subject.html b/api/templates/email_change_subject.html index 4ff8026f1..afabc2191 100644 --- a/api/templates/email_change_subject.html +++ b/api/templates/email_change_subject.html @@ -1 +1 @@ -{{define "email_change_subject"}}[{{.ClientCfg.SiteName}}] Your email address has changed for {{.Props.TeamDisplayName}}{{end}} +{{define "email_change_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.Subject}}{{end}} diff --git a/api/templates/email_change_verify_body.html b/api/templates/email_change_verify_body.html index 9d2c559b3..0d0c0aaba 100644 --- a/api/templates/email_change_verify_body.html +++ b/api/templates/email_change_verify_body.html @@ -17,10 +17,10 @@
-

You updated your email

-

You email address for {{.Props.TeamDisplayName}} has been changed to {{.Props.NewEmail}}.
If you did not make this change, please contact the system administrator.

+

{{.Props.Title}}

+

{{.Props.Info}}

diff --git a/api/templates/email_change_verify_subject.html b/api/templates/email_change_verify_subject.html index 744aaccfc..4fc4f4846 100644 --- a/api/templates/email_change_verify_subject.html +++ b/api/templates/email_change_verify_subject.html @@ -1 +1 @@ -{{define "email_change_verify_subject"}}[{{.ClientCfg.SiteName}}] Verify new email address for {{.Props.TeamDisplayName}}{{end}} +{{define "email_change_verify_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.Subject}}{{end}} diff --git a/api/templates/email_footer.html b/api/templates/email_footer.html index e3ff9c584..6dc7fa483 100644 --- a/api/templates/email_footer.html +++ b/api/templates/email_footer.html @@ -6,7 +6,7 @@

(c) 2015 Mattermost, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.
- To change your notification preferences, log in to your team site and go to Account Settings > Notifications. + {{.Props.Footer}}

diff --git a/api/templates/email_info.html b/api/templates/email_info.html index 48725d144..0a34f18a0 100644 --- a/api/templates/email_info.html +++ b/api/templates/email_info.html @@ -1,9 +1,7 @@ {{define "email_info"}} {{end}} diff --git a/api/templates/error.html b/api/templates/error.html index 9fb2da1ba..2b6211be2 100644 --- a/api/templates/error.html +++ b/api/templates/error.html @@ -22,9 +22,9 @@
-

{{ .ClientCfg.SiteName }} needs your help:

+

{{.Props.Title}}

{{ .Props.Message }}

- Go back to team site + {{.Props.Link}}
diff --git a/api/templates/find_teams_body.html b/api/templates/find_teams_body.html index 0b52af033..1324091aa 100644 --- a/api/templates/find_teams_body.html +++ b/api/templates/find_teams_body.html @@ -17,14 +17,14 @@
-

You updated your email

-

To finish updating your email address for {{.Props.TeamDisplayName}}, please click the link below to confirm this is the right address.

+

{{.Props.Title}}

+

{{.Props.Info}}

- Verify Email + {{.Props.VerifyButton}}

- Any questions at all, mail us any time: {{.ClientCfg.FeedbackEmail}}.
- Best wishes,
- The {{.ClientCfg.SiteName}} Team
+ {{.Html.EmailInfo}}
diff --git a/api/templates/find_teams_subject.html b/api/templates/find_teams_subject.html index f3a1437b3..ebc339562 100644 --- a/api/templates/find_teams_subject.html +++ b/api/templates/find_teams_subject.html @@ -1 +1 @@ -{{define "find_teams_subject"}}Your {{ .ClientCfg.SiteName }} Teams{{end}} +{{define "find_teams_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/invite_body.html b/api/templates/invite_body.html index a81d0c3d5..2b6bde6d3 100644 --- a/api/templates/invite_body.html +++ b/api/templates/invite_body.html @@ -17,13 +17,13 @@
-

Finding teams

-

{{ if .Props }} - Your request to find teams associated with your email found the following:
- {{range $index, $element := .Props}} +

{{.Props.Title}}

+

{{ if .Extra }} + {{.Props.Found}}
+ {{range $index, $element := .Extra}} {{ $index }}
{{ end }} {{ else }} - We could not find any teams for the given email. + {{.Props.NotFound}} {{ end }}

diff --git a/api/templates/invite_subject.html b/api/templates/invite_subject.html index 10f68969f..504915d50 100644 --- a/api/templates/invite_subject.html +++ b/api/templates/invite_subject.html @@ -1 +1 @@ -{{define "invite_subject"}}{{ .Props.SenderName }} invited you to join {{ .Props.TeamDisplayName }} Team on {{.ClientCfg.SiteName}}{{end}} +{{define "invite_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/password_change_body.html b/api/templates/password_change_body.html index 6199a3423..2c4ba10ca 100644 --- a/api/templates/password_change_body.html +++ b/api/templates/password_change_body.html @@ -17,8 +17,8 @@
-

You've been invited

-

The team {{.Props.SenderStatus}} {{.Props.SenderName}}, has invited you to join {{.Props.TeamDisplayName}}.

+

{{.Props.Title}}

+

{{.Html.Info}}

- Join Team + {{.Props.Button}}


-

Mattermost lets you share messages and files from your PC or phone, with instant search and archiving. After you’ve joined {{.Props.TeamDisplayName}}, you can sign-in to your new team and access these features anytime from the web address:

{{.Props.TeamURL}}

+

{{.Html.ExtraInfo}}

diff --git a/api/templates/password_change_subject.html b/api/templates/password_change_subject.html index 0cbf052c1..897f1210d 100644 --- a/api/templates/password_change_subject.html +++ b/api/templates/password_change_subject.html @@ -1 +1 @@ -{{define "password_change_subject"}}Your password has been updated for {{.Props.TeamDisplayName}} on {{ .ClientCfg.SiteName }}{{end}} +{{define "password_change_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/post_body.html b/api/templates/post_body.html index 468d5e205..54f34d1dd 100644 --- a/api/templates/post_body.html +++ b/api/templates/post_body.html @@ -17,10 +17,10 @@
-

You updated your password

-

Your password has been updated for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} by {{.Props.Method}}.
If this change wasn't initiated by you, please contact your system administrator.

+

{{.Props.Title}}

+

{{.Html.Info}}

diff --git a/api/templates/post_subject.html b/api/templates/post_subject.html index f53353d85..60daaa432 100644 --- a/api/templates/post_subject.html +++ b/api/templates/post_subject.html @@ -1 +1 @@ -{{define "post_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.TeamDisplayName}} Team Notifications for {{.Props.Month}} {{.Props.Day}}, {{.Props.Year}}{{end}} +{{define "post_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.Subject}}{{end}} diff --git a/api/templates/reset_body.html b/api/templates/reset_body.html index a608c804a..69cd44957 100644 --- a/api/templates/reset_body.html +++ b/api/templates/reset_body.html @@ -17,10 +17,10 @@
-

You were mentioned

-

CHANNEL: {{.Props.ChannelName}}
{{.Props.SenderName}} - {{.Props.Hour}}:{{.Props.Minute}} {{.Props.TimeZone}}, {{.Props.Month}} {{.Props.Day}}

{{.Props.PostMessage}}

+

{{.Props.BodyText}}

+

{{.Html.Info}}

{{.Props.PostMessage}}

- Go To Channel + {{.Props.Button}}

diff --git a/api/templates/reset_subject.html b/api/templates/reset_subject.html index 87ad7bc38..a2852d332 100644 --- a/api/templates/reset_subject.html +++ b/api/templates/reset_subject.html @@ -1 +1 @@ -{{define "reset_subject"}}Reset your password{{end}} +{{define "reset_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/signin_change_body.html b/api/templates/signin_change_body.html index 5b96df944..af8577f0f 100644 --- a/api/templates/signin_change_body.html +++ b/api/templates/signin_change_body.html @@ -17,8 +17,8 @@
-

You requested a password reset

-

To change your password, click "Reset Password" below.
If you did not mean to reset your password, please ignore this email and your password will remain the same.

+

{{.Props.Title}}

+

{{.Html.Info}}

- Reset Password + {{.Props.Button}}

diff --git a/api/templates/signin_change_subject.html b/api/templates/signin_change_subject.html index b1d644a28..606dc4df3 100644 --- a/api/templates/signin_change_subject.html +++ b/api/templates/signin_change_subject.html @@ -1 +1 @@ -{{define "signin_change_subject"}}You updated your sign-in method for {{.Props.TeamDisplayName}} on {{ .ClientCfg.SiteName }}{{end}} +{{define "signin_change_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/signup_team_body.html b/api/templates/signup_team_body.html index 2f384ac43..683a9891e 100644 --- a/api/templates/signup_team_body.html +++ b/api/templates/signup_team_body.html @@ -17,11 +17,11 @@
-

You updated your sign-in method

-

You updated your sign-in method for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} to {{.Props.Method}}.
If this change wasn't initiated by you, please contact your system administrator.

+

{{.Props.Title}}

+

{{.Html.Info}}

diff --git a/api/templates/signup_team_subject.html b/api/templates/signup_team_subject.html index 4fc5b3d72..413a5c8c1 100644 --- a/api/templates/signup_team_subject.html +++ b/api/templates/signup_team_subject.html @@ -1 +1 @@ -{{define "signup_team_subject"}}{{ .ClientCfg.SiteName }} Team Setup{{end}} \ No newline at end of file +{{define "signup_team_subject"}}{{.Props.Subject}}{{end}} \ No newline at end of file diff --git a/api/templates/verify_body.html b/api/templates/verify_body.html index c42b2a372..2b0d25f94 100644 --- a/api/templates/verify_body.html +++ b/api/templates/verify_body.html @@ -17,10 +17,10 @@
-

Thanks for creating a team!

+

{{.Props.Title}}

- Set up your team + {{.Props.Button}}

- {{ .ClientCfg.SiteName }} is one place for all your team communication, searchable and available anywhere.
You'll get more out of {{ .ClientCfg.SiteName }} when your team is in constant communication--let's get them on board.

+ {{.Html.Info}}

diff --git a/api/templates/verify_subject.html b/api/templates/verify_subject.html index 9a3a11282..ad7fc2aaa 100644 --- a/api/templates/verify_subject.html +++ b/api/templates/verify_subject.html @@ -1 +1 @@ -{{define "verify_subject"}}[{{ .Props.TeamDisplayName }} {{ .ClientCfg.SiteName }}] Email Verification{{end}} +{{define "verify_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/welcome_body.html b/api/templates/welcome_body.html index 71d838b08..b5ca9beb3 100644 --- a/api/templates/welcome_body.html +++ b/api/templates/welcome_body.html @@ -18,19 +18,19 @@ {{if .Props.VerifyUrl }} {{end}}
-

You've joined the {{ .Props.TeamDisplayName }} team

-

Please verify your email address by clicking below.

+

{{.Props.Title}}

+

{{.Props.Info}}

- Verify Email + {{.Props.Button}}

-

You've joined the {{ .Props.TeamDisplayName }} team

-

Please verify your email address by clicking below.

+

{{.Props.Title}}

+

{{.Props.Info}}

- Verify Email + {{.Props.Button}}

-

You can sign-in to your new team from the web address:

+

{{.Props.Info2}}

{{.Props.TeamURL}} -

Mattermost lets you share messages and files from your PC or phone, with instant search and archiving.

+

{{.Props.Info3}}

diff --git a/api/templates/welcome_subject.html b/api/templates/welcome_subject.html index c3b70ef20..95189b900 100644 --- a/api/templates/welcome_subject.html +++ b/api/templates/welcome_subject.html @@ -1 +1 @@ -{{define "welcome_subject"}}You joined {{ .Props.TeamDisplayName }}{{end}} +{{define "welcome_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/user.go b/api/user.go index 76ed66112..473f0da54 100644 --- a/api/user.go +++ b/api/user.go @@ -17,6 +17,7 @@ import ( "github.com/mattermost/platform/utils" "github.com/mssola/user_agent" "hash/fnv" + "html/template" "image" "image/color" "image/draw" @@ -134,7 +135,7 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) { } if sendWelcomeEmail { - sendWelcomeEmailAndForget(ruser.Id, ruser.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team), ruser.EmailVerified) + sendWelcomeEmailAndForget(c, ruser.Id, ruser.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team), ruser.EmailVerified) } w.Write([]byte(ruser.ToJson())) @@ -308,13 +309,19 @@ func CreateOAuthUser(c *Context, w http.ResponseWriter, r *http.Request, service return ruser } -func sendWelcomeEmailAndForget(userId, email, teamName, teamDisplayName, siteURL, teamURL string, verified bool) { +func sendWelcomeEmailAndForget(c *Context, userId, email, teamName, teamDisplayName, siteURL, teamURL string, verified bool) { go func() { - subjectPage := NewServerTemplatePage("welcome_subject") - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("welcome_body") + subjectPage := NewServerTemplatePage("welcome_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.welcome_subject", map[string]interface{}{"TeamDisplayName": teamDisplayName}) + + bodyPage := NewServerTemplatePage("welcome_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL + bodyPage.Props["Title"] = c.T("api.templates.welcome_body.title", map[string]interface{}{"TeamDisplayName": teamDisplayName}) + bodyPage.Props["Info"] = c.T("api.templates.welcome_body.info") + bodyPage.Props["Button"] = c.T("api.templates.welcome_body.button") + bodyPage.Props["Info2"] = c.T("api.templates.welcome_body.info2") + bodyPage.Props["Info3"] = c.T("api.templates.welcome_body.info3") bodyPage.Props["TeamURL"] = teamURL if !verified { @@ -367,18 +374,21 @@ func addDirectChannelsAndForget(user *model.User) { }() } -func SendVerifyEmailAndForget(userId, userEmail, teamName, teamDisplayName, siteURL, teamURL string) { +func SendVerifyEmailAndForget(c *Context, userId, userEmail, teamName, teamDisplayName, siteURL, teamURL string) { go func() { link := fmt.Sprintf("%s/verify_email?uid=%s&hid=%s&teamname=%s&email=%s", siteURL, userId, model.HashPassword(userId), teamName, userEmail) - subjectPage := NewServerTemplatePage("verify_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("verify_body") + subjectPage := NewServerTemplatePage("verify_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.verify_subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("verify_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName + bodyPage.Props["Title"] = c.T("api.templates.verify_body.title", map[string]interface{}{"TeamDisplayName": teamDisplayName}) + bodyPage.Props["Info"] = c.T("api.templates.verify_body.info") bodyPage.Props["VerifyUrl"] = link + bodyPage.Props["Button"] = c.T("api.templates.verify_body.button") if err := utils.SendMail(userEmail, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_verify_email_and_forget.failed.error"), err) @@ -1141,10 +1151,10 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) { l4g.Error(tresult.Err.Message) } else { team := tresult.Data.(*model.Team) - sendEmailChangeEmailAndForget(rusers[1].Email, rusers[0].Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL()) + sendEmailChangeEmailAndForget(c, rusers[1].Email, rusers[0].Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL()) if utils.Cfg.EmailSettings.RequireEmailVerification { - SendEmailChangeVerifyEmailAndForget(rusers[0].Id, rusers[0].Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) + SendEmailChangeVerifyEmailAndForget(c, rusers[0].Id, rusers[0].Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) } } } @@ -1224,7 +1234,7 @@ func updatePassword(c *Context, w http.ResponseWriter, r *http.Request) { l4g.Error(tresult.Err.Message) } else { team := tresult.Data.(*model.Team) - sendPasswordChangeEmailAndForget(user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), c.T("api.user.update_password.menu")) + sendPasswordChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), c.T("api.user.update_password.menu")) } data := make(map[string]string) @@ -1526,11 +1536,15 @@ func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) { link := fmt.Sprintf("%s/reset_password?d=%s&h=%s", c.GetTeamURLFromTeam(team), url.QueryEscape(data), url.QueryEscape(hash)) - subjectPage := NewServerTemplatePage("reset_subject") - subjectPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage := NewServerTemplatePage("reset_body") + subjectPage := NewServerTemplatePage("reset_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.reset_subject") + + bodyPage := NewServerTemplatePage("reset_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() + bodyPage.Props["Title"] = c.T("api.templates.reset_body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.reset_body.info")) bodyPage.Props["ResetUrl"] = link + bodyPage.Props["Button"] = c.T("api.templates.reset_body.button") if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { c.Err = model.NewLocAppError("sendPasswordReset", "api.user.send_password_reset.send.app_error", nil, "err="+err.Message) @@ -1632,23 +1646,24 @@ func resetPassword(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAuditWithUserId(userId, "success") } - sendPasswordChangeEmailAndForget(user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), "using a reset password link") + sendPasswordChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), c.T("api.user.reset_password.method")) props["new_password"] = "" w.Write([]byte(model.MapToJson(props))) } -func sendPasswordChangeEmailAndForget(email, teamDisplayName, teamURL, siteURL, method string) { +func sendPasswordChangeEmailAndForget(c *Context, email, teamDisplayName, teamURL, siteURL, method string) { go func() { - subjectPage := NewServerTemplatePage("password_change_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("password_change_body") + subjectPage := NewServerTemplatePage("password_change_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.password_change_subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("password_change_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage.Props["TeamURL"] = teamURL - bodyPage.Props["Method"] = method + bodyPage.Props["Title"] = c.T("api.templates.password_change_body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.password_change_body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "TeamURL": teamURL, "Method": method})) if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_password_change_email_and_forget.error"), err) @@ -1657,17 +1672,18 @@ func sendPasswordChangeEmailAndForget(email, teamDisplayName, teamURL, siteURL, }() } -func sendEmailChangeEmailAndForget(oldEmail, newEmail, teamDisplayName, teamURL, siteURL string) { +func sendEmailChangeEmailAndForget(c *Context, oldEmail, newEmail, teamDisplayName, teamURL, siteURL string) { go func() { - subjectPage := NewServerTemplatePage("email_change_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("email_change_body") + subjectPage := NewServerTemplatePage("email_change_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.email_change_body", + map[string]interface{}{"TeamDisplayName": teamDisplayName}) + + bodyPage := NewServerTemplatePage("email_change_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage.Props["TeamURL"] = teamURL - bodyPage.Props["NewEmail"] = newEmail + bodyPage.Props["Title"] = c.T("api.templates.email_change_body.title") + bodyPage.Props["Info"] = c.T("api.templates.email_change_body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "NewEmail": newEmail}) if err := utils.SendMail(oldEmail, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_email_change_email_and_forget.error"), err) @@ -1676,18 +1692,22 @@ func sendEmailChangeEmailAndForget(oldEmail, newEmail, teamDisplayName, teamURL, }() } -func SendEmailChangeVerifyEmailAndForget(userId, newUserEmail, teamName, teamDisplayName, siteURL, teamURL string) { +func SendEmailChangeVerifyEmailAndForget(c *Context, userId, newUserEmail, teamName, teamDisplayName, siteURL, teamURL string) { go func() { link := fmt.Sprintf("%s/verify_email?uid=%s&hid=%s&teamname=%s&email=%s", siteURL, userId, model.HashPassword(userId), teamName, newUserEmail) - subjectPage := NewServerTemplatePage("email_change_verify_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("email_change_verify_body") + subjectPage := NewServerTemplatePage("email_change_verify_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.email_change_verify_subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName}) + + bodyPage := NewServerTemplatePage("email_change_verify_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName + bodyPage.Props["Title"] = c.T("api.templates.email_change_verify_body.title") + bodyPage.Props["Info"] = c.T("api.templates.email_change_verify_body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName}) bodyPage.Props["VerifyUrl"] = link + bodyPage.Props["VerifyButton"] = c.T("api.templates.email_change_verify_body.button") if err := utils.SendMail(newUserEmail, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_email_change_verify_email_and_forget.error"), err) @@ -2028,7 +2048,7 @@ func CompleteSwitchWithOAuth(c *Context, w http.ResponseWriter, r *http.Request, return } - sendSignInChangeEmailAndForget(user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), strings.Title(service)+" SSO") + sendSignInChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), strings.Title(service)+" SSO") } func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) { @@ -2085,7 +2105,7 @@ func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) { return } - sendSignInChangeEmailAndForget(user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), "email and password") + sendSignInChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), c.T("api.templates.signin_change_email.body.method_email")) RevokeAllSession(c, c.Session.UserId) if c.Err != nil { @@ -2099,17 +2119,18 @@ func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(m))) } -func sendSignInChangeEmailAndForget(email, teamDisplayName, teamURL, siteURL, method string) { +func sendSignInChangeEmailAndForget(c *Context, email, teamDisplayName, teamURL, siteURL, method string) { go func() { - subjectPage := NewServerTemplatePage("signin_change_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("signin_change_body") + subjectPage := NewServerTemplatePage("signin_change_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.singin_change_email.subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("signin_change_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage.Props["TeamURL"] = teamURL - bodyPage.Props["Method"] = method + bodyPage.Props["Title"] = c.T("api.templates.signin_change_email.body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.singin_change_email.body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "TeamURL": teamURL, "Method": method})) if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_sign_in_change_email_and_forget.error"), err) -- cgit v1.2.3-1-g7c22