summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Kraft <martinkraft@gmail.com>2018-05-28 10:35:27 -0400
committerMartin Kraft <martinkraft@gmail.com>2018-05-28 10:35:27 -0400
commitc180cdbd1cba584c6e74cae7042de2290b51feb6 (patch)
tree19002d12a212d0bcc0e09d31410df548b93d77ef
parent7225abddeefb569f1f2da739211d7797b63814a2 (diff)
parentc37d153ffb276e501660133de836a61eec25e544 (diff)
downloadchat-c180cdbd1cba584c6e74cae7042de2290b51feb6.tar.gz
chat-c180cdbd1cba584c6e74cae7042de2290b51feb6.tar.bz2
chat-c180cdbd1cba584c6e74cae7042de2290b51feb6.zip
Merge remote-tracking branch 'origin/master' into advanced-permissions-phase-2
-rw-r--r--api4/channel_test.go31
-rw-r--r--api4/user.go13
-rw-r--r--api4/user_test.go15
-rw-r--r--app/channel.go6
-rw-r--r--app/email.go22
-rw-r--r--config/default.json1
-rw-r--r--i18n/en.json20
-rw-r--r--model/config.go5
-rw-r--r--model/websocket_message.go3
-rw-r--r--templates/deactivate_body.html41
-rw-r--r--utils/config.go2
11 files changed, 157 insertions, 2 deletions
diff --git a/api4/channel_test.go b/api4/channel_test.go
index 8fd68fc08..7b677f77f 100644
--- a/api4/channel_test.go
+++ b/api4/channel_test.go
@@ -11,6 +11,7 @@ import (
"strconv"
"strings"
"testing"
+ "time"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
@@ -933,12 +934,42 @@ func TestConvertChannelToPrivate(t *testing.T) {
t.Fatal("should not return a channel")
}
+ WebSocketClient, err := th.CreateWebSocketClient()
+ if err != nil {
+ t.Fatal(err)
+ }
+ WebSocketClient.Listen()
+
publicChannel2 := th.CreatePublicChannel()
rchannel, resp = th.SystemAdminClient.ConvertChannelToPrivate(publicChannel2.Id)
CheckOKStatus(t, resp)
if rchannel.Type != model.CHANNEL_PRIVATE {
t.Fatal("channel should be converted from public to private")
}
+
+ stop := make(chan bool)
+ eventHit := false
+
+ go func() {
+ for {
+ select {
+ case resp := <-WebSocketClient.EventChannel:
+ if resp.Event == model.WEBSOCKET_EVENT_CHANNEL_CONVERTED && resp.Data["channel_id"].(string) == publicChannel2.Id {
+ eventHit = true
+ }
+ case <-stop:
+ return
+ }
+ }
+ }()
+
+ time.Sleep(400 * time.Millisecond)
+
+ stop <- true
+
+ if !eventHit {
+ t.Fatal("did not receive channel_converted event")
+ }
}
func TestRestoreChannel(t *testing.T) {
diff --git a/api4/user.go b/api4/user.go
index 2a539a551..ea90d2127 100644
--- a/api4/user.go
+++ b/api4/user.go
@@ -713,6 +713,12 @@ func updateUserActive(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
+ // if EnableUserDeactivation flag is disabled the user cannot deactivate himself.
+ if isSelfDeactive && !*c.App.GetConfig().TeamSettings.EnableUserDeactivation {
+ c.Err = model.NewAppError("updateUserActive", "api.user.update_active.not_enable.app_error", nil, "userId="+c.Params.UserId, http.StatusUnauthorized)
+ return
+ }
+
var user *model.User
var err *model.AppError
@@ -725,6 +731,13 @@ func updateUserActive(c *Context, w http.ResponseWriter, r *http.Request) {
c.Err = err
} else {
c.LogAuditWithUserId(user.Id, fmt.Sprintf("active=%v", active))
+ if isSelfDeactive {
+ c.App.Go(func() {
+ if err = c.App.SendDeactivateAccountEmail(user.Email, user.Locale, c.App.GetSiteURL()); err != nil {
+ mlog.Error(err.Error())
+ }
+ })
+ }
ReturnStatusOK(w)
}
}
diff --git a/api4/user_test.go b/api4/user_test.go
index 4851f139e..593208c92 100644
--- a/api4/user_test.go
+++ b/api4/user_test.go
@@ -1198,6 +1198,12 @@ func TestUpdateUserActive(t *testing.T) {
SystemAdminClient := th.SystemAdminClient
user := th.BasicUser
+ EnableUserDeactivation := th.App.Config().TeamSettings.EnableUserDeactivation
+ defer func() {
+ th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.EnableUserDeactivation = EnableUserDeactivation })
+ }()
+
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserDeactivation = true })
pass, resp := Client.UpdateUserActive(user.Id, false)
CheckNoError(t, resp)
@@ -1205,6 +1211,15 @@ func TestUpdateUserActive(t *testing.T) {
t.Fatal("should have returned true")
}
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserDeactivation = false })
+ pass, resp = Client.UpdateUserActive(user.Id, false)
+ CheckUnauthorizedStatus(t, resp)
+
+ if pass {
+ t.Fatal("should have returned false")
+ }
+
+ th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.EnableUserDeactivation = true })
pass, resp = Client.UpdateUserActive(user.Id, false)
CheckUnauthorizedStatus(t, resp)
diff --git a/app/channel.go b/app/channel.go
index 4b606ac27..55a5008d4 100644
--- a/app/channel.go
+++ b/app/channel.go
@@ -386,6 +386,12 @@ func (a *App) UpdateChannelPrivacy(oldChannel *model.Channel, user *model.User)
return channel, err
}
+ a.InvalidateCacheForChannel(channel)
+
+ messageWs := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_CONVERTED, channel.TeamId, "", "", nil)
+ messageWs.Add("channel_id", channel.Id)
+ a.Publish(messageWs)
+
return channel, nil
}
}
diff --git a/app/email.go b/app/email.go
index aa05cefdb..206c48aaa 100644
--- a/app/email.go
+++ b/app/email.go
@@ -322,6 +322,28 @@ func (a *App) NewEmailTemplate(name, locale string) *utils.HTMLTemplate {
return t
}
+func (a *App) SendDeactivateAccountEmail(email string, locale, siteURL string) *model.AppError {
+ T := utils.GetUserTranslations(locale)
+
+ rawUrl, _ := url.Parse(siteURL)
+
+ subject := T("api.templates.deactivate_subject",
+ map[string]interface{}{"SiteName": a.ClientConfig()["SiteName"],
+ "ServerURL": rawUrl.Host})
+
+ bodyPage := a.NewEmailTemplate("deactivate_body", locale)
+ bodyPage.Props["SiteURL"] = siteURL
+ bodyPage.Props["Title"] = T("api.templates.deactivate_body.title", map[string]interface{}{"ServerURL": rawUrl.Host})
+ bodyPage.Html["Info"] = utils.TranslateAsHtml(T, "api.templates.deactivate_body.info",
+ map[string]interface{}{"SiteURL": siteURL})
+
+ if err := a.SendMail(email, subject, bodyPage.Render()); err != nil {
+ return model.NewAppError("SendDeactivateEmail", "api.user.send_deactivate_email_and_forget.failed.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ return nil
+}
+
func (a *App) SendMail(to, subject, htmlBody string) *model.AppError {
license := a.License()
return utils.SendMailUsingConfig(to, subject, htmlBody, a.Config(), license != nil && *license.Features.Compliance)
diff --git a/config/default.json b/config/default.json
index 2d6265dcc..3548339d0 100644
--- a/config/default.json
+++ b/config/default.json
@@ -71,6 +71,7 @@
"EnableTeamCreation": true,
"EnableUserCreation": true,
"EnableOpenServer": false,
+ "EnableUserDeactivation": false,
"RestrictCreationToDomains": "",
"EnableCustomBrand": false,
"CustomBrandText": "",
diff --git a/i18n/en.json b/i18n/en.json
index 37a199582..d631e7e1d 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -2823,6 +2823,22 @@
"translation": "[{{ .SiteName }}] You joined {{ .ServerURL }}"
},
{
+ "id": "api.templates.deactivate_subject",
+ "translation": "[{{ .SiteName }}] Your account at {{ .ServerURL }} has been deactivated"
+ },
+ {
+ "id": "api.templates.deactivate_body.title",
+ "translation": "Your account has been deactivated at {{ .ServerURL }}"
+ },
+ {
+ "id": "api.templates.deactivate_body.info",
+ "translation": "You deactivated your account on {{ .SiteURL }}.<br>If this change wasn't initiated by you or you want to reactivate your account, contact your system administrator."
+ },
+ {
+ "id": "api.user.send_deactivate_email_and_forget.failed.error",
+ "translation": "Failed to send the deactivate account email successfully"
+ },
+ {
"id": "api.user.activate_mfa.email_and_ldap_only.app_error",
"translation": "MFA is not available for this account type"
},
@@ -3147,6 +3163,10 @@
"translation": "You do not have the appropriate permissions"
},
{
+ "id": "api.user.update_active.not_enable.app_error",
+ "translation": "You cannot deactivate yourself because this feature is not enabled. Please contact your System Administrator."
+ },
+ {
"id": "api.user.update_mfa.not_available.app_error",
"translation": "MFA not configured or available on this server"
},
diff --git a/model/config.go b/model/config.go
index deaae6db8..ba3a02d33 100644
--- a/model/config.go
+++ b/model/config.go
@@ -1002,6 +1002,7 @@ type TeamSettings struct {
EnableTeamCreation *bool
EnableUserCreation *bool
EnableOpenServer *bool
+ EnableUserDeactivation *bool
RestrictCreationToDomains string
EnableCustomBrand *bool
CustomBrandText *string
@@ -1036,6 +1037,10 @@ func (s *TeamSettings) SetDefaults() {
s.EnableCustomBrand = NewBool(false)
}
+ if s.EnableUserDeactivation == nil {
+ s.EnableUserDeactivation = NewBool(false)
+ }
+
if s.CustomBrandText == nil {
s.CustomBrandText = NewString(TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT)
}
diff --git a/model/websocket_message.go b/model/websocket_message.go
index 071975d6c..31b16d1a7 100644
--- a/model/websocket_message.go
+++ b/model/websocket_message.go
@@ -14,8 +14,9 @@ const (
WEBSOCKET_EVENT_POSTED = "posted"
WEBSOCKET_EVENT_POST_EDITED = "post_edited"
WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
- WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
+ WEBSOCKET_EVENT_CHANNEL_CONVERTED = "channel_converted"
WEBSOCKET_EVENT_CHANNEL_CREATED = "channel_created"
+ WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
WEBSOCKET_EVENT_CHANNEL_UPDATED = "channel_updated"
WEBSOCKET_EVENT_CHANNEL_MEMBER_UPDATED = "channel_member_updated"
WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
diff --git a/templates/deactivate_body.html b/templates/deactivate_body.html
new file mode 100644
index 000000000..45a2f42af
--- /dev/null
+++ b/templates/deactivate_body.html
@@ -0,0 +1,41 @@
+{{define "deactivate_body"}}
+
+<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="margin-top: 20px; line-height: 1.7; color: #555;">
+ <tr>
+ <td>
+ <table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 660px; font-family: Helvetica, Arial, sans-serif; font-size: 14px; background: #FFF;">
+ <tr>
+ <td style="border: 1px solid #ddd;">
+ <table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
+ <tr>
+ <td style="padding: 20px 20px 10px; text-align:left;">
+ <img src="{{.Props.SiteURL}}/static/images/logo-email.png" width="130px" style="opacity: 0.5" alt="">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <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;">{{.Props.Title}}</h2>
+ <p>{{.Html.Info}}</p>
+ </td>
+ </tr>
+ <tr>
+ {{template "email_info" . }}
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ {{template "email_footer" . }}
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+
+{{end}}
diff --git a/utils/config.go b/utils/config.go
index 0da1d0abe..c85da7067 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -448,7 +448,7 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/")
props["SiteName"] = c.TeamSettings.SiteName
props["EnableTeamCreation"] = strconv.FormatBool(*c.TeamSettings.EnableTeamCreation)
- props["EnableUserCreation"] = strconv.FormatBool(*c.TeamSettings.EnableUserCreation)
+ props["EnableUserDeactivation"] = strconv.FormatBool(*c.TeamSettings.EnableUserDeactivation)
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
props["RestrictTeamInvite"] = *c.TeamSettings.RestrictTeamInvite