Esempio n. 1
0
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {

	m := model.MapFromJson(r.Body)
	email := strings.ToLower(strings.TrimSpace(m["email"]))

	if len(email) == 0 {
		c.SetInvalidParam("signupTeam", "email")
		return
	}

	subjectPage := NewServerTemplatePage("signup_team_subject", c.GetSiteURL())
	bodyPage := NewServerTemplatePage("signup_team_body", c.GetSiteURL())
	bodyPage.Props["TourUrl"] = utils.Cfg.TeamSettings.TourLink

	props := make(map[string]string)
	props["email"] = email
	props["time"] = fmt.Sprintf("%v", model.GetMillis())

	data := model.MapToJson(props)
	hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))

	bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_team_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))

	if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
		c.Err = err
		return
	}

	if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV || utils.Cfg.EmailSettings.ByPassEmail {
		m["follow_link"] = bodyPage.Props["Link"]
	}

	w.Header().Set("Access-Control-Allow-Origin", " *")
	w.Write([]byte(model.MapToJson(m)))
}
Esempio n. 2
0
func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) {

	m := model.MapFromJson(r.Body)

	email := strings.ToLower(strings.TrimSpace(m["email"]))

	if email == "" {
		c.SetInvalidParam("findTeam", "email")
		return
	}

	subjectPage := NewServerTemplatePage("find_teams_subject")
	subjectPage.Props["SiteURL"] = c.GetSiteURL()
	bodyPage := NewServerTemplatePage("find_teams_body")
	bodyPage.Props["SiteURL"] = c.GetSiteURL()

	if result := <-Srv.Store.Team().GetTeamsForEmail(email); result.Err != nil {
		c.Err = result.Err
	} else {
		teams := result.Data.([]*model.Team)

		// the template expects Props to be a map with team names as the keys and the team url as the value
		props := make(map[string]string)
		for _, team := range teams {
			props[team.Name] = c.GetTeamURLFromTeam(team)
		}
		bodyPage.Props = props

		if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("An error occured while sending an email in emailTeams err=%v", err)
		}

		w.Write([]byte(model.MapToJson(m)))
	}
}
Esempio n. 3
0
func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) {
	props := model.MapFromJson(r.Body)

	email := props["email"]
	if len(email) == 0 {
		c.SetInvalidParam("sendPasswordReset", "email")
		return
	}

	name := props["name"]
	if len(name) == 0 {
		c.SetInvalidParam("sendPasswordReset", "name")
		return
	}

	var team *model.Team
	if result := <-Srv.Store.Team().GetByName(name); result.Err != nil {
		c.Err = result.Err
		return
	} else {
		team = result.Data.(*model.Team)
	}

	var user *model.User
	if result := <-Srv.Store.User().GetByEmail(team.Id, email); result.Err != nil {
		c.Err = model.NewAppError("sendPasswordReset", "We couldn’t find an account with that address.", "email="+email+" team_id="+team.Id)
		return
	} else {
		user = result.Data.(*model.User)
	}

	if len(user.AuthData) != 0 {
		c.Err = model.NewAppError("sendPasswordReset", "Cannot reset password for SSO accounts", "userId="+user.Id+", teamId="+team.Id)
		return
	}

	newProps := make(map[string]string)
	newProps["user_id"] = user.Id
	newProps["time"] = fmt.Sprintf("%v", model.GetMillis())

	data := model.MapToJson(newProps)
	hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.PasswordResetSalt))

	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")
	bodyPage.Props["SiteURL"] = c.GetSiteURL()
	bodyPage.Props["ResetUrl"] = link

	if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
		c.Err = model.NewAppError("sendPasswordReset", "Failed to send password reset email successfully", "err="+err.Message)
		return
	}

	c.LogAuditWithUserId(user.Id, "sent="+email)

	w.Write([]byte(model.MapToJson(props)))
}
Esempio n. 4
0
func InviteMembers(team *model.Team, user *model.User, invites []string) {
	for _, invite := range invites {
		if len(invite) > 0 {
			teamUrl := ""
			if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV {
				teamUrl = "http://localhost:8065"
			} else if utils.Cfg.ServiceSettings.UseSSL {
				teamUrl = fmt.Sprintf("https://%v.%v", team.Domain, utils.Cfg.ServiceSettings.Domain)
			} else {
				teamUrl = fmt.Sprintf("http://%v.%v", team.Domain, utils.Cfg.ServiceSettings.Domain)
			}

			sender := ""
			if len(strings.TrimSpace(user.FullName)) == 0 {
				sender = user.Username
			} else {
				sender = user.FullName
			}

			senderRole := ""
			if strings.Contains(user.Roles, model.ROLE_ADMIN) || strings.Contains(user.Roles, model.ROLE_SYSTEM_ADMIN) {
				senderRole = "administrator"
			} else {
				senderRole = "member"
			}

			subjectPage := NewServerTemplatePage("invite_subject", teamUrl)
			subjectPage.Props["SenderName"] = sender
			subjectPage.Props["TeamName"] = team.Name
			bodyPage := NewServerTemplatePage("invite_body", teamUrl)
			bodyPage.Props["TeamName"] = team.Name
			bodyPage.Props["SenderName"] = sender
			bodyPage.Props["SenderStatus"] = senderRole

			bodyPage.Props["Email"] = invite

			props := make(map[string]string)
			props["email"] = invite
			props["id"] = team.Id
			props["name"] = team.Name
			props["domain"] = team.Domain
			props["time"] = fmt.Sprintf("%v", model.GetMillis())
			data := model.MapToJson(props)
			hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
			bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", teamUrl, url.QueryEscape(data), url.QueryEscape(hash))

			if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV {
				l4g.Info("sending invitation to %v %v", invite, bodyPage.Props["Link"])
			}

			if err := utils.SendMail(invite, subjectPage.Render(), bodyPage.Render()); err != nil {
				l4g.Error("Failed to send invite email successfully err=%v", err)
			}
		}
	}
}
Esempio n. 5
0
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
		c.Err = model.NewLocAppError("signupTeam", "api.team.signup_team.email_disabled.app_error", nil, "")
		c.Err.StatusCode = http.StatusNotImplemented
		return
	}

	m := model.MapFromJson(r.Body)
	email := strings.ToLower(strings.TrimSpace(m["email"]))

	if len(email) == 0 {
		c.SetInvalidParam("signupTeam", "email")
		return
	}

	if !isTeamCreationAllowed(c, email) {
		return
	}

	subjectPage := utils.NewHTMLTemplate("signup_team_subject", c.Locale)
	subjectPage.Props["Subject"] = c.T("api.templates.signup_team_subject",
		map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]})

	bodyPage := utils.NewHTMLTemplate("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.info",
		map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]}))

	props := make(map[string]string)
	props["email"] = email
	props["time"] = fmt.Sprintf("%v", model.GetMillis())

	data := model.MapToJson(props)
	hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))

	bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_team_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))

	if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
		c.Err = err
		return
	}

	if !utils.Cfg.EmailSettings.RequireEmailVerification {
		m["follow_link"] = fmt.Sprintf("/signup_team_complete/?d=%s&h=%s", url.QueryEscape(data), url.QueryEscape(hash))
	}

	w.Header().Set("Access-Control-Allow-Origin", " *")
	w.Write([]byte(model.MapToJson(m)))
}
Esempio n. 6
0
func fireAndForgetWelcomeEmail(email, teamDisplayName, teamURL string) {
	go func() {

		subjectPage := NewServerTemplatePage("welcome_subject")
		subjectPage.Props["TeamDisplayName"] = teamDisplayName
		bodyPage := NewServerTemplatePage("welcome_body")
		bodyPage.Props["TeamURL"] = teamURL

		if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("Failed to send welcome email successfully err=%v", err)
		}

	}()
}
Esempio n. 7
0
func fireAndForgetEmailChangeEmail(email, teamName, teamUrl string) {
	go func() {

		subjectPage := NewServerTemplatePage("email_change_subject", teamUrl)
		subjectPage.Props["TeamName"] = teamName
		bodyPage := NewServerTemplatePage("email_change_body", teamUrl)
		bodyPage.Props["TeamName"] = teamName

		if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("Failed to send update password email successfully err=%v", err)
		}

	}()
}
Esempio n. 8
0
func sendBatchedEmailNotification(userId string, notifications []*batchedNotification) {
	uchan := Srv.Store.User().Get(userId)
	pchan := Srv.Store.Preference().Get(userId, model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, model.PREFERENCE_NAME_DISPLAY_NAME_FORMAT)

	var user *model.User
	if result := <-uchan; result.Err != nil {
		l4g.Warn("api.email_batching.send_batched_email_notification.user.app_error")
		return
	} else {
		user = result.Data.(*model.User)
	}

	translateFunc := utils.GetUserTranslations(user.Locale)

	var displayNameFormat string
	if result := <-pchan; result.Err != nil && result.Err.DetailedError != sql.ErrNoRows.Error() {
		l4g.Warn("api.email_batching.send_batched_email_notification.preferences.app_error")
		return
	} else if result.Err != nil {
		// no display name format saved, so fall back to default
		displayNameFormat = model.PREFERENCE_DEFAULT_DISPLAY_NAME_FORMAT
	} else {
		displayNameFormat = result.Data.(model.Preference).Value
	}

	var contents string
	for _, notification := range notifications {
		template := utils.NewHTMLTemplate("post_batched_post", user.Locale)

		contents += renderBatchedPost(template, notification.post, notification.teamName, displayNameFormat, translateFunc)
	}

	tm := time.Unix(notifications[0].post.CreateAt/1000, 0)

	subject := translateFunc("api.email_batching.send_batched_email_notification.subject", len(notifications), map[string]interface{}{
		"SiteName": utils.Cfg.TeamSettings.SiteName,
		"Year":     tm.Year(),
		"Month":    translateFunc(tm.Month().String()),
		"Day":      tm.Day(),
	})

	body := utils.NewHTMLTemplate("post_batched_body", user.Locale)
	body.Props["SiteURL"] = *utils.Cfg.ServiceSettings.SiteURL
	body.Props["Posts"] = template.HTML(contents)
	body.Props["BodyText"] = translateFunc("api.email_batching.send_batched_email_notification.body_text", len(notifications))

	if err := utils.SendMail(user.Email, subject, body.Render()); err != nil {
		l4g.Warn(utils.T("api.email_batchings.send_batched_email_notification.send.app_error"), user.Email, err)
	}
}
Esempio n. 9
0
func fireAndForgetWelcomeEmail(name, email, teamName, link string) {
	go func() {

		subjectPage := NewServerTemplatePage("welcome_subject", link)
		bodyPage := NewServerTemplatePage("welcome_body", link)
		bodyPage.Props["FullName"] = name
		bodyPage.Props["TeamName"] = teamName
		bodyPage.Props["FeedbackName"] = utils.Cfg.EmailSettings.FeedbackName

		if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("Failed to send welcome email successfully err=%v", err)
		}

	}()
}
Esempio n. 10
0
func fireAndForgetPasswordChangeEmail(email, teamDisplayName, teamURL, method string) {
	go func() {

		subjectPage := NewServerTemplatePage("password_change_subject", teamURL)
		subjectPage.Props["TeamDisplayName"] = teamDisplayName
		bodyPage := NewServerTemplatePage("password_change_body", teamURL)
		bodyPage.Props["TeamDisplayName"] = teamDisplayName
		bodyPage.Props["Method"] = method

		if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("Failed to send update password email successfully err=%v", err)
		}

	}()
}
Esempio n. 11
0
File: user.go Progetto: jjz/platform
func FireAndForgetVerifyEmail(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", siteURL)
		subjectPage.Props["TeamDisplayName"] = teamDisplayName
		bodyPage := NewServerTemplatePage("verify_body", siteURL)
		bodyPage.Props["TeamDisplayName"] = teamDisplayName
		bodyPage.Props["VerifyUrl"] = link

		if err := utils.SendMail(userEmail, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("Failed to send verification email successfully err=%v", err)
		}
	}()
}
Esempio n. 12
0
func InviteMembers(c *Context, team *model.Team, user *model.User, invites []string) {
	for _, invite := range invites {
		if len(invite) > 0 {

			sender := user.GetDisplayName()

			senderRole := ""
			if c.IsTeamAdmin() {
				senderRole = c.T("api.team.invite_members.admin")
			} else {
				senderRole = c.T("api.team.invite_members.member")
			}

			subjectPage := utils.NewHTMLTemplate("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 := utils.NewHTMLTemplate("invite_body", c.Locale)
			bodyPage.Props["SiteURL"] = c.GetSiteURL()
			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
			props["display_name"] = team.DisplayName
			props["name"] = team.Name
			props["time"] = fmt.Sprintf("%v", model.GetMillis())
			data := model.MapToJson(props)
			hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
			bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))

			if !utils.Cfg.EmailSettings.SendEmailNotifications {
				l4g.Info(utils.T("api.team.invite_members.sending.info"), invite, bodyPage.Props["Link"])
			}

			if err := utils.SendMail(invite, subjectPage.Render(), bodyPage.Render()); err != nil {
				l4g.Error(utils.T("api.team.invite_members.send.error"), err)
			}
		}
	}
}
Esempio n. 13
0
func InviteMembers(c *Context, team *model.Team, user *model.User, invites []string) {
	for _, invite := range invites {
		if len(invite) > 0 {
			teamURL := ""
			teamURL = c.GetTeamURLFromTeam(team)

			sender := user.GetDisplayName()

			senderRole := ""
			if strings.Contains(user.Roles, model.ROLE_ADMIN) || strings.Contains(user.Roles, model.ROLE_SYSTEM_ADMIN) {
				senderRole = "administrator"
			} else {
				senderRole = "member"
			}

			subjectPage := NewServerTemplatePage("invite_subject", teamURL)
			subjectPage.Props["SenderName"] = sender
			subjectPage.Props["TeamDisplayName"] = team.DisplayName
			bodyPage := NewServerTemplatePage("invite_body", teamURL)
			bodyPage.Props["TeamDisplayName"] = team.DisplayName
			bodyPage.Props["SenderName"] = sender
			bodyPage.Props["SenderStatus"] = senderRole

			bodyPage.Props["Email"] = invite

			props := make(map[string]string)
			props["email"] = invite
			props["id"] = team.Id
			props["display_name"] = team.DisplayName
			props["name"] = team.Name
			props["time"] = fmt.Sprintf("%v", model.GetMillis())
			data := model.MapToJson(props)
			hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
			bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))

			if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV {
				l4g.Info("sending invitation to %v %v", invite, bodyPage.Props["Link"])
			}

			if err := utils.SendMail(invite, subjectPage.Render(), bodyPage.Render()); err != nil {
				l4g.Error("Failed to send invite email successfully err=%v", err)
			}
		}
	}
}
Esempio n. 14
0
func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) {

	m := model.MapFromJson(r.Body)

	email := strings.ToLower(strings.TrimSpace(m["email"]))

	if email == "" {
		c.SetInvalidParam("findTeam", "email")
		return
	}

	protocol := "http"

	if utils.Cfg.ServiceSettings.UseSSL {
		protocol = "https"
	}

	subjectPage := NewServerTemplatePage("find_teams_subject", c.TeamUrl)
	bodyPage := NewServerTemplatePage("find_teams_body", c.TeamUrl)

	for key, _ := range utils.Cfg.ServiceSettings.Shards {
		url := fmt.Sprintf("%v://%v.%v/api/v1", protocol, key, utils.Cfg.ServiceSettings.Domain)

		if strings.Index(utils.Cfg.ServiceSettings.Domain, "localhost") == 0 {
			url = fmt.Sprintf("%v://%v/api/v1", protocol, utils.Cfg.ServiceSettings.Domain)
		}

		client := model.NewClient(url)

		if result, err := client.FindTeams(email); err != nil {
			l4g.Error("An error occured while finding teams at %v err=%v", key, err)
		} else {
			data := result.Data.([]string)
			for _, domain := range data {
				bodyPage.Props[fmt.Sprintf("%v://%v.%v", protocol, domain, utils.Cfg.ServiceSettings.Domain)] = ""
			}
		}
	}

	if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
		l4g.Error("An error occured while sending an email in emailTeams err=%v", err)
	}

	w.Write([]byte(model.MapToJson(m)))
}
Esempio n. 15
0
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
		c.Err = model.NewAppError("signupTeam", "Team sign-up with email is disabled.", "")
		c.Err.StatusCode = http.StatusNotImplemented
		return
	}

	m := model.MapFromJson(r.Body)
	email := strings.ToLower(strings.TrimSpace(m["email"]))

	if len(email) == 0 {
		c.SetInvalidParam("signupTeam", "email")
		return
	}

	if !isTreamCreationAllowed(c, email) {
		return
	}

	subjectPage := NewServerTemplatePage("signup_team_subject")
	subjectPage.Props["SiteURL"] = c.GetSiteURL()
	bodyPage := NewServerTemplatePage("signup_team_body")
	bodyPage.Props["SiteURL"] = c.GetSiteURL()

	props := make(map[string]string)
	props["email"] = email
	props["time"] = fmt.Sprintf("%v", model.GetMillis())

	data := model.MapToJson(props)
	hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))

	bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_team_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))

	if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
		c.Err = err
		return
	}

	if !utils.Cfg.EmailSettings.RequireEmailVerification {
		m["follow_link"] = bodyPage.Props["Link"]
	}

	w.Header().Set("Access-Control-Allow-Origin", " *")
	w.Write([]byte(model.MapToJson(m)))
}
Esempio n. 16
0
func sendEmailChangeEmailAndForget(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")
		bodyPage.Props["SiteURL"] = siteURL
		bodyPage.Props["TeamDisplayName"] = teamDisplayName
		bodyPage.Props["TeamURL"] = teamURL
		bodyPage.Props["NewEmail"] = newEmail

		if err := utils.SendMail(oldEmail, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("Failed to send email change notification email successfully err=%v", err)
		}

	}()
}
Esempio n. 17
0
func sendWelcomeEmailAndForget(userId, email, teamName, teamDisplayName, siteURL, teamURL string, verified bool) {
	go func() {

		subjectPage := NewServerTemplatePage("welcome_subject")
		subjectPage.Props["TeamDisplayName"] = teamDisplayName
		bodyPage := NewServerTemplatePage("welcome_body")
		bodyPage.Props["SiteURL"] = siteURL
		bodyPage.Props["TeamURL"] = teamURL

		if !verified {
			link := fmt.Sprintf("%s/verify_email?uid=%s&hid=%s&teamname=%s&email=%s", siteURL, userId, model.HashPassword(userId), teamName, email)
			bodyPage.Props["VerifyUrl"] = link
		}

		if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
			l4g.Error("Failed to send welcome email successfully err=%v", err)
		}
	}()
}
Esempio n. 18
0
func InviteMembers(c *Context, team *model.Team, user *model.User, invites []string) {
	for _, invite := range invites {
		if len(invite) > 0 {

			sender := user.GetDisplayName()

			senderRole := ""
			if c.IsTeamAdmin() {
				senderRole = c.T("api.team.invite_members.admin")
			} else {
				senderRole = c.T("api.team.invite_members.member")
			}

			subjectPage := NewServerTemplatePage("invite_subject")
			subjectPage.Props["SenderName"] = sender
			subjectPage.Props["TeamDisplayName"] = team.DisplayName

			bodyPage := NewServerTemplatePage("invite_body")
			bodyPage.Props["SiteURL"] = c.GetSiteURL()
			bodyPage.Props["TeamURL"] = c.GetTeamURL()
			bodyPage.Props["TeamDisplayName"] = team.DisplayName
			bodyPage.Props["SenderName"] = sender
			bodyPage.Props["SenderStatus"] = senderRole
			props := make(map[string]string)
			props["email"] = invite
			props["id"] = team.Id
			props["display_name"] = team.DisplayName
			props["name"] = team.Name
			props["time"] = fmt.Sprintf("%v", model.GetMillis())
			data := model.MapToJson(props)
			hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
			bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))

			if !utils.Cfg.EmailSettings.SendEmailNotifications {
				l4g.Info(utils.T("api.team.invite_members.sending.info"), invite, bodyPage.Props["Link"])
			}

			if err := utils.SendMail(invite, subjectPage.Render(), bodyPage.Render()); err != nil {
				l4g.Error(utils.T("api.team.invite_members.send.error"), err)
			}
		}
	}
}
Esempio n. 19
0
func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) {

	m := model.MapFromJson(r.Body)

	email := strings.ToLower(strings.TrimSpace(m["email"]))

	if email == "" {
		c.SetInvalidParam("findTeam", "email")
		return
	}

	subjectPage := NewServerTemplatePage("find_teams_subject", c.GetSiteURL())
	bodyPage := NewServerTemplatePage("find_teams_body", c.GetSiteURL())

	if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
		l4g.Error("An error occured while sending an email in emailTeams err=%v", err)
	}

	w.Write([]byte(model.MapToJson(m)))
}
Esempio n. 20
0
func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) {

	m := model.MapFromJson(r.Body)

	email := strings.ToLower(strings.TrimSpace(m["email"]))

	if email == "" {
		c.SetInvalidParam("findTeam", "email")
		return
	}

	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
	} else {
		teams := result.Data.([]*model.Team)

		// the template expects Props to be a map with team names as the keys and the team url as the value
		props := make(map[string]string)
		for _, team := range teams {
			props[team.Name] = c.GetTeamURLFromTeam(team)
		}
		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)
		}

		w.Write([]byte(model.MapToJson(m)))
	}
}
Esempio n. 21
0
func InviteMembers(team *model.Team, senderName string, invites []string) {
	for _, invite := range invites {
		if len(invite) > 0 {
			senderRole := utils.T("api.team.invite_members.member")

			subject := utils.T("api.templates.invite_subject",
				map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName, "SiteName": utils.ClientCfg["SiteName"]})

			bodyPage := utils.NewHTMLTemplate("invite_body", model.DEFAULT_LOCALE)
			bodyPage.Props["SiteURL"] = *utils.Cfg.ServiceSettings.SiteURL
			bodyPage.Props["Title"] = utils.T("api.templates.invite_body.title")
			bodyPage.Html["Info"] = template.HTML(utils.T("api.templates.invite_body.info",
				map[string]interface{}{"SenderStatus": senderRole, "SenderName": senderName, "TeamDisplayName": team.DisplayName}))
			bodyPage.Props["Button"] = utils.T("api.templates.invite_body.button")
			bodyPage.Html["ExtraInfo"] = template.HTML(utils.T("api.templates.invite_body.extra_info",
				map[string]interface{}{"TeamDisplayName": team.DisplayName, "TeamURL": *utils.Cfg.ServiceSettings.SiteURL + "/" + team.Name}))

			props := make(map[string]string)
			props["email"] = invite
			props["id"] = team.Id
			props["display_name"] = team.DisplayName
			props["name"] = team.Name
			props["time"] = fmt.Sprintf("%v", model.GetMillis())
			data := model.MapToJson(props)
			hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
			bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", *utils.Cfg.ServiceSettings.SiteURL, url.QueryEscape(data), url.QueryEscape(hash))

			if !utils.Cfg.EmailSettings.SendEmailNotifications {
				l4g.Info(utils.T("api.team.invite_members.sending.info"), invite, bodyPage.Props["Link"])
			}

			if err := utils.SendMail(invite, subject, bodyPage.Render()); err != nil {
				l4g.Error(utils.T("api.team.invite_members.send.error"), err)
			}
		}
	}
}
Esempio n. 22
0
func sendNotificationEmail(c *Context, post *model.Post, user *model.User, channel *model.Channel, team *model.Team, senderName string) {
	// skip if inactive
	if user.DeleteAt > 0 {
		return
	}

	var channelName string
	var bodyText string
	var subjectText string

	teamURL := c.GetSiteURL() + "/" + team.Name
	tm := time.Unix(post.CreateAt/1000, 0)

	userLocale := utils.GetUserTranslations(user.Locale)

	if channel.Type == model.CHANNEL_DIRECT {
		bodyText = userLocale("api.post.send_notifications_and_forget.message_body")
		subjectText = userLocale("api.post.send_notifications_and_forget.message_subject")
		channelName = senderName
	} else {
		bodyText = userLocale("api.post.send_notifications_and_forget.mention_body")
		subjectText = userLocale("api.post.send_notifications_and_forget.mention_subject")
		channelName = channel.DisplayName
	}

	month := userLocale(tm.Month().String())
	day := fmt.Sprintf("%d", tm.Day())
	year := fmt.Sprintf("%d", tm.Year())
	zone, _ := tm.Zone()

	subjectPage := utils.NewHTMLTemplate("post_subject", user.Locale)
	subjectPage.Props["Subject"] = userLocale("api.templates.post_subject",
		map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName,
			"Month": month[:3], "Day": day, "Year": year})
	subjectPage.Props["SiteName"] = utils.Cfg.TeamSettings.SiteName

	bodyPage := utils.NewHTMLTemplate("post_body", user.Locale)
	bodyPage.Props["SiteURL"] = c.GetSiteURL()
	bodyPage.Props["PostMessage"] = model.ClearMentionTags(post.Message)
	bodyPage.Props["TeamLink"] = teamURL + "/pl/" + post.Id
	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 {
		// extract the filenames from their paths and determine what type of files are attached
		filenames := make([]string, len(post.Filenames))
		onlyImages := true
		for i, filename := range post.Filenames {
			var err error
			if filenames[i], err = url.QueryUnescape(filepath.Base(filename)); err != nil {
				// this should never error since filepath was escaped using url.QueryEscape
				filenames[i] = filepath.Base(filename)
			}

			ext := filepath.Ext(filename)
			onlyImages = onlyImages && model.IsFileExtImage(ext)
		}
		filenamesString := strings.Join(filenames, ", ")

		var attachmentPrefix string
		if onlyImages {
			attachmentPrefix = "Image"
		} else {
			attachmentPrefix = "File"
		}
		if len(post.Filenames) > 1 {
			attachmentPrefix += "s"
		}

		bodyPage.Props["PostMessage"] = userLocale("api.post.send_notifications_and_forget.sent",
			map[string]interface{}{"Prefix": attachmentPrefix, "Filenames": filenamesString})
	}

	if err := utils.SendMail(user.Email, subjectPage.Render(), bodyPage.Render()); err != nil {
		l4g.Error(utils.T("api.post.send_notifications_and_forget.send.error"), user.Email, err)
	}
}
Esempio n. 23
0
func convertTeamTo30(primaryTeamName string, team *TeamForUpgrade, uniqueEmails map[string]bool, uniqueUsernames map[string]bool) []*UserForUpgrade {
	store := api.Srv.Store.(*store.SqlStore)
	var users []*UserForUpgrade
	if _, err := store.GetMaster().Select(&users, "SELECT Users.Id, Users.Username, Users.Email, Users.Roles, Users.TeamId FROM Users WHERE Users.TeamId = :TeamId", map[string]interface{}{"TeamId": team.Id}); err != nil {
		l4g.Error("Failed to load profiles for team details=%v", err)
		flushLogAndExit(1)
	}

	var members []*model.TeamMember
	if result := <-api.Srv.Store.Team().GetMembers(team.Id); result.Err != nil {
		l4g.Error("Failed to load team membership details=%v", result.Err)
		flushLogAndExit(1)
	} else {
		members = result.Data.([]*model.TeamMember)
	}

	for _, user := range users {
		shouldUpdateUser := false
		previousRole := user.Roles
		previousEmail := user.Email
		previousUsername := user.Username

		member := &model.TeamMember{
			TeamId: team.Id,
			UserId: user.Id,
		}

		if model.IsInRole(user.Roles, model.ROLE_TEAM_ADMIN) {
			member.Roles = model.ROLE_TEAM_ADMIN
			user.Roles = ""
			shouldUpdateUser = true
		}

		exists := false
		for _, member := range members {
			if member.UserId == user.Id {
				exists = true
				break
			}
		}

		if !exists {
			if result := <-api.Srv.Store.Team().SaveMember(member); result.Err != nil {
				l4g.Error("Failed to save membership for %v details=%v", user.Email, result.Err)
				flushLogAndExit(1)
			}
		}

		err := api.MoveFile(
			"teams/"+team.Id+"/users/"+user.Id+"/profile.png",
			"users/"+user.Id+"/profile.png",
		)

		if err != nil {
			l4g.Warn("No profile image to move for %v", user.Email)
		}

		if uniqueEmails[user.Email] {
			shouldUpdateUser = true
			emailParts := strings.Split(user.Email, "@")
			if len(emailParts) == 2 {
				user.Email = emailParts[0] + "+" + team.Name + "@" + emailParts[1]
			} else {
				user.Email = user.Email + "." + team.Name
			}

			if len(user.Email) > 127 {
				user.Email = user.Email[:127]
			}
		}

		if uniqueUsernames[user.Username] {
			shouldUpdateUser = true
			user.Username = team.Name + "." + user.Username

			if len(user.Username) > 63 {
				user.Username = user.Username[:63]
			}
		}

		if shouldUpdateUser {
			if _, err := store.GetMaster().Exec(`
				UPDATE Users 
				SET 
				    Email = :Email,
				    Username = :Username,
				    Roles = :Roles
				WHERE
				    Id = :Id
				`,
				map[string]interface{}{
					"Email":    user.Email,
					"Username": user.Username,
					"Roles":    user.Roles,
					"Id":       user.Id,
				},
			); err != nil {
				l4g.Error("Failed to update user %v details=%v", user.Email, err)
				flushLogAndExit(1)
			}

			l4g.Info("modified user_id=%v, changed email from=%v to=%v, changed username from=%v to %v changed roles from=%v to=%v", user.Id, previousEmail, user.Email, previousUsername, user.Username, previousRole, user.Roles)

			emailChanged := previousEmail != user.Email
			usernameChanged := previousUsername != user.Username

			if emailChanged || usernameChanged {
				bodyPage := utils.NewHTMLTemplate("upgrade_30_body", "")

				EmailChanged := ""
				UsernameChanged := ""

				if emailChanged {
					EmailChanged = "true"
				}

				if usernameChanged {
					UsernameChanged = "true"
				}

				bodyPage.Html["Info"] = template.HTML(utils.T("api.templates.upgrade_30_body.info",
					map[string]interface{}{
						"SiteName":        utils.ClientCfg["SiteName"],
						"TeamName":        team.Name,
						"Email":           user.Email,
						"Username":        user.Username,
						"EmailChanged":    EmailChanged,
						"UsernameChanged": UsernameChanged,
					}))

				utils.SendMail(
					previousEmail,
					utils.T("api.templates.upgrade_30_subject.info"),
					bodyPage.Render(),
				)
			}
		}

		uniqueEmails[user.Email] = true
		uniqueUsernames[user.Username] = true
	}

	return users
}
Esempio n. 24
0
func sendNotificationEmail(c *Context, post *model.Post, user *model.User, channel *model.Channel, team *model.Team, senderName string, sender *model.User) {
	// skip if inactive
	if user.DeleteAt > 0 {
		return
	}

	if channel.Type == model.CHANNEL_DIRECT && channel.TeamId != team.Id {
		// this message is a cross-team DM so it we need to find a team that the recipient is on to use in the link
		if result := <-Srv.Store.Team().GetTeamsByUserId(user.Id); result.Err != nil {
			l4g.Error(utils.T("api.post.send_notifications_and_forget.get_teams.error"), user.Id, result.Err)
			return
		} else {
			// if the recipient isn't in the current user's team, just pick one
			teams := result.Data.([]*model.Team)
			found := false

			for i := range teams {
				if teams[i].Id == team.Id {
					found = true
					break
				}
			}

			if !found {
				team = teams[0]
			}
		}
	}

	if *utils.Cfg.EmailSettings.EnableEmailBatching {
		var sendBatched bool

		if result := <-Srv.Store.Preference().Get(user.Id, model.PREFERENCE_CATEGORY_NOTIFICATIONS, model.PREFERENCE_NAME_EMAIL_INTERVAL); result.Err != nil {
			// if the call fails, assume it hasn't been set and use the default
			sendBatched = false
		} else {
			// default to not using batching if the setting is set to immediate
			sendBatched = result.Data.(model.Preference).Value != model.PREFERENCE_DEFAULT_EMAIL_INTERVAL
		}

		if sendBatched {
			if err := AddNotificationEmailToBatch(user, post, team); err == nil {
				return
			}
		}

		// fall back to sending a single email if we can't batch it for some reason
	}

	var channelName string
	var bodyText string
	var subjectText string
	var mailTemplate string
	var mailParameters map[string]interface{}

	teamURL := c.GetSiteURL() + "/" + team.Name
	tm := time.Unix(post.CreateAt/1000, 0)

	userLocale := utils.GetUserTranslations(user.Locale)
	month := userLocale(tm.Month().String())
	day := fmt.Sprintf("%d", tm.Day())
	year := fmt.Sprintf("%d", tm.Year())
	zone, _ := tm.Zone()

	if channel.Type == model.CHANNEL_DIRECT {
		bodyText = userLocale("api.post.send_notifications_and_forget.message_body")
		subjectText = userLocale("api.post.send_notifications_and_forget.message_subject")

		senderDisplayName := senderName
		if sender != nil {
			if result := <-Srv.Store.Preference().Get(user.Id, model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, "name_format"); result.Err != nil {
				// Show default sender's name if user doesn't set display settings.
				senderDisplayName = senderName
			} else {
				senderDisplayName = sender.GetDisplayNameForPreference(result.Data.(model.Preference).Value)
			}
		}

		mailTemplate = "api.templates.post_subject_in_direct_message"
		mailParameters = map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName,
			"SenderDisplayName": senderDisplayName, "Month": month, "Day": day, "Year": year}
	} else {
		bodyText = userLocale("api.post.send_notifications_and_forget.mention_body")
		subjectText = userLocale("api.post.send_notifications_and_forget.mention_subject")
		channelName = channel.DisplayName
		mailTemplate = "api.templates.post_subject_in_channel"
		mailParameters = map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName,
			"ChannelName": channelName, "Month": month, "Day": day, "Year": year}
	}

	subjectPage := utils.NewHTMLTemplate("post_subject", user.Locale)
	subjectPage.Props["Subject"] = userLocale(mailTemplate, mailParameters)
	subjectPage.Props["SiteName"] = utils.Cfg.TeamSettings.SiteName

	bodyPage := utils.NewHTMLTemplate("post_body", user.Locale)
	bodyPage.Props["SiteURL"] = c.GetSiteURL()
	bodyPage.Props["PostMessage"] = getMessageForNotification(post, userLocale)
	bodyPage.Props["TeamLink"] = teamURL + "/pl/" + post.Id
	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}))

	if err := utils.SendMail(user.Email, html.UnescapeString(subjectPage.Render()), bodyPage.Render()); err != nil {
		l4g.Error(utils.T("api.post.send_notifications_and_forget.send.error"), user.Email, err)
	}
}
Esempio n. 25
0
func fireAndForgetNotifications(post *model.Post, teamId, siteURL string) {

	go func() {
		// Get a list of user names (to be used as keywords) and ids for the given team
		uchan := Srv.Store.User().GetProfiles(teamId)
		echan := Srv.Store.Channel().GetMembers(post.ChannelId)
		cchan := Srv.Store.Channel().Get(post.ChannelId)
		tchan := Srv.Store.Team().Get(teamId)

		var channel *model.Channel
		var channelName string
		var bodyText string
		var subjectText string
		if result := <-cchan; result.Err != nil {
			l4g.Error("Failed to retrieve channel channel_id=%v, err=%v", post.ChannelId, result.Err)
			return
		} else {
			channel = result.Data.(*model.Channel)
			if channel.Type == model.CHANNEL_DIRECT {
				bodyText = "You have one new message."
				subjectText = "New Direct Message"
			} else {
				bodyText = "You have one new mention."
				subjectText = "New Mention"
				channelName = channel.DisplayName
			}
		}

		var mentionedUsers []string

		if result := <-uchan; result.Err != nil {
			l4g.Error("Failed to retrieve user profiles team_id=%v, err=%v", teamId, result.Err)
			return
		} else {
			profileMap := result.Data.(map[string]*model.User)

			if _, ok := profileMap[post.UserId]; !ok {
				l4g.Error("Post user_id not returned by GetProfiles user_id=%v", post.UserId)
				return
			}
			senderName := profileMap[post.UserId].Username

			toEmailMap := make(map[string]bool)

			if channel.Type == model.CHANNEL_DIRECT {

				var otherUserId string
				if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId {
					otherUserId = userIds[1]
					channelName = profileMap[userIds[1]].Username
				} else {
					otherUserId = userIds[0]
					channelName = profileMap[userIds[0]].Username
				}

				otherUser := profileMap[otherUserId]
				sendEmail := true
				if _, ok := otherUser.NotifyProps["email"]; ok && otherUser.NotifyProps["email"] == "false" {
					sendEmail = false
				}
				if sendEmail && (otherUser.IsOffline() || otherUser.IsAway()) {
					toEmailMap[otherUserId] = true
				}

			} else {

				// Find out who is a member of the channel, only keep those profiles
				if eResult := <-echan; eResult.Err != nil {
					l4g.Error("Failed to get channel members channel_id=%v err=%v", post.ChannelId, eResult.Err.Message)
					return
				} else {
					tempProfileMap := make(map[string]*model.User)
					members := eResult.Data.([]model.ChannelMember)
					for _, member := range members {
						tempProfileMap[member.UserId] = profileMap[member.UserId]
					}

					profileMap = tempProfileMap
				}

				// Build map for keywords
				keywordMap := make(map[string][]string)
				for _, profile := range profileMap {
					if len(profile.NotifyProps["mention_keys"]) > 0 {

						// Add all the user's mention keys
						splitKeys := strings.Split(profile.NotifyProps["mention_keys"], ",")
						for _, k := range splitKeys {
							keywordMap[k] = append(keywordMap[strings.ToLower(k)], profile.Id)
						}
					}

					// If turned on, add the user's case sensitive first name
					if profile.NotifyProps["first_name"] == "true" {
						keywordMap[profile.FirstName] = append(keywordMap[profile.FirstName], profile.Id)
					}

					// Add @all to keywords if user has them turned on
					if profile.NotifyProps["all"] == "true" {
						keywordMap["@all"] = append(keywordMap["@all"], profile.Id)
					}

					// Add @channel to keywords if user has them turned on
					if profile.NotifyProps["channel"] == "true" {
						keywordMap["@channel"] = append(keywordMap["@channel"], profile.Id)
					}
				}

				// Build a map as a list of unique user_ids that are mentioned in this post
				splitF := func(c rune) bool {
					return model.SplitRunes[c]
				}
				splitMessage := strings.FieldsFunc(post.Message, splitF)
				for _, word := range splitMessage {

					// Non-case-sensitive check for regular keys
					userIds1, keyMatch := keywordMap[strings.ToLower(word)]

					// Case-sensitive check for first name
					userIds2, firstNameMatch := keywordMap[word]

					userIds := append(userIds1, userIds2...)

					// If one of the non-case-senstive keys or the first name matches the word
					//  then we add en entry to the sendEmail map
					if keyMatch || firstNameMatch {
						for _, userId := range userIds {
							if post.UserId == userId {
								continue
							}
							sendEmail := true
							if _, ok := profileMap[userId].NotifyProps["email"]; ok && profileMap[userId].NotifyProps["email"] == "false" {
								sendEmail = false
							}
							if sendEmail && (profileMap[userId].IsAway() || profileMap[userId].IsOffline()) {
								toEmailMap[userId] = true
							} else {
								toEmailMap[userId] = false
							}
						}
					}
				}

				for id := range toEmailMap {
					fireAndForgetMentionUpdate(post.ChannelId, id)
				}
			}

			if len(toEmailMap) != 0 {
				mentionedUsers = make([]string, 0, len(toEmailMap))
				for k := range toEmailMap {
					mentionedUsers = append(mentionedUsers, k)
				}

				var teamDisplayName string
				var teamURL string
				if result := <-tchan; result.Err != nil {
					l4g.Error("Failed to retrieve team team_id=%v, err=%v", teamId, result.Err)
					return
				} else {
					teamDisplayName = result.Data.(*model.Team).DisplayName
					teamURL = siteURL + "/" + result.Data.(*model.Team).Name
				}

				// Build and send the emails
				location, _ := time.LoadLocation("UTC")
				tm := time.Unix(post.CreateAt/1000, 0).In(location)

				subjectPage := NewServerTemplatePage("post_subject")
				subjectPage.Props["SiteURL"] = siteURL
				subjectPage.Props["TeamDisplayName"] = teamDisplayName
				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())

				for id, doSend := range toEmailMap {

					if !doSend {
						continue
					}

					// skip if inactive
					if profileMap[id].DeleteAt > 0 {
						continue
					}

					bodyPage := NewServerTemplatePage("post_body")
					bodyPage.Props["SiteURL"] = siteURL
					bodyPage.Props["Nickname"] = profileMap[id].FirstName
					bodyPage.Props["TeamDisplayName"] = teamDisplayName
					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["PostMessage"] = model.ClearMentionTags(post.Message)
					bodyPage.Props["TeamLink"] = teamURL + "/channels/" + channel.Name

					// 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 {
						// extract the filenames from their paths and determine what type of files are attached
						filenames := make([]string, len(post.Filenames))
						onlyImages := true
						for i, filename := range post.Filenames {
							var err error
							if filenames[i], err = url.QueryUnescape(filepath.Base(filename)); err != nil {
								// this should never error since filepath was escaped using url.QueryEscape
								filenames[i] = filepath.Base(filename)
							}

							ext := filepath.Ext(filename)
							onlyImages = onlyImages && model.IsFileExtImage(ext)
						}
						filenamesString := strings.Join(filenames, ", ")

						var attachmentPrefix string
						if onlyImages {
							attachmentPrefix = "Image"
						} else {
							attachmentPrefix = "File"
						}
						if len(post.Filenames) > 1 {
							attachmentPrefix += "s"
						}

						bodyPage.Props["PostMessage"] = fmt.Sprintf("%s: %s sent", attachmentPrefix, filenamesString)
					}

					if err := utils.SendMail(profileMap[id].Email, subjectPage.Render(), bodyPage.Render()); err != nil {
						l4g.Error("Failed to send mention email successfully email=%v err=%v", profileMap[id].Email, err)
					}

					if len(utils.Cfg.EmailSettings.ApplePushServer) > 0 {
						sessionChan := Srv.Store.Session().GetSessions(id)
						if result := <-sessionChan; result.Err != nil {
							l4g.Error("Failed to retrieve sessions in notifications id=%v, err=%v", id, result.Err)
						} else {
							sessions := result.Data.([]*model.Session)
							alreadySeen := make(map[string]string)

							for _, session := range sessions {
								if len(session.DeviceId) > 0 && alreadySeen[session.DeviceId] == "" {

									alreadySeen[session.DeviceId] = session.DeviceId

									utils.FireAndForgetSendAppleNotify(session.DeviceId, subjectPage.Render(), 1)
								}
							}
						}
					}
				}
			}
		}

		message := model.NewMessage(teamId, post.ChannelId, post.UserId, model.ACTION_POSTED)
		message.Add("post", post.ToJson())

		if len(post.Filenames) != 0 {
			message.Add("otherFile", "true")

			for _, filename := range post.Filenames {
				ext := filepath.Ext(filename)
				if model.IsFileExtImage(ext) {
					message.Add("image", "true")
					break
				}
			}
		}

		if len(mentionedUsers) != 0 {
			message.Add("mentions", model.ArrayToJson(mentionedUsers))
		}

		PublishAndForget(message)
	}()
}
Esempio n. 26
0
func doSecurityAndDiagnostics() {
	if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert {
		if result := <-app.Srv.Store.System().Get(); result.Err == nil {
			props := result.Data.(model.StringMap)
			lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0)
			currentTime := model.GetMillis()

			if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
				l4g.Debug(utils.T("mattermost.security_checks.debug"))

				v := url.Values{}

				v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
				v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
				v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
				v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
				v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
				v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)

				if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 {
					v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1")
				} else {
					v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0")
				}

				systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)}
				if lastSecurityTime == 0 {
					<-app.Srv.Store.System().Save(systemSecurityLastTime)
				} else {
					<-app.Srv.Store.System().Update(systemSecurityLastTime)
				}

				if ucr := <-app.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
					v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
				}

				if ucr := <-app.Srv.Store.Status().GetTotalActiveUsersCount(); ucr.Err == nil {
					v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
				}

				if tcr := <-app.Srv.Store.Team().AnalyticsTeamCount(); tcr.Err == nil {
					v.Set(utils.PROP_DIAGNOSTIC_TEAM_COUNT, strconv.FormatInt(tcr.Data.(int64), 10))
				}

				res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
				if err != nil {
					l4g.Error(utils.T("mattermost.security_info.error"))
					return
				}

				bulletins := model.SecurityBulletinsFromJson(res.Body)
				ioutil.ReadAll(res.Body)
				res.Body.Close()

				for _, bulletin := range bulletins {
					if bulletin.AppliesToVersion == model.CurrentVersion {
						if props["SecurityBulletin_"+bulletin.Id] == "" {
							if results := <-app.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
								l4g.Error(utils.T("mattermost.system_admins.error"))
								return
							} else {
								users := results.Data.(map[string]*model.User)

								resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id)
								if err != nil {
									l4g.Error(utils.T("mattermost.security_bulletin.error"))
									return
								}

								body, err := ioutil.ReadAll(resBody.Body)
								res.Body.Close()
								if err != nil || resBody.StatusCode != 200 {
									l4g.Error(utils.T("mattermost.security_bulletin_read.error"))
									return
								}

								for _, user := range users {
									l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email)
									utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body))
								}
							}

							bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
							<-app.Srv.Store.System().Save(bulletinSeen)
						}
					}
				}
			}
		}
	}

	if *utils.Cfg.LogSettings.EnableDiagnostics {
		utils.SendGeneralDiagnostics()
		sendServerDiagnostics()
	}
}
Esempio n. 27
0
func runSecurityAndDiagnosticsJobAndForget() {
	go func() {
		for {
			if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert {
				if result := <-api.Srv.Store.System().Get(); result.Err == nil {
					props := result.Data.(model.StringMap)
					lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0)
					currentTime := model.GetMillis()

					if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
						l4g.Debug("Checking for security update from Mattermost")

						v := url.Values{}

						v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
						v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
						v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
						v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
						v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
						v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)

						if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 {
							v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1")
						} else {
							v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0")
						}

						systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)}
						if lastSecurityTime == 0 {
							<-api.Srv.Store.System().Save(systemSecurityLastTime)
						} else {
							<-api.Srv.Store.System().Update(systemSecurityLastTime)
						}

						if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
							v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
						}

						if ucr := <-api.Srv.Store.User().GetTotalActiveUsersCount(); ucr.Err == nil {
							v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
						}

						res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
						if err != nil {
							l4g.Error("Failed to get security update information from Mattermost.")
							return
						}

						bulletins := model.SecurityBulletinsFromJson(res.Body)

						for _, bulletin := range bulletins {
							if bulletin.AppliesToVersion == model.CurrentVersion {
								if props["SecurityBulletin_"+bulletin.Id] == "" {
									if results := <-api.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
										l4g.Error("Failed to get system admins for security update information from Mattermost.")
										return
									} else {
										users := results.Data.(map[string]*model.User)

										resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id)
										if err != nil {
											l4g.Error("Failed to get security bulletin details")
											return
										}

										body, err := ioutil.ReadAll(resBody.Body)
										res.Body.Close()
										if err != nil || resBody.StatusCode != 200 {
											l4g.Error("Failed to read security bulletin details")
											return
										}

										for _, user := range users {
											l4g.Info("Sending security bulletin for " + bulletin.Id + " to " + user.Email)
											utils.SendMail(user.Email, "Mattermost Security Bulletin", string(body))
										}
									}

									bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
									<-api.Srv.Store.System().Save(bulletinSeen)
								}
							}
						}
					}
				}
			}

			time.Sleep(time.Hour * 4)
		}
	}()
}
Esempio n. 28
0
func securityAndDiagnosticsJob() {
	go func() {
		for {
			if utils.Cfg.PrivacySettings.EnableSecurityFixAlert && model.IsOfficalBuild() {
				if result := <-api.Srv.Store.System().Get(); result.Err == nil {
					props := result.Data.(model.StringMap)
					lastSecurityTime, _ := strconv.ParseInt(props["LastSecurityTime"], 10, 0)
					currentTime := model.GetMillis()

					id := props["DiagnosticId"]
					if len(id) == 0 {
						id = model.NewId()
						systemId := &model.System{Name: "DiagnosticId", Value: id}
						<-api.Srv.Store.System().Save(systemId)
					}

					v := url.Values{}
					v.Set(utils.PROP_DIAGNOSTIC_ID, id)
					v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
					v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
					v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
					v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)

					if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
						l4g.Info("Checking for security update from Mattermost")

						systemSecurityLastTime := &model.System{Name: "LastSecurityTime", Value: strconv.FormatInt(currentTime, 10)}
						if lastSecurityTime == 0 {
							<-api.Srv.Store.System().Save(systemSecurityLastTime)
						} else {
							<-api.Srv.Store.System().Update(systemSecurityLastTime)
						}

						res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
						if err != nil {
							l4g.Error("Failed to get security update information from Mattermost.")
							return
						}

						bulletins := model.SecurityBulletinsFromJson(res.Body)

						for _, bulletin := range bulletins {
							if bulletin.AppliesToVersion == model.CurrentVersion {
								if props["SecurityBulletin_"+bulletin.Id] == "" {
									if results := <-api.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
										l4g.Error("Failed to get system admins for security update information from Mattermost.")
										return
									} else {
										users := results.Data.(map[string]*model.User)

										resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id)
										if err != nil {
											l4g.Error("Failed to get security bulletin details")
											return
										}

										body, err := ioutil.ReadAll(resBody.Body)
										res.Body.Close()
										if err != nil || resBody.StatusCode != 200 {
											l4g.Error("Failed to read security bulletin details")
											return
										}

										for _, user := range users {
											l4g.Info("Sending security bulletin for " + bulletin.Id + " to " + user.Email)
											utils.SendMail(user.Email, "Mattermost Security Bulletin", string(body))
										}
									}

									bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
									<-api.Srv.Store.System().Save(bulletinSeen)
								}
							}
						}
					}
				}
			}

			time.Sleep(time.Hour * 4)
		}
	}()
}
Esempio n. 29
0
func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *model.Channel, profileMap map[string]*model.User, members []model.ChannelMember) {
	var channelName string
	var bodyText string
	var subjectText string

	var mentionedUsers []string

	if _, ok := profileMap[post.UserId]; !ok {
		l4g.Error(utils.T("api.post.send_notifications_and_forget.user_id.error"), post.UserId)
		return
	}
	senderName := profileMap[post.UserId].Username

	toEmailMap := make(map[string]bool)

	if channel.Type == model.CHANNEL_DIRECT {

		var otherUserId string
		if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId {
			otherUserId = userIds[1]
			channelName = profileMap[userIds[1]].Username
		} else {
			otherUserId = userIds[0]
			channelName = profileMap[userIds[0]].Username
		}

		otherUser := profileMap[otherUserId]
		sendEmail := true
		if _, ok := otherUser.NotifyProps["email"]; ok && otherUser.NotifyProps["email"] == "false" {
			sendEmail = false
		}
		if sendEmail && (otherUser.IsOffline() || otherUser.IsAway()) {
			toEmailMap[otherUserId] = true
		}

	} else {
		// Find out who is a member of the channel, only keep those profiles
		tempProfileMap := make(map[string]*model.User)
		for _, member := range members {
			tempProfileMap[member.UserId] = profileMap[member.UserId]
		}

		profileMap = tempProfileMap

		// Build map for keywords
		keywordMap := make(map[string][]string)
		for _, profile := range profileMap {
			if len(profile.NotifyProps["mention_keys"]) > 0 {

				// Add all the user's mention keys
				splitKeys := strings.Split(profile.NotifyProps["mention_keys"], ",")
				for _, k := range splitKeys {
					keywordMap[k] = append(keywordMap[strings.ToLower(k)], profile.Id)
				}
			}

			// If turned on, add the user's case sensitive first name
			if profile.NotifyProps["first_name"] == "true" {
				keywordMap[profile.FirstName] = append(keywordMap[profile.FirstName], profile.Id)
			}

			// Add @all to keywords if user has them turned on
			// if profile.NotifyProps["all"] == "true" {
			// 	keywordMap["@all"] = append(keywordMap["@all"], profile.Id)
			// }

			// Add @channel to keywords if user has them turned on
			if profile.NotifyProps["channel"] == "true" {
				keywordMap["@channel"] = append(keywordMap["@channel"], profile.Id)
			}
		}

		// Build a map as a list of unique user_ids that are mentioned in this post
		splitF := func(c rune) bool {
			return model.SplitRunes[c]
		}
		splitMessage := strings.Fields(post.Message)
		for _, word := range splitMessage {
			var userIds []string

			// Non-case-sensitive check for regular keys
			if ids, match := keywordMap[strings.ToLower(word)]; match {
				userIds = append(userIds, ids...)
			}

			// Case-sensitive check for first name
			if ids, match := keywordMap[word]; match {
				userIds = append(userIds, ids...)
			}

			if len(userIds) == 0 {
				// No matches were found with the string split just on whitespace so try further splitting
				// the message on punctuation
				splitWords := strings.FieldsFunc(word, splitF)

				for _, splitWord := range splitWords {
					// Non-case-sensitive check for regular keys
					if ids, match := keywordMap[strings.ToLower(splitWord)]; match {
						userIds = append(userIds, ids...)
					}

					// Case-sensitive check for first name
					if ids, match := keywordMap[splitWord]; match {
						userIds = append(userIds, ids...)
					}
				}
			}

			for _, userId := range userIds {
				if post.UserId == userId && post.Props["from_webhook"] != "true" {
					continue
				}
				sendEmail := true
				if _, ok := profileMap[userId].NotifyProps["email"]; ok && profileMap[userId].NotifyProps["email"] == "false" {
					sendEmail = false
				}
				if sendEmail && (profileMap[userId].IsAway() || profileMap[userId].IsOffline()) {
					toEmailMap[userId] = true
				} else {
					toEmailMap[userId] = false
				}
			}
		}

		for id := range toEmailMap {
			updateMentionCountAndForget(post.ChannelId, id)
		}
	}

	if len(toEmailMap) != 0 {
		mentionedUsers = make([]string, 0, len(toEmailMap))
		for k := range toEmailMap {
			mentionedUsers = append(mentionedUsers, k)
		}

		teamURL := c.GetSiteURL() + "/" + team.Name

		// Build and send the emails
		tm := time.Unix(post.CreateAt/1000, 0)

		for id, doSend := range toEmailMap {

			if !doSend {
				continue
			}

			// skip if inactive
			if profileMap[id].DeleteAt > 0 {
				continue
			}

			userLocale := utils.GetUserTranslations(profileMap[id].Locale)

			if channel.Type == model.CHANNEL_DIRECT {
				bodyText = userLocale("api.post.send_notifications_and_forget.message_body")
				subjectText = userLocale("api.post.send_notifications_and_forget.message_subject")
			} else {
				bodyText = userLocale("api.post.send_notifications_and_forget.mention_body")
				subjectText = userLocale("api.post.send_notifications_and_forget.mention_subject")
				channelName = channel.DisplayName
			}

			month := userLocale(tm.Month().String())
			day := fmt.Sprintf("%d", tm.Day())
			year := fmt.Sprintf("%d", tm.Year())
			zone, _ := tm.Zone()

			subjectPage := utils.NewHTMLTemplate("post_subject", profileMap[id].Locale)
			subjectPage.Props["Subject"] = userLocale("api.templates.post_subject",
				map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName,
					"Month": month[:3], "Day": day, "Year": year})
			subjectPage.Props["SiteName"] = utils.Cfg.TeamSettings.SiteName

			bodyPage := utils.NewHTMLTemplate("post_body", profileMap[id].Locale)
			bodyPage.Props["SiteURL"] = c.GetSiteURL()
			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 {
				// extract the filenames from their paths and determine what type of files are attached
				filenames := make([]string, len(post.Filenames))
				onlyImages := true
				for i, filename := range post.Filenames {
					var err error
					if filenames[i], err = url.QueryUnescape(filepath.Base(filename)); err != nil {
						// this should never error since filepath was escaped using url.QueryEscape
						filenames[i] = filepath.Base(filename)
					}

					ext := filepath.Ext(filename)
					onlyImages = onlyImages && model.IsFileExtImage(ext)
				}
				filenamesString := strings.Join(filenames, ", ")

				var attachmentPrefix string
				if onlyImages {
					attachmentPrefix = "Image"
				} else {
					attachmentPrefix = "File"
				}
				if len(post.Filenames) > 1 {
					attachmentPrefix += "s"
				}

				bodyPage.Props["PostMessage"] = userLocale("api.post.send_notifications_and_forget.sent",
					map[string]interface{}{"Prefix": attachmentPrefix, "Filenames": filenamesString})
			}

			if err := utils.SendMail(profileMap[id].Email, subjectPage.Render(), bodyPage.Render()); err != nil {
				l4g.Error(utils.T("api.post.send_notifications_and_forget.send.error"), profileMap[id].Email, err)
			}

			if *utils.Cfg.EmailSettings.SendPushNotifications {
				sessionChan := Srv.Store.Session().GetSessions(id)
				if result := <-sessionChan; result.Err != nil {
					l4g.Error(utils.T("api.post.send_notifications_and_forget.sessions.error"), id, result.Err)
				} else {
					sessions := result.Data.([]*model.Session)
					alreadySeen := make(map[string]string)

					pushServer := *utils.Cfg.EmailSettings.PushNotificationServer
					if pushServer == model.MHPNS && (!utils.IsLicensed || !*utils.License.Features.MHPNS) {
						l4g.Warn(utils.T("api.post.send_notifications_and_forget.push_notification.mhpnsWarn"))
					} else {
						for _, session := range sessions {
							if len(session.DeviceId) > 0 && alreadySeen[session.DeviceId] == "" &&
								(strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")) {
								alreadySeen[session.DeviceId] = session.DeviceId

								msg := model.PushNotification{}
								if badge := <-Srv.Store.User().GetUnreadCount(id); badge.Err != nil {
									msg.Badge = 1
									l4g.Error(utils.T("store.sql_user.get_unread_count.app_error"), id, badge.Err)
								} else {
									msg.Badge = int(badge.Data.(int64))
								}
								msg.ServerId = utils.CfgDiagnosticId
								msg.ChannelId = channel.Id
								msg.ChannelName = channel.Name

								if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":") {
									msg.Platform = model.PUSH_NOTIFY_APPLE
									msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_APPLE+":")
								} else if strings.HasPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":") {
									msg.Platform = model.PUSH_NOTIFY_ANDROID
									msg.DeviceId = strings.TrimPrefix(session.DeviceId, model.PUSH_NOTIFY_ANDROID+":")
								}

								if *utils.Cfg.EmailSettings.PushNotificationContents == model.FULL_NOTIFICATION {
									if channel.Type == model.CHANNEL_DIRECT {
										msg.Category = model.CATEGORY_DM
										msg.Message = "@" + senderName + ": " + model.ClearMentionTags(post.Message)
									} else {
										msg.Message = "@" + senderName + " @ " + channelName + ": " + model.ClearMentionTags(post.Message)
									}
								} else {
									if channel.Type == model.CHANNEL_DIRECT {
										msg.Category = model.CATEGORY_DM
										msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_message")
									} else {
										msg.Message = senderName + userLocale("api.post.send_notifications_and_forget.push_mention") + channelName
									}
								}

								tr := &http.Transport{
									TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
								}
								httpClient := &http.Client{Transport: tr}
								request, _ := http.NewRequest("POST", pushServer+model.API_URL_SUFFIX_V1+"/send_push", strings.NewReader(msg.ToJson()))

								l4g.Debug(utils.T("api.post.send_notifications_and_forget.push_notification.debug"), msg.DeviceId, msg.Message)
								if _, err := httpClient.Do(request); err != nil {
									l4g.Error(utils.T("api.post.send_notifications_and_forget.push_notification.error"), id, err)
								}
							}
						}
					}
				}
			}
		}
	}

	message := model.NewMessage(c.TeamId, post.ChannelId, post.UserId, model.ACTION_POSTED)
	message.Add("post", post.ToJson())
	message.Add("channel_type", channel.Type)

	if len(post.Filenames) != 0 {
		message.Add("otherFile", "true")

		for _, filename := range post.Filenames {
			ext := filepath.Ext(filename)
			if model.IsFileExtImage(ext) {
				message.Add("image", "true")
				break
			}
		}
	}

	if len(mentionedUsers) != 0 {
		message.Add("mentions", model.ArrayToJson(mentionedUsers))
	}

	PublishAndForget(message)
}
Esempio n. 30
0
func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {

	go func() {
		// Get a list of user names (to be used as keywords) and ids for the given team
		uchan := Srv.Store.User().GetProfiles(teamId)
		echan := Srv.Store.Channel().GetMembers(post.ChannelId)
		cchan := Srv.Store.Channel().Get(post.ChannelId)
		tchan := Srv.Store.Team().Get(teamId)

		var channel *model.Channel
		var channelName string
		var bodyText string
		var subjectText string
		if result := <-cchan; result.Err != nil {
			l4g.Error("Failed to retrieve channel channel_id=%v, err=%v", post.ChannelId, result.Err)
			return
		} else {
			channel = result.Data.(*model.Channel)
			if channel.Type == model.CHANNEL_DIRECT {
				bodyText = "You have one new message."
				subjectText = "New Direct Message"
			} else {
				bodyText = "You have one new mention."
				subjectText = "New Mention"
				channelName = channel.DisplayName
			}
		}

		var mentionedUsers []string

		if result := <-uchan; result.Err != nil {
			l4g.Error("Failed to retrieve user profiles team_id=%v, err=%v", teamId, result.Err)
			return
		} else {
			profileMap := result.Data.(map[string]*model.User)

			if _, ok := profileMap[post.UserId]; !ok {
				l4g.Error("Post user_id not returned by GetProfiles user_id=%v", post.UserId)
				return
			}
			senderName := profileMap[post.UserId].Username

			toEmailMap := make(map[string]bool)

			if channel.Type == model.CHANNEL_DIRECT {

				var otherUserId string
				if userIds := strings.Split(channel.Name, "__"); userIds[0] == post.UserId {
					otherUserId = userIds[1]
					channelName = profileMap[userIds[1]].Username
				} else {
					otherUserId = userIds[0]
					channelName = profileMap[userIds[0]].Username
				}

				otherUser := profileMap[otherUserId]
				sendEmail := true
				if _, ok := otherUser.NotifyProps["email"]; ok && otherUser.NotifyProps["email"] == "false" {
					sendEmail = false
				}
				if sendEmail && (otherUser.IsOffline() || otherUser.IsAway()) {
					toEmailMap[otherUserId] = true
				}

			} else {

				// Find out who is a member of the channel only keep those profiles
				if eResult := <-echan; eResult.Err != nil {
					l4g.Error("Failed to get channel members channel_id=%v err=%v", post.ChannelId, eResult.Err.Message)
					return
				} else {
					tempProfileMap := make(map[string]*model.User)
					members := eResult.Data.([]model.ChannelMember)
					for _, member := range members {
						tempProfileMap[member.UserId] = profileMap[member.UserId]
					}

					profileMap = tempProfileMap
				}

				// Build map for keywords
				keywordMap := make(map[string][]string)
				for _, profile := range profileMap {
					if len(profile.NotifyProps["mention_keys"]) > 0 {

						// Add all the user's mention keys
						splitKeys := strings.Split(profile.NotifyProps["mention_keys"], ",")
						for _, k := range splitKeys {
							keywordMap[k] = append(keywordMap[strings.ToLower(k)], profile.Id)
						}

						// If turned on, add the user's case sensitive first name
						if profile.NotifyProps["first_name"] == "true" {
							splitName := strings.Split(profile.FullName, " ")
							if len(splitName) > 0 && splitName[0] != "" {
								keywordMap[splitName[0]] = append(keywordMap[splitName[0]], profile.Id)
							}
						}
					}
				}

				// Build a map as a list of unique user_ids that are mentioned in this post
				splitF := func(c rune) bool {
					return model.SplitRunes[c]
				}
				splitMessage := strings.FieldsFunc(strings.Replace(post.Message, "<br>", " ", -1), splitF)
				for _, word := range splitMessage {

					// Non-case-sensitive check for regular keys
					userIds1, keyMatch := keywordMap[strings.ToLower(word)]

					// Case-sensitive check for first name
					userIds2, firstNameMatch := keywordMap[word]

					userIds := append(userIds1, userIds2...)

					// If one of the non-case-senstive keys or the first name matches the word
					//  then we add en entry to the sendEmail map
					if keyMatch || firstNameMatch {
						for _, userId := range userIds {
							if post.UserId == userId {
								continue
							}
							sendEmail := true
							if _, ok := profileMap[userId].NotifyProps["email"]; ok && profileMap[userId].NotifyProps["email"] == "false" {
								sendEmail = false
							}
							if sendEmail && (profileMap[userId].IsAway() || profileMap[userId].IsOffline()) {
								toEmailMap[userId] = true
							} else {
								toEmailMap[userId] = false
							}
						}
					}
				}

				for id, _ := range toEmailMap {
					fireAndForgetMentionUpdate(post.ChannelId, id)
				}
			}

			if len(toEmailMap) != 0 {
				mentionedUsers = make([]string, 0, len(toEmailMap))
				for k := range toEmailMap {
					mentionedUsers = append(mentionedUsers, k)
				}

				var teamName string
				if result := <-tchan; result.Err != nil {
					l4g.Error("Failed to retrieve team team_id=%v, err=%v", teamId, result.Err)
					return
				} else {
					teamName = result.Data.(*model.Team).Name
				}

				// Build and send the emails
				location, _ := time.LoadLocation("UTC")
				tm := time.Unix(post.CreateAt/1000, 0).In(location)

				subjectPage := NewServerTemplatePage("post_subject", teamUrl)
				subjectPage.Props["TeamName"] = teamName
				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())

				for id, doSend := range toEmailMap {

					if !doSend {
						continue
					}

					// skip if inactive
					if profileMap[id].DeleteAt > 0 {
						continue
					}

					firstName := strings.Split(profileMap[id].FullName, " ")[0]

					bodyPage := NewServerTemplatePage("post_body", teamUrl)
					bodyPage.Props["FullName"] = firstName
					bodyPage.Props["TeamName"] = teamName
					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["PostMessage"] = model.ClearMentionTags(post.Message)
					bodyPage.Props["TeamLink"] = teamUrl + "/channels/" + channel.Name

					if err := utils.SendMail(profileMap[id].Email, subjectPage.Render(), bodyPage.Render()); err != nil {
						l4g.Error("Failed to send mention email successfully email=%v err=%v", profileMap[id].Email, err)
					}

					if len(utils.Cfg.EmailSettings.ApplePushServer) > 0 {
						sessionChan := Srv.Store.Session().GetSessions(id)
						if result := <-sessionChan; result.Err != nil {
							l4g.Error("Failed to retrieve sessions in notifications id=%v, err=%v", id, result.Err)
						} else {
							sessions := result.Data.([]*model.Session)
							alreadySeen := make(map[string]string)

							for _, session := range sessions {
								if len(session.DeviceId) > 0 && alreadySeen[session.DeviceId] == "" {

									alreadySeen[session.DeviceId] = session.DeviceId

									utils.FireAndForgetSendAppleNotify(session.DeviceId, subjectPage.Render(), 1)
								}
							}
						}
					}
				}
			}
		}

		message := model.NewMessage(teamId, post.ChannelId, post.UserId, model.ACTION_POSTED)
		message.Add("post", post.ToJson())
		if len(mentionedUsers) != 0 {
			message.Add("mentions", model.ArrayToJson(mentionedUsers))
		}

		store.PublishAndForget(message)
	}()
}