Unverified Commit c3e9c414 authored by Carlos Tadeu Panato Junior's avatar Carlos Tadeu Panato Junior Committed by GitHub

[MM-1915] Add Deactivate Account - server side (#8699)

parent b6d5cc4f
......@@ -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)
}
}
......
......@@ -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)
......
......@@ -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)
......
......@@ -71,6 +71,7 @@
"EnableTeamCreation": true,
"EnableUserCreation": true,
"EnableOpenServer": false,
"EnableUserDeactivation": false,
"RestrictCreationToDomains": "",
"EnableCustomBrand": false,
"CustomBrandText": "",
......
......@@ -2750,6 +2750,22 @@
"id": "api.templates.welcome_subject",
"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"
......@@ -3074,6 +3090,10 @@
"id": "api.user.update_active.permissions.app_error",
"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"
......
......@@ -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)
}
......
{{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}}
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment