merging
Этот коммит содержится в:
12
api/admin.go
12
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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
12
api/api.go
12
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)
|
||||
}
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
|
||||
@@ -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.NewLocAppError("addLicense", "api.license.add_license.expired.app_error", nil, "")
|
||||
|
||||
35
api/post.go
35
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 {
|
||||
|
||||
48
api/team.go
48
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
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You updated your email</h2>
|
||||
<p>You email address for {{.Props.TeamDisplayName}} has been changed to {{.Props.NewEmail}}.<br>If you did not make this change, please contact the system administrator.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Props.Info}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You updated your email</h2>
|
||||
<p>To finish updating your email address for {{.Props.TeamDisplayName}}, please click the link below to confirm this is the right address.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Props.Info}}</p>
|
||||
<p style="margin: 20px 0 15px">
|
||||
<a href="{{.Props.VerifyUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Verify Email</a>
|
||||
<a href="{{.Props.VerifyUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.VerifyButton}}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 Mattermost, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
To change your notification preferences, log in to your team site and go to Account Settings > Notifications.
|
||||
{{.Props.Footer}}
|
||||
</p>
|
||||
</td>
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
{{define "email_info"}}
|
||||
|
||||
<td style="color: #999; padding-top: 20px; line-height: 25px; font-size: 13px;">
|
||||
Any questions at all, mail us any time: <a href="mailto:{{.ClientCfg.FeedbackEmail}}" style="text-decoration: none; color:#2389D7;">{{.ClientCfg.FeedbackEmail}}</a>.<br>
|
||||
Best wishes,<br>
|
||||
The {{.ClientCfg.SiteName}} Team<br>
|
||||
{{.Html.EmailInfo}}
|
||||
</td>
|
||||
|
||||
{{end}}
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
<div class="container-fluid">
|
||||
<div class="error__container">
|
||||
<div class="error__icon"><i class="fa fa-exclamation-triangle"></i></div>
|
||||
<h2>{{ .ClientCfg.SiteName }} needs your help:</h2>
|
||||
<h2>{{.Props.Title}}</h2>
|
||||
<p>{{ .Props.Message }}</p>
|
||||
<a href="{{.Props.SiteURL}}">Go back to team site</a>
|
||||
<a href="{{.Props.SiteURL}}">{{.Props.Link}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">Finding teams</h2>
|
||||
<p>{{ if .Props }}
|
||||
Your request to find teams associated with your email found the following:<br>
|
||||
{{range $index, $element := .Props}}
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{ if .Extra }}
|
||||
{{.Props.Found}}<br>
|
||||
{{range $index, $element := .Extra}}
|
||||
<a href="{{ $element }}" style="text-decoration: none; color:#2389D7;">{{ $index }}</a><br>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
We could not find any teams for the given email.
|
||||
{{.Props.NotFound}}
|
||||
{{ end }}
|
||||
</p>
|
||||
</td>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "find_teams_subject"}}Your {{ .ClientCfg.SiteName }} Teams{{end}}
|
||||
{{define "find_teams_subject"}}{{.Props.Subject}}{{end}}
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You've been invited</h2>
|
||||
<p>The team {{.Props.SenderStatus}} <strong>{{.Props.SenderName}}</strong>, has invited you to join <strong>{{.Props.TeamDisplayName}}</strong>.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Html.Info}}</p>
|
||||
<p style="margin: 30px 0 15px">
|
||||
<a href="{{.Props.Link}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Join Team</a>
|
||||
<a href="{{.Props.Link}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.Button}}</a>
|
||||
</p>
|
||||
<br/>
|
||||
<p>Mattermost lets you share messages and files from your PC or phone, with instant search and archiving. After you’ve joined <strong>{{.Props.TeamDisplayName}}</strong>, you can sign-in to your new team and access these features anytime from the web address:<br/><br/><a href="{{.Props.TeamURL}}">{{.Props.TeamURL}}</a></p>
|
||||
<p>{{.Html.ExtraInfo}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "invite_subject"}}{{ .Props.SenderName }} invited you to join {{ .Props.TeamDisplayName }} Team on {{.ClientCfg.SiteName}}{{end}}
|
||||
{{define "invite_subject"}}{{.Props.Subject}}{{end}}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You updated your password</h2>
|
||||
<p>Your password has been updated for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} by {{.Props.Method}}.<br>If this change wasn't initiated by you, please contact your system administrator.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Html.Info}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You were mentioned</h2>
|
||||
<p>CHANNEL: {{.Props.ChannelName}}<br>{{.Props.SenderName}} - {{.Props.Hour}}:{{.Props.Minute}} {{.Props.TimeZone}}, {{.Props.Month}} {{.Props.Day}}<br><pre style="text-align:left;font-family: 'Lato', sans-serif; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;">{{.Props.PostMessage}}</pre></p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.BodyText}}</h2>
|
||||
<p>{{.Html.Info}}<br><pre style="text-align:left;font-family: 'Lato', sans-serif; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;">{{.Props.PostMessage}}</pre></p>
|
||||
<p style="margin: 20px 0 15px">
|
||||
<a href="{{.Props.TeamLink}}" style="background: #2389D7; display: inline-block; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 170px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Go To Channel</a>
|
||||
<a href="{{.Props.TeamLink}}" style="background: #2389D7; display: inline-block; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 170px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.Button}}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You requested a password reset</h2>
|
||||
<p>To change your password, click "Reset Password" below.<br>If you did not mean to reset your password, please ignore this email and your password will remain the same.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Html.Info}}</p>
|
||||
<p style="margin: 20px 0 15px">
|
||||
<a href="{{.Props.ResetUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Reset Password</a>
|
||||
<a href="{{.Props.ResetUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.Button}}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "reset_subject"}}Reset your password{{end}}
|
||||
{{define "reset_subject"}}{{.Props.Subject}}{{end}}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You updated your sign-in method</h2>
|
||||
<p>You updated your sign-in method for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} to {{.Props.Method}}.<br>If this change wasn't initiated by you, please contact your system administrator.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Html.Info}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">Thanks for creating a team!</h2>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p style="margin: 20px 0 25px">
|
||||
<a href="{{.Props.Link}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Set up your team</a>
|
||||
<a href="{{.Props.Link}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.Button}}</a>
|
||||
</p>
|
||||
{{ .ClientCfg.SiteName }} is one place for all your team communication, searchable and available anywhere.<br>You'll get more out of {{ .ClientCfg.SiteName }} when your team is in constant communication--let's get them on board.<br></p>
|
||||
{{.Html.Info}}<br></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "signup_team_subject"}}{{ .ClientCfg.SiteName }} Team Setup{{end}}
|
||||
{{define "signup_team_subject"}}{{.Props.Subject}}{{end}}
|
||||
@@ -17,10 +17,10 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You've joined the {{ .Props.TeamDisplayName }} team</h2>
|
||||
<p>Please verify your email address by clicking below.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Props.Info}}</p>
|
||||
<p style="margin: 20px 0 15px">
|
||||
<a href="{{.Props.VerifyUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Verify Email</a>
|
||||
<a href="{{.Props.VerifyUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.Button}}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "verify_subject"}}[{{ .Props.TeamDisplayName }} {{ .ClientCfg.SiteName }}] Email Verification{{end}}
|
||||
{{define "verify_subject"}}{{.Props.Subject}}{{end}}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
{{if .Props.VerifyUrl }}
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You've joined the {{ .Props.TeamDisplayName }} team</h2>
|
||||
<p>Please verify your email address by clicking below.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">{{.Props.Title}}</h2>
|
||||
<p>{{.Props.Info}}</p>
|
||||
<p style="margin: 20px 0 15px">
|
||||
<a href="{{.Props.VerifyUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Verify Email</a>
|
||||
<a href="{{.Props.VerifyUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">{{.Props.Button}}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 25px; line-height: 1.5;">You can sign-in to your new team from the web address:</h2>
|
||||
<h2 style="font-weight: normal; margin-top: 25px; line-height: 1.5;">{{.Props.Info2}}</h2>
|
||||
<a href="{{.Props.TeamURL}}">{{.Props.TeamURL}}</a>
|
||||
<p>Mattermost lets you share messages and files from your PC or phone, with instant search and archiving.</p>
|
||||
<p>{{.Props.Info3}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "welcome_subject"}}You joined {{ .Props.TeamDisplayName }}{{end}}
|
||||
{{define "welcome_subject"}}{{.Props.Subject}}{{end}}
|
||||
|
||||
121
api/user.go
121
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)
|
||||
@@ -1530,11 +1540,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)
|
||||
@@ -1636,23 +1650,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)
|
||||
@@ -1661,17 +1676,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)
|
||||
@@ -1680,18 +1696,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)
|
||||
@@ -2032,7 +2052,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) {
|
||||
@@ -2089,7 +2109,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 {
|
||||
@@ -2103,17 +2123,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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -82,7 +82,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
|
||||
}
|
||||
@@ -111,7 +111,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
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,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
|
||||
}
|
||||
@@ -151,7 +151,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
|
||||
}
|
||||
@@ -199,7 +199,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
|
||||
}
|
||||
|
||||
@@ -215,7 +215,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
|
||||
}
|
||||
@@ -239,7 +239,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
|
||||
}
|
||||
@@ -268,7 +268,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
|
||||
}
|
||||
}
|
||||
@@ -284,7 +284,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
|
||||
}
|
||||
@@ -316,7 +316,7 @@ func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request)
|
||||
|
||||
if c.Session.TeamId != hook.TeamId && 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
|
||||
}
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user