mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Adding email to admin console
This commit is contained in:
27
api/admin.go
27
api/admin.go
@@ -24,6 +24,7 @@ func InitAdmin(r *mux.Router) {
|
|||||||
sr.Handle("/config", ApiUserRequired(getConfig)).Methods("GET")
|
sr.Handle("/config", ApiUserRequired(getConfig)).Methods("GET")
|
||||||
sr.Handle("/save_config", ApiUserRequired(saveConfig)).Methods("POST")
|
sr.Handle("/save_config", ApiUserRequired(saveConfig)).Methods("POST")
|
||||||
sr.Handle("/client_props", ApiAppHandler(getClientProperties)).Methods("GET")
|
sr.Handle("/client_props", ApiAppHandler(getClientProperties)).Methods("GET")
|
||||||
|
sr.Handle("/test_email", ApiUserRequired(testEmail)).Methods("POST")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -98,3 +99,29 @@ func saveConfig(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
json := utils.Cfg.ToJson()
|
json := utils.Cfg.ToJson()
|
||||||
w.Write([]byte(json))
|
w.Write([]byte(json))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !c.HasSystemAdminPermissions("testEmail") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := model.ConfigFromJson(r.Body)
|
||||||
|
if cfg == nil {
|
||||||
|
c.SetInvalidParam("testEmail", "config")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-Srv.Store.User().Get(c.Session.UserId); result.Err != nil {
|
||||||
|
c.Err = result.Err
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if err := utils.SendMailUsingConfig(result.Data.(*model.User).Email, "Mattermost - Testing Email Settings", "<br/><br/><br/>It appears your Mattermost email is setup correctly!", cfg); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]string)
|
||||||
|
m["SUCCESS"] = "true"
|
||||||
|
w.Write([]byte(model.MapToJson(m)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -122,3 +122,31 @@ func TestSaveConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEmailTest(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||||
|
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||||
|
|
||||||
|
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||||
|
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||||
|
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||||
|
|
||||||
|
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||||
|
|
||||||
|
if _, err := Client.TestEmail(utils.Cfg); err == nil {
|
||||||
|
t.Fatal("Shouldn't have permissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Context{}
|
||||||
|
c.RequestId = model.NewId()
|
||||||
|
c.IpAddress = "cmd_line"
|
||||||
|
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
|
||||||
|
|
||||||
|
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||||
|
|
||||||
|
if _, err := Client.TestEmail(utils.Cfg); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
11
api/team.go
11
api/team.go
@@ -38,7 +38,7 @@ func InitTeam(r *mux.Router) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if utils.Cfg.ServiceSettings.DisableEmailSignUp {
|
if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
|
||||||
c.Err = model.NewAppError("signupTeam", "Team sign-up with email is disabled.", "")
|
c.Err = model.NewAppError("signupTeam", "Team sign-up with email is disabled.", "")
|
||||||
c.Err.StatusCode = http.StatusNotImplemented
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
return
|
return
|
||||||
@@ -76,10 +76,7 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV || utils.Cfg.EmailSettings.ByPassEmail {
|
m["follow_link"] = bodyPage.Props["Link"]
|
||||||
m["follow_link"] = bodyPage.Props["Link"]
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", " *")
|
w.Header().Set("Access-Control-Allow-Origin", " *")
|
||||||
w.Write([]byte(model.MapToJson(m)))
|
w.Write([]byte(model.MapToJson(m)))
|
||||||
}
|
}
|
||||||
@@ -147,7 +144,7 @@ func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if utils.Cfg.ServiceSettings.DisableEmailSignUp {
|
if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
|
||||||
c.Err = model.NewAppError("createTeamFromSignup", "Team sign-up with email is disabled.", "")
|
c.Err = model.NewAppError("createTeamFromSignup", "Team sign-up with email is disabled.", "")
|
||||||
c.Err.StatusCode = http.StatusNotImplemented
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
return
|
return
|
||||||
@@ -257,7 +254,7 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateTeam(c *Context, team *model.Team) *model.Team {
|
func CreateTeam(c *Context, team *model.Team) *model.Team {
|
||||||
if utils.Cfg.ServiceSettings.DisableEmailSignUp {
|
if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
|
||||||
c.Err = model.NewAppError("createTeam", "Team sign-up with email is disabled.", "")
|
c.Err = model.NewAppError("createTeam", "Team sign-up with email is disabled.", "")
|
||||||
c.Err.StatusCode = http.StatusNotImplemented
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func InitUser(r *mux.Router) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if utils.Cfg.ServiceSettings.DisableEmailSignUp {
|
if !utils.Cfg.EmailSettings.AllowSignUpWithEmail {
|
||||||
c.Err = model.NewAppError("signupTeam", "User sign-up with email is disabled.", "")
|
c.Err = model.NewAppError("signupTeam", "User sign-up with email is disabled.", "")
|
||||||
c.Err.StatusCode = http.StatusNotImplemented
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
return
|
return
|
||||||
@@ -324,7 +324,7 @@ func checkUserPassword(c *Context, user *model.User, password string) bool {
|
|||||||
func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) {
|
func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) {
|
||||||
c.LogAuditWithUserId(user.Id, "attempt")
|
c.LogAuditWithUserId(user.Id, "attempt")
|
||||||
|
|
||||||
if !user.EmailVerified && !utils.Cfg.EmailSettings.ByPassEmail {
|
if !user.EmailVerified && utils.Cfg.EmailSettings.RequireEmailVerification {
|
||||||
c.Err = model.NewAppError("Login", "Login failed because email address has not been verified", "user_id="+user.Id)
|
c.Err = model.NewAppError("Login", "Login failed because email address has not been verified", "user_id="+user.Id)
|
||||||
c.Err.StatusCode = http.StatusForbidden
|
c.Err.StatusCode = http.StatusForbidden
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
"UseLocalStorage": true,
|
"UseLocalStorage": true,
|
||||||
"StorageDirectory": "./data/",
|
"StorageDirectory": "./data/",
|
||||||
"AllowedLoginAttempts": 10,
|
"AllowedLoginAttempts": 10,
|
||||||
"DisableEmailSignUp": false,
|
|
||||||
"EnableOAuthServiceProvider": false
|
"EnableOAuthServiceProvider": false
|
||||||
},
|
},
|
||||||
"SqlSettings": {
|
"SqlSettings": {
|
||||||
@@ -51,14 +50,16 @@
|
|||||||
"InitialFont": "luximbi.ttf"
|
"InitialFont": "luximbi.ttf"
|
||||||
},
|
},
|
||||||
"EmailSettings": {
|
"EmailSettings": {
|
||||||
"ByPassEmail": true,
|
"AllowSignUpWithEmail": true,
|
||||||
|
"SendEmailNotifications": false,
|
||||||
|
"RequireEmailVerification": false,
|
||||||
|
"FeedbackName": "",
|
||||||
|
"FeedbackEmail": "",
|
||||||
"SMTPUsername": "",
|
"SMTPUsername": "",
|
||||||
"SMTPPassword": "",
|
"SMTPPassword": "",
|
||||||
"SMTPServer": "",
|
"SMTPServer": "",
|
||||||
"UseTLS": false,
|
"SMTPPort": "",
|
||||||
"UseStartTLS": false,
|
"ConnectionSecurity": "",
|
||||||
"FeedbackEmail": "",
|
|
||||||
"FeedbackName": "",
|
|
||||||
"ApplePushServer": "",
|
"ApplePushServer": "",
|
||||||
"ApplePushCertPublic": "",
|
"ApplePushCertPublic": "",
|
||||||
"ApplePushCertPrivate": ""
|
"ApplePushCertPrivate": ""
|
||||||
|
|||||||
@@ -403,6 +403,15 @@ func (c *Client) SaveConfig(config *Config) (*Result, *AppError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) TestEmail(config *Config) (*Result, *AppError) {
|
||||||
|
if r, err := c.DoApiPost("/admin/test_email", config.ToJson()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
|
func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/channels/create", channel.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/channels/create", channel.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ type ServiceSettings struct {
|
|||||||
UseLocalStorage bool
|
UseLocalStorage bool
|
||||||
StorageDirectory string
|
StorageDirectory string
|
||||||
AllowedLoginAttempts int
|
AllowedLoginAttempts int
|
||||||
DisableEmailSignUp bool
|
|
||||||
EnableOAuthServiceProvider bool
|
EnableOAuthServiceProvider bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,14 +72,18 @@ type ImageSettings struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EmailSettings struct {
|
type EmailSettings struct {
|
||||||
ByPassEmail bool
|
AllowSignUpWithEmail bool
|
||||||
SMTPUsername string
|
SendEmailNotifications bool
|
||||||
SMTPPassword string
|
RequireEmailVerification bool
|
||||||
SMTPServer string
|
FeedbackName string
|
||||||
UseTLS bool
|
FeedbackEmail string
|
||||||
UseStartTLS bool
|
SMTPUsername string
|
||||||
FeedbackEmail string
|
SMTPPassword string
|
||||||
FeedbackName string
|
SMTPServer string
|
||||||
|
SMTPPort string
|
||||||
|
ConnectionSecurity string
|
||||||
|
|
||||||
|
// For Future Use
|
||||||
ApplePushServer string
|
ApplePushServer string
|
||||||
ApplePushCertPublic string
|
ApplePushCertPublic string
|
||||||
ApplePushCertPrivate string
|
ApplePushCertPrivate string
|
||||||
|
|||||||
@@ -176,18 +176,24 @@ func getClientProperties(c *model.Config) map[string]string {
|
|||||||
props["BuildHash"] = model.BuildHash
|
props["BuildHash"] = model.BuildHash
|
||||||
|
|
||||||
props["SiteName"] = c.ServiceSettings.SiteName
|
props["SiteName"] = c.ServiceSettings.SiteName
|
||||||
props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail)
|
props["AnalyticsUrl"] = c.ServiceSettings.AnalyticsUrl
|
||||||
|
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
|
||||||
|
|
||||||
|
props["SendEmailNotifications"] = strconv.FormatBool(c.EmailSettings.SendEmailNotifications)
|
||||||
|
props["AllowSignUpWithEmail"] = strconv.FormatBool(c.EmailSettings.AllowSignUpWithEmail)
|
||||||
props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail
|
props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail
|
||||||
|
|
||||||
|
props["AllowSignUpWithGitLab"] = strconv.FormatBool(false)
|
||||||
|
|
||||||
props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
|
props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
|
||||||
props["AllowPublicLink"] = strconv.FormatBool(c.TeamSettings.AllowPublicLink)
|
props["AllowPublicLink"] = strconv.FormatBool(c.TeamSettings.AllowPublicLink)
|
||||||
|
|
||||||
props["SegmentDeveloperKey"] = c.ClientSettings.SegmentDeveloperKey
|
props["SegmentDeveloperKey"] = c.ClientSettings.SegmentDeveloperKey
|
||||||
props["GoogleDeveloperKey"] = c.ClientSettings.GoogleDeveloperKey
|
props["GoogleDeveloperKey"] = c.ClientSettings.GoogleDeveloperKey
|
||||||
props["AnalyticsUrl"] = c.ServiceSettings.AnalyticsUrl
|
|
||||||
props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail)
|
|
||||||
props["ProfileHeight"] = fmt.Sprintf("%v", c.ImageSettings.ProfileHeight)
|
props["ProfileHeight"] = fmt.Sprintf("%v", c.ImageSettings.ProfileHeight)
|
||||||
props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
|
props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
|
||||||
props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
|
props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
|
||||||
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
|
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
@@ -200,21 +206,6 @@ func IsS3Configured() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllowedAuthServices() []string {
|
|
||||||
authServices := []string{}
|
|
||||||
for name, service := range Cfg.SSOSettings {
|
|
||||||
if service.Allow {
|
|
||||||
authServices = append(authServices, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !Cfg.ServiceSettings.DisableEmailSignUp {
|
|
||||||
authServices = append(authServices, "email")
|
|
||||||
}
|
|
||||||
|
|
||||||
return authServices
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsServiceAllowed(s string) bool {
|
func IsServiceAllowed(s string) bool {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -15,43 +15,28 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckMailSettings() *model.AppError {
|
const (
|
||||||
if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
|
CONN_SECURITY_NONE = ""
|
||||||
return model.NewAppError("CheckMailSettings", "No email settings present, mail will not be sent", "")
|
CONN_SECURITY_TLS = "TLS"
|
||||||
}
|
CONN_SECURITY_STARTTLS = "STARTTLS"
|
||||||
conn, err := connectToSMTPServer()
|
)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
c, err2 := newSMTPClient(conn)
|
|
||||||
if err2 != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer c.Quit()
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func connectToSMTPServer() (net.Conn, *model.AppError) {
|
|
||||||
host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
|
|
||||||
|
|
||||||
|
func connectToSMTPServer(config *model.Config) (net.Conn, *model.AppError) {
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if Cfg.EmailSettings.UseTLS {
|
if config.EmailSettings.ConnectionSecurity == CONN_SECURITY_TLS {
|
||||||
tlsconfig := &tls.Config{
|
tlsconfig := &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
ServerName: host,
|
ServerName: config.EmailSettings.SMTPServer,
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err = tls.Dial("tcp", Cfg.EmailSettings.SMTPServer, tlsconfig)
|
conn, err = tls.Dial("tcp", config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort, tlsconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn, err = net.Dial("tcp", Cfg.EmailSettings.SMTPServer)
|
conn, err = net.Dial("tcp", config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("SendMail", "Failed to open connection", err.Error())
|
return nil, model.NewAppError("SendMail", "Failed to open connection", err.Error())
|
||||||
}
|
}
|
||||||
@@ -60,24 +45,23 @@ func connectToSMTPServer() (net.Conn, *model.AppError) {
|
|||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
|
func newSMTPClient(conn net.Conn, config *model.Config) (*smtp.Client, *model.AppError) {
|
||||||
host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
|
c, err := smtp.NewClient(conn, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort)
|
||||||
c, err := smtp.NewClient(conn, host)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l4g.Error("Failed to open a connection to SMTP server %v", err)
|
l4g.Error("Failed to open a connection to SMTP server %v", err)
|
||||||
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
||||||
}
|
}
|
||||||
// GO does not support plain auth over a non encrypted connection.
|
// GO does not support plain auth over a non encrypted connection.
|
||||||
// so if not tls then no auth
|
// so if not tls then no auth
|
||||||
auth := smtp.PlainAuth("", Cfg.EmailSettings.SMTPUsername, Cfg.EmailSettings.SMTPPassword, host)
|
auth := smtp.PlainAuth("", config.EmailSettings.SMTPUsername, config.EmailSettings.SMTPPassword, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort)
|
||||||
if Cfg.EmailSettings.UseTLS {
|
if config.EmailSettings.ConnectionSecurity == CONN_SECURITY_TLS {
|
||||||
if err = c.Auth(auth); err != nil {
|
if err = c.Auth(auth); err != nil {
|
||||||
return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
|
return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
|
||||||
}
|
}
|
||||||
} else if Cfg.EmailSettings.UseStartTLS {
|
} else if config.EmailSettings.ConnectionSecurity == CONN_SECURITY_TLS {
|
||||||
tlsconfig := &tls.Config{
|
tlsconfig := &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
ServerName: host,
|
ServerName: config.EmailSettings.SMTPServer,
|
||||||
}
|
}
|
||||||
c.StartTLS(tlsconfig)
|
c.StartTLS(tlsconfig)
|
||||||
if err = c.Auth(auth); err != nil {
|
if err = c.Auth(auth); err != nil {
|
||||||
@@ -88,12 +72,16 @@ func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SendMail(to, subject, body string) *model.AppError {
|
func SendMail(to, subject, body string) *model.AppError {
|
||||||
|
return SendMailUsingConfig(to, subject, body, Cfg)
|
||||||
|
}
|
||||||
|
|
||||||
if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
|
func SendMailUsingConfig(to, subject, body string, config *model.Config) *model.AppError {
|
||||||
|
|
||||||
|
if !config.EmailSettings.SendEmailNotifications {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fromMail := mail.Address{Cfg.EmailSettings.FeedbackName, Cfg.EmailSettings.FeedbackEmail}
|
fromMail := mail.Address{config.EmailSettings.FeedbackName, config.EmailSettings.FeedbackEmail}
|
||||||
toMail := mail.Address{"", to}
|
toMail := mail.Address{"", to}
|
||||||
|
|
||||||
headers := make(map[string]string)
|
headers := make(map[string]string)
|
||||||
@@ -110,13 +98,13 @@ func SendMail(to, subject, body string) *model.AppError {
|
|||||||
}
|
}
|
||||||
message += "\r\n<html><body>" + body + "</body></html>"
|
message += "\r\n<html><body>" + body + "</body></html>"
|
||||||
|
|
||||||
conn, err1 := connectToSMTPServer()
|
conn, err1 := connectToSMTPServer(config)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return err1
|
return err1
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
c, err2 := newSMTPClient(conn)
|
c, err2 := newSMTPClient(conn, config)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,148 @@
|
|||||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
var Client = require('../../utils/client.jsx');
|
||||||
|
var AsyncClient = require('../../utils/async_client.jsx');
|
||||||
|
|
||||||
export default class EmailSettings extends React.Component {
|
export default class EmailSettings extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.handleTestConnection = this.handleTestConnection.bind(this);
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
this.buildConfig = this.buildConfig.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
sendEmailNotifications: this.props.config.EmailSettings.SendEmailNotifications,
|
||||||
|
saveNeeded: false,
|
||||||
|
serverError: null,
|
||||||
|
emailSuccess: null,
|
||||||
|
emailFail: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChange(action) {
|
||||||
|
var s = {saveNeeded: true, serverError: this.state.serverError};
|
||||||
|
|
||||||
|
if (action === 'sendEmailNotifications_true') {
|
||||||
|
s.sendEmailNotifications = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'sendEmailNotifications_false') {
|
||||||
|
s.sendEmailNotifications = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildConfig() {
|
||||||
|
var config = this.props.config;
|
||||||
|
config.EmailSettings.AllowSignUpWithEmail = React.findDOMNode(this.refs.allowSignUpWithEmail).checked;
|
||||||
|
config.EmailSettings.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).checked;
|
||||||
|
config.EmailSettings.RequireEmailVerification = React.findDOMNode(this.refs.requireEmailVerification).checked;
|
||||||
|
config.EmailSettings.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).checked;
|
||||||
|
config.EmailSettings.FeedbackName = React.findDOMNode(this.refs.feedbackName).value.trim();
|
||||||
|
config.EmailSettings.FeedbackEmail = React.findDOMNode(this.refs.feedbackEmail).value.trim();
|
||||||
|
config.EmailSettings.SMTPServer = React.findDOMNode(this.refs.SMTPServer).value.trim();
|
||||||
|
config.EmailSettings.SMTPPort = React.findDOMNode(this.refs.SMTPPort).value.trim();
|
||||||
|
config.EmailSettings.SMTPUsername = React.findDOMNode(this.refs.SMTPUsername).value.trim();
|
||||||
|
config.EmailSettings.SMTPPassword = React.findDOMNode(this.refs.SMTPPassword).value.trim();
|
||||||
|
config.EmailSettings.ConnectionSecurity = React.findDOMNode(this.refs.ConnectionSecurity).value.trim();
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTestConnection(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('#connection-button').button('loading');
|
||||||
|
|
||||||
|
var config = this.buildConfig();
|
||||||
|
|
||||||
|
Client.testEmail(
|
||||||
|
config,
|
||||||
|
() => {
|
||||||
|
this.setState({
|
||||||
|
sendEmailNotifications: config.EmailSettings.SendEmailNotifications,
|
||||||
|
serverError: null,
|
||||||
|
saveNeeded: true,
|
||||||
|
emailSuccess: true,
|
||||||
|
emailFail: null
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
this.setState({
|
||||||
|
sendEmailNotifications: config.EmailSettings.SendEmailNotifications,
|
||||||
|
serverError: null,
|
||||||
|
saveNeeded: true,
|
||||||
|
emailSuccess: null,
|
||||||
|
emailFail: err.message + ' - ' + err.detailed_error
|
||||||
|
});
|
||||||
|
$('#connection-button').button('reset');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('#save-button').button('loading');
|
||||||
|
|
||||||
|
var config = this.buildConfig();
|
||||||
|
|
||||||
|
Client.saveConfig(
|
||||||
|
config,
|
||||||
|
() => {
|
||||||
|
AsyncClient.getConfig();
|
||||||
|
this.setState({
|
||||||
|
sendEmailNotifications: config.EmailSettings.SendEmailNotifications,
|
||||||
|
serverError: null,
|
||||||
|
saveNeeded: false,
|
||||||
|
emailSuccess: null,
|
||||||
|
emailFail: null
|
||||||
|
});
|
||||||
|
$('#save-button').button('reset');
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
this.setState({
|
||||||
|
sendEmailNotifications: config.EmailSettings.SendEmailNotifications,
|
||||||
|
serverError: err.message,
|
||||||
|
saveNeeded: true,
|
||||||
|
emailSuccess: null,
|
||||||
|
emailFail: null
|
||||||
|
});
|
||||||
|
$('#save-button').button('reset');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
var serverError = '';
|
||||||
|
if (this.state.serverError) {
|
||||||
|
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
var saveClass = 'btn';
|
||||||
|
if (this.state.saveNeeded) {
|
||||||
|
saveClass = 'btn btn-primary';
|
||||||
|
}
|
||||||
|
|
||||||
|
var emailSuccess = '';
|
||||||
|
if (this.state.emailSuccess) {
|
||||||
|
emailSuccess = (
|
||||||
|
<div className='alert alert-success'>
|
||||||
|
<i className='fa fa-check'></i>{'No errors were reported while sending an email. Please check your inbox to make sure.'}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var emailFail = '';
|
||||||
|
if (this.state.emailFail) {
|
||||||
|
emailSuccess = (
|
||||||
|
<div className='alert alert-warning'>
|
||||||
|
<i className='fa fa-warning'></i>{'Connection unsuccessful: ' + this.state.emailFail}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='wrapper--fixed'>
|
<div className='wrapper--fixed'>
|
||||||
<h3>{'Email Settings'}</h3>
|
<h3>{'Email Settings'}</h3>
|
||||||
@@ -17,149 +150,130 @@ export default class EmailSettings extends React.Component {
|
|||||||
className='form-horizontal'
|
className='form-horizontal'
|
||||||
role='form'
|
role='form'
|
||||||
>
|
>
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<label
|
<label
|
||||||
className='control-label col-sm-4'
|
className='control-label col-sm-4'
|
||||||
htmlFor='email'
|
htmlFor='allowSignUpWithEmail'
|
||||||
>
|
>
|
||||||
{'Bypass Email: '}
|
{'Allow Sign Up With Email: '}
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
data-trigger='hover click'
|
|
||||||
data-toggle='popover'
|
|
||||||
data-position='bottom'
|
|
||||||
data-content={'Here\'s some more help text inside a popover for the Bypass Email field just to show how popovers look.'}
|
|
||||||
>
|
|
||||||
{'(?)'}
|
|
||||||
</a>
|
|
||||||
</label>
|
</label>
|
||||||
<div className='col-sm-8'>
|
<div className='col-sm-8'>
|
||||||
<label className='radio-inline'>
|
<label className='radio-inline'>
|
||||||
<input
|
<input
|
||||||
type='radio'
|
type='radio'
|
||||||
name='byPassEmail'
|
name='allowSignUpWithEmail'
|
||||||
value='option1'
|
value='true'
|
||||||
|
ref='allowSignUpWithEmail'
|
||||||
|
defaultChecked={this.props.config.EmailSettings.AllowSignUpWithEmail}
|
||||||
|
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_true')}
|
||||||
/>
|
/>
|
||||||
{'True'}
|
{'true'}
|
||||||
</label>
|
</label>
|
||||||
<label className='radio-inline'>
|
<label className='radio-inline'>
|
||||||
<input
|
<input
|
||||||
type='radio'
|
type='radio'
|
||||||
name='byPassEmail'
|
name='allowSignUpWithEmail'
|
||||||
value='option2'
|
value='false'
|
||||||
|
defaultChecked={!this.props.config.EmailSettings.AllowSignUpWithEmail}
|
||||||
|
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_false')}
|
||||||
/>
|
/>
|
||||||
{'False'}
|
{'false'}
|
||||||
</label>
|
</label>
|
||||||
<p className='help-text'>{'This is some sample help text for the Bypass Email field'}</p>
|
<p className='help-text'>{'Typically set to true in production. When true Mattermost will allow team creation and account signup utilizing email and password. You would set this to false if you only wanted to allow signup from a service like OAuth or LDAP.'}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<label
|
<label
|
||||||
className='control-label col-sm-4'
|
className='control-label col-sm-4'
|
||||||
htmlFor='smtpUsername'
|
htmlFor='sendEmailNotifications'
|
||||||
>
|
>
|
||||||
{'SMTP Username:'}
|
{'Send Email Notifications: '}
|
||||||
</label>
|
</label>
|
||||||
<div className='col-sm-8'>
|
<div className='col-sm-8'>
|
||||||
<input
|
<label className='radio-inline'>
|
||||||
type='email'
|
<input
|
||||||
className='form-control'
|
type='radio'
|
||||||
id='smtpUsername'
|
name='sendEmailNotifications'
|
||||||
placeholder='Enter your SMTP username'
|
value='true'
|
||||||
value=''
|
ref='sendEmailNotifications'
|
||||||
/>
|
defaultChecked={this.props.config.EmailSettings.SendEmailNotifications}
|
||||||
<div className='help-text'>
|
onChange={this.handleChange.bind(this, 'sendEmailNotifications_true')}
|
||||||
<div className='alert alert-warning'><i className='fa fa-warning'></i>{' This is some error text for the Bypass Email field'}</div>
|
/>
|
||||||
</div>
|
{'true'}
|
||||||
<p className='help-text'>{'This is some sample help text for the SMTP username field'}</p>
|
</label>
|
||||||
|
<label className='radio-inline'>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
name='sendEmailNotifications'
|
||||||
|
value='false'
|
||||||
|
defaultChecked={!this.props.config.EmailSettings.SendEmailNotifications}
|
||||||
|
onChange={this.handleChange.bind(this, 'sendEmailNotifications_false')}
|
||||||
|
/>
|
||||||
|
{'false'}
|
||||||
|
</label>
|
||||||
|
<p className='help-text'>{'Typically set to true in production. When true Mattermost will attempt to send email notifications. Developers may set this field to false skipping sending emails for faster development.'}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<label
|
<label
|
||||||
className='control-label col-sm-4'
|
className='control-label col-sm-4'
|
||||||
htmlFor='smtpPassword'
|
htmlFor='requireEmailVerification'
|
||||||
>
|
>
|
||||||
{'SMTP Password:'}
|
{'Require Email Verification: '}
|
||||||
</label>
|
</label>
|
||||||
<div className='col-sm-8'>
|
<div className='col-sm-8'>
|
||||||
<input
|
<label className='radio-inline'>
|
||||||
type='password'
|
<input
|
||||||
className='form-control'
|
type='radio'
|
||||||
id='smtpPassword'
|
name='requireEmailVerification'
|
||||||
placeholder='Enter your SMTP password'
|
value='true'
|
||||||
value=''
|
ref='requireEmailVerification'
|
||||||
/>
|
defaultChecked={this.props.config.EmailSettings.RequireEmailVerification}
|
||||||
|
onChange={this.handleChange.bind(this, 'requireEmailVerification_true')}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
|
/>
|
||||||
|
{'true'}
|
||||||
|
</label>
|
||||||
|
<label className='radio-inline'>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
name='requireEmailVerification'
|
||||||
|
value='false'
|
||||||
|
defaultChecked={!this.props.config.EmailSettings.RequireEmailVerification}
|
||||||
|
onChange={this.handleChange.bind(this, 'requireEmailVerification_false')}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
|
/>
|
||||||
|
{'false'}
|
||||||
|
</label>
|
||||||
|
<p className='help-text'>{'Typically set to true in production. When true Mattermost will not allow a user to login without first having recieved an email with a verification link. Developers may set this field to false so skip sending verification emails for faster development.'}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<label
|
<label
|
||||||
className='control-label col-sm-4'
|
className='control-label col-sm-4'
|
||||||
htmlFor='smtpServer'
|
htmlFor='feedbackName'
|
||||||
>
|
>
|
||||||
{'SMTP Server:'}
|
{'Feedback Name:'}
|
||||||
</label>
|
</label>
|
||||||
<div className='col-sm-8'>
|
<div className='col-sm-8'>
|
||||||
<input
|
<input
|
||||||
type='text'
|
type='text'
|
||||||
className='form-control'
|
className='form-control'
|
||||||
id='smtpServer'
|
id='feedbackName'
|
||||||
placeholder='Enter your SMTP server'
|
ref='feedbackName'
|
||||||
value=''
|
placeholder='Ex: "Mattermost", "System", "John Smith"'
|
||||||
|
defaultValue={this.props.config.EmailSettings.FeedbackName}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
/>
|
/>
|
||||||
<div className='help-text'>
|
<p className='help-text'>{'Name displayed on email account used when sending notification emails from Mattermost.'}</p>
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
className='help-link'
|
|
||||||
>
|
|
||||||
{'Test Connection'}
|
|
||||||
</a>
|
|
||||||
<div className='alert alert-success'><i className='fa fa-check'></i>{' Connection successful'}</div>
|
|
||||||
<div className='alert alert-warning hide'><i className='fa fa-warning'></i>{' Connection unsuccessful'}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<label className='control-label col-sm-4'>{'Use TLS:'}</label>
|
|
||||||
<div className='col-sm-8'>
|
|
||||||
<label className='radio-inline'>
|
|
||||||
<input
|
|
||||||
type='radio'
|
|
||||||
name='tls'
|
|
||||||
value='option1'
|
|
||||||
/>
|
|
||||||
{'True'}
|
|
||||||
</label>
|
|
||||||
<label className='radio-inline'>
|
|
||||||
<input
|
|
||||||
type='radio'
|
|
||||||
name='tls'
|
|
||||||
value='option2'
|
|
||||||
/>
|
|
||||||
{'False'}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<label className='control-label col-sm-4'>{'Use Start TLS:'}</label>
|
|
||||||
<div className='col-sm-8'>
|
|
||||||
<label className='radio-inline'>
|
|
||||||
<input
|
|
||||||
type='radio'
|
|
||||||
name='starttls'
|
|
||||||
value='option1'
|
|
||||||
/>
|
|
||||||
{'True'}
|
|
||||||
</label>
|
|
||||||
<label className='radio-inline'>
|
|
||||||
<input
|
|
||||||
type='radio'
|
|
||||||
name='starttls'
|
|
||||||
value='option2'
|
|
||||||
/>
|
|
||||||
{'False'}
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<label
|
<label
|
||||||
className='control-label col-sm-4'
|
className='control-label col-sm-4'
|
||||||
@@ -169,143 +283,175 @@ export default class EmailSettings extends React.Component {
|
|||||||
</label>
|
</label>
|
||||||
<div className='col-sm-8'>
|
<div className='col-sm-8'>
|
||||||
<input
|
<input
|
||||||
type='text'
|
type='email'
|
||||||
className='form-control'
|
className='form-control'
|
||||||
id='feedbackEmail'
|
id='feedbackEmail'
|
||||||
placeholder='Enter your feedback email'
|
ref='feedbackEmail'
|
||||||
value=''
|
placeholder='Ex: "mattermost@yourcompany.com", "admin@yourcompany.com"'
|
||||||
|
defaultValue={this.props.config.EmailSettings.FeedbackEmail}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
/>
|
/>
|
||||||
|
<p className='help-text'>{'Email displayed on email account used when sending notification emails from Mattermost.'}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<label
|
<label
|
||||||
className='control-label col-sm-4'
|
className='control-label col-sm-4'
|
||||||
htmlFor='feedbackUsername'
|
htmlFor='SMTPUsername'
|
||||||
>
|
>
|
||||||
{'Feedback Username:'}
|
{'SMTP Username:'}
|
||||||
</label>
|
</label>
|
||||||
<div className='col-sm-8'>
|
<div className='col-sm-8'>
|
||||||
<input
|
<input
|
||||||
type='text'
|
type='text'
|
||||||
className='form-control'
|
className='form-control'
|
||||||
id='feedbackUsername'
|
id='SMTPUsername'
|
||||||
placeholder='Enter your feedback username'
|
ref='SMTPUsername'
|
||||||
value=''
|
placeholder='Ex: "admin@yourcompany.com", "AKIADTOVBGERKLCBV"'
|
||||||
|
defaultValue={this.props.config.EmailSettings.SMTPUsername}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
/>
|
/>
|
||||||
</div>
|
<p className='help-text'>{' Obtain this credential from administrator setting up your email server.'}</p>
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<div className='col-sm-offset-4 col-sm-8'>
|
|
||||||
<div className='checkbox'>
|
|
||||||
<label><input type='checkbox' />{'Remember me'}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className='form-group'>
|
||||||
className='panel-group'
|
<label
|
||||||
id='accordion'
|
className='control-label col-sm-4'
|
||||||
role='tablist'
|
htmlFor='SMTPPassword'
|
||||||
aria-multiselectable='true'
|
>
|
||||||
>
|
{'SMTP Password:'}
|
||||||
<div className='panel panel-default'>
|
</label>
|
||||||
<div
|
<div className='col-sm-8'>
|
||||||
className='panel-heading'
|
<input
|
||||||
role='tab'
|
type='text'
|
||||||
id='headingOne'
|
className='form-control'
|
||||||
|
id='SMTPPassword'
|
||||||
|
ref='SMTPPassword'
|
||||||
|
placeholder='Ex: "yourpassword", "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||||
|
defaultValue={this.props.config.EmailSettings.SMTPPassword}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
|
/>
|
||||||
|
<p className='help-text'>{' Obtain this credential from administrator setting up your email server.'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='form-group'>
|
||||||
|
<label
|
||||||
|
className='control-label col-sm-4'
|
||||||
|
htmlFor='SMTPServer'
|
||||||
|
>
|
||||||
|
{'SMTP Server:'}
|
||||||
|
</label>
|
||||||
|
<div className='col-sm-8'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='form-control'
|
||||||
|
id='SMTPServer'
|
||||||
|
ref='SMTPServer'
|
||||||
|
placeholder='Ex: "smtp.yourcompany.com", "email-smtp.us-east-1.amazonaws.com"'
|
||||||
|
defaultValue={this.props.config.EmailSettings.SMTPServer}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
|
/>
|
||||||
|
<p className='help-text'>{'Location of SMTP email server.'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='form-group'>
|
||||||
|
<label
|
||||||
|
className='control-label col-sm-4'
|
||||||
|
htmlFor='SMTPPort'
|
||||||
|
>
|
||||||
|
{'SMTP Port:'}
|
||||||
|
</label>
|
||||||
|
<div className='col-sm-8'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='form-control'
|
||||||
|
id='SMTPPort'
|
||||||
|
ref='SMTPPort'
|
||||||
|
placeholder='Ex: "25", "465"'
|
||||||
|
defaultValue={this.props.config.EmailSettings.SMTPPort}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
|
/>
|
||||||
|
<p className='help-text'>{'Port of SMTP email server.'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='form-group'>
|
||||||
|
<label
|
||||||
|
className='control-label col-sm-4'
|
||||||
|
htmlFor='ConnectionSecurity'
|
||||||
|
>
|
||||||
|
{'Connection Security:'}
|
||||||
|
</label>
|
||||||
|
<div className='col-sm-8'>
|
||||||
|
<select
|
||||||
|
className='form-control'
|
||||||
|
id='ConnectionSecurity'
|
||||||
|
ref='ConnectionSecurity'
|
||||||
|
defaultValue={this.props.config.EmailSettings.ConnectionSecurity}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.sendEmailNotifications}
|
||||||
>
|
>
|
||||||
<h3 className='panel-title'>
|
<option value=''>{'None'}</option>
|
||||||
<a
|
<option value='TLS'>{'TLS (Recommended)'}</option>
|
||||||
className='collapsed'
|
<option value='STARTTLS'>{'STARTTLS'}</option>
|
||||||
role='button'
|
</select>
|
||||||
data-toggle='collapse'
|
<div className='help-text'>
|
||||||
data-parent='#accordion'
|
<table
|
||||||
href='#collapseOne'
|
className='table-bordered'
|
||||||
aria-expanded='true'
|
cellPadding='5'
|
||||||
aria-controls='collapseOne'
|
>
|
||||||
>
|
<tr><td className='help-text'>{'None'}</td><td className='help-text'>{'Mattermost will send email over an unsecure connection.'}</td></tr>
|
||||||
{'Advanced Settings '}
|
<tr><td className='help-text'>{'TLS'}</td><td className='help-text'>{'Encrypts the communication between Mattermost and your email server.'}</td></tr>
|
||||||
<i className='fa fa-plus'></i>
|
<tr><td className='help-text'>{'STARTTLS'}</td><td className='help-text'>{'Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.'}</td></tr>
|
||||||
<i className='fa fa-minus'></i>
|
</table>
|
||||||
</a>
|
|
||||||
</h3>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className='help-text'>
|
||||||
id='collapseOne'
|
<button
|
||||||
className='panel-collapse collapse'
|
className='help-link'
|
||||||
role='tabpanel'
|
onClick={this.handleTestConnection}
|
||||||
aria-labelledby='headingOne'
|
disabled={!this.state.sendEmailNotifications}
|
||||||
>
|
id='connection-button'
|
||||||
<div className='panel-body'>
|
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Testing...'}
|
||||||
<div className='form-group'>
|
>
|
||||||
<label
|
{'Test Connection'}
|
||||||
className='control-label col-sm-4'
|
</button>
|
||||||
htmlFor='feedbackUsername'
|
{emailSuccess}
|
||||||
>
|
{emailFail}
|
||||||
{'Apple push server:'}
|
|
||||||
</label>
|
|
||||||
<div className='col-sm-8'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='form-control'
|
|
||||||
id='feedbackUsername'
|
|
||||||
placeholder='Enter your Apple push server'
|
|
||||||
value=''
|
|
||||||
/>
|
|
||||||
<p className='help-text'>{'This is some sample help text for the Apple push server field'}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<label
|
|
||||||
className='control-label col-sm-4'
|
|
||||||
htmlFor='feedbackUsername'
|
|
||||||
>
|
|
||||||
{'Apple push certificate public:'}
|
|
||||||
</label>
|
|
||||||
<div className='col-sm-8'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='form-control'
|
|
||||||
id='feedbackUsername'
|
|
||||||
placeholder='Enter your public apple push certificate'
|
|
||||||
value=''
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='form-group'>
|
|
||||||
<label
|
|
||||||
className='control-label col-sm-4'
|
|
||||||
htmlFor='feedbackUsername'
|
|
||||||
>
|
|
||||||
{'Apple push certificate private:'}
|
|
||||||
</label>
|
|
||||||
<div className='col-sm-8'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='form-control'
|
|
||||||
id='feedbackUsername'
|
|
||||||
placeholder='Enter your private apple push certificate'
|
|
||||||
value=''
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<div className='col-sm-12'>
|
<div className='col-sm-12'>
|
||||||
|
{serverError}
|
||||||
<button
|
<button
|
||||||
|
disabled={!this.state.saveNeeded}
|
||||||
type='submit'
|
type='submit'
|
||||||
className='btn btn-primary'
|
className={saveClass}
|
||||||
|
onClick={this.handleSubmit}
|
||||||
|
id='save-button'
|
||||||
|
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||||
>
|
>
|
||||||
{'Save'}
|
{'Save'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmailSettings.propTypes = {
|
||||||
|
config: React.PropTypes.object
|
||||||
|
};
|
||||||
@@ -12,13 +12,33 @@ export default class LogSettings extends React.Component {
|
|||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
consoleEnable: this.props.config.LogSettings.ConsoleEnable,
|
||||||
|
fileEnable: this.props.config.LogSettings.FileEnable,
|
||||||
saveNeeded: false,
|
saveNeeded: false,
|
||||||
serverError: null
|
serverError: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange() {
|
handleChange(action) {
|
||||||
this.setState({saveNeeded: true, serverError: this.state.serverError});
|
var s = {saveNeeded: true, serverError: this.state.serverError};
|
||||||
|
|
||||||
|
if (action === 'console_true') {
|
||||||
|
s.consoleEnable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'console_false') {
|
||||||
|
s.consoleEnable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'file_true') {
|
||||||
|
s.fileEnable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'file_false') {
|
||||||
|
s.fileEnable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(e) {
|
handleSubmit(e) {
|
||||||
@@ -37,11 +57,21 @@ export default class LogSettings extends React.Component {
|
|||||||
config,
|
config,
|
||||||
() => {
|
() => {
|
||||||
AsyncClient.getConfig();
|
AsyncClient.getConfig();
|
||||||
this.setState({serverError: null, saveNeeded: false});
|
this.setState({
|
||||||
|
consoleEnable: config.LogSettings.ConsoleEnable,
|
||||||
|
fileEnable: config.LogSettings.FileEnable,
|
||||||
|
serverError: null,
|
||||||
|
saveNeeded: false
|
||||||
|
});
|
||||||
$('#save-button').button('reset');
|
$('#save-button').button('reset');
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
this.setState({serverError: err.message, saveNeeded: true});
|
this.setState({
|
||||||
|
consoleEnable: config.LogSettings.ConsoleEnable,
|
||||||
|
fileEnable: config.LogSettings.FileEnable,
|
||||||
|
serverError: err.message,
|
||||||
|
saveNeeded: true
|
||||||
|
});
|
||||||
$('#save-button').button('reset');
|
$('#save-button').button('reset');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -81,7 +111,7 @@ export default class LogSettings extends React.Component {
|
|||||||
value='true'
|
value='true'
|
||||||
ref='consoleEnable'
|
ref='consoleEnable'
|
||||||
defaultChecked={this.props.config.LogSettings.ConsoleEnable}
|
defaultChecked={this.props.config.LogSettings.ConsoleEnable}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange.bind(this, 'console_true')}
|
||||||
/>
|
/>
|
||||||
{'true'}
|
{'true'}
|
||||||
</label>
|
</label>
|
||||||
@@ -91,7 +121,7 @@ export default class LogSettings extends React.Component {
|
|||||||
name='consoleEnable'
|
name='consoleEnable'
|
||||||
value='false'
|
value='false'
|
||||||
defaultChecked={!this.props.config.LogSettings.ConsoleEnable}
|
defaultChecked={!this.props.config.LogSettings.ConsoleEnable}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange.bind(this, 'console_false')}
|
||||||
/>
|
/>
|
||||||
{'false'}
|
{'false'}
|
||||||
</label>
|
</label>
|
||||||
@@ -113,6 +143,7 @@ export default class LogSettings extends React.Component {
|
|||||||
ref='consoleLevel'
|
ref='consoleLevel'
|
||||||
defaultValue={this.props.config.LogSettings.consoleLevel}
|
defaultValue={this.props.config.LogSettings.consoleLevel}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.consoleEnable}
|
||||||
>
|
>
|
||||||
<option value='DEBUG'>{'DEBUG'}</option>
|
<option value='DEBUG'>{'DEBUG'}</option>
|
||||||
<option value='INFO'>{'INFO'}</option>
|
<option value='INFO'>{'INFO'}</option>
|
||||||
@@ -136,7 +167,7 @@ export default class LogSettings extends React.Component {
|
|||||||
ref='fileEnable'
|
ref='fileEnable'
|
||||||
value='true'
|
value='true'
|
||||||
defaultChecked={this.props.config.LogSettings.FileEnable}
|
defaultChecked={this.props.config.LogSettings.FileEnable}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange.bind(this, 'file_true')}
|
||||||
/>
|
/>
|
||||||
{'true'}
|
{'true'}
|
||||||
</label>
|
</label>
|
||||||
@@ -146,7 +177,7 @@ export default class LogSettings extends React.Component {
|
|||||||
name='fileEnable'
|
name='fileEnable'
|
||||||
value='false'
|
value='false'
|
||||||
defaultChecked={!this.props.config.LogSettings.FileEnable}
|
defaultChecked={!this.props.config.LogSettings.FileEnable}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange.bind(this, 'file_false')}
|
||||||
/>
|
/>
|
||||||
{'false'}
|
{'false'}
|
||||||
</label>
|
</label>
|
||||||
@@ -168,6 +199,7 @@ export default class LogSettings extends React.Component {
|
|||||||
ref='fileLevel'
|
ref='fileLevel'
|
||||||
defaultValue={this.props.config.LogSettings.FileLevel}
|
defaultValue={this.props.config.LogSettings.FileLevel}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.fileEnable}
|
||||||
>
|
>
|
||||||
<option value='DEBUG'>{'DEBUG'}</option>
|
<option value='DEBUG'>{'DEBUG'}</option>
|
||||||
<option value='INFO'>{'INFO'}</option>
|
<option value='INFO'>{'INFO'}</option>
|
||||||
@@ -193,6 +225,7 @@ export default class LogSettings extends React.Component {
|
|||||||
placeholder='Enter your file location'
|
placeholder='Enter your file location'
|
||||||
defaultValue={this.props.config.LogSettings.FileLocation}
|
defaultValue={this.props.config.LogSettings.FileLocation}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.fileEnable}
|
||||||
/>
|
/>
|
||||||
<p className='help-text'>{'File to which log files are written. If blank, will be set to ./logs/mattermost.log. Log rotation is enabled and new files may be created in the same directory.'}</p>
|
<p className='help-text'>{'File to which log files are written. If blank, will be set to ./logs/mattermost.log. Log rotation is enabled and new files may be created in the same directory.'}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -214,6 +247,7 @@ export default class LogSettings extends React.Component {
|
|||||||
placeholder='Enter your file format'
|
placeholder='Enter your file format'
|
||||||
defaultValue={this.props.config.LogSettings.FileFormat}
|
defaultValue={this.props.config.LogSettings.FileFormat}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
disabled={!this.state.fileEnable}
|
||||||
/>
|
/>
|
||||||
<p className='help-text'>
|
<p className='help-text'>
|
||||||
{'Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'}
|
{'Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default class InviteMemberModal extends React.Component {
|
|||||||
emailErrors: {},
|
emailErrors: {},
|
||||||
firstNameErrors: {},
|
firstNameErrors: {},
|
||||||
lastNameErrors: {},
|
lastNameErrors: {},
|
||||||
emailEnabled: !global.window.config.ByPassEmail
|
emailEnabled: !global.window.config.SendEmailNotifications
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,10 +95,8 @@ export default class Login extends React.Component {
|
|||||||
focusEmail = true;
|
focusEmail = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const authServices = JSON.parse(this.props.authServices);
|
|
||||||
|
|
||||||
let loginMessage = [];
|
let loginMessage = [];
|
||||||
if (authServices.indexOf(Constants.GITLAB_SERVICE) !== -1) {
|
if (global.window.config.AllowSignUpWithGitLab) {
|
||||||
loginMessage.push(
|
loginMessage.push(
|
||||||
<a
|
<a
|
||||||
className='btn btn-custom-login gitlab'
|
className='btn btn-custom-login gitlab'
|
||||||
@@ -116,7 +114,7 @@ export default class Login extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let emailSignup;
|
let emailSignup;
|
||||||
if (authServices.indexOf(Constants.EMAIL_SERVICE) !== -1) {
|
if (global.window.config.AllowSignUpWithEmail) {
|
||||||
emailSignup = (
|
emailSignup = (
|
||||||
<div>
|
<div>
|
||||||
<div className={'form-group' + errorClass}>
|
<div className={'form-group' + errorClass}>
|
||||||
@@ -206,10 +204,8 @@ export default class Login extends React.Component {
|
|||||||
Login.defaultProps = {
|
Login.defaultProps = {
|
||||||
teamName: '',
|
teamName: '',
|
||||||
teamDisplayName: '',
|
teamDisplayName: '',
|
||||||
authServices: ''
|
|
||||||
};
|
};
|
||||||
Login.propTypes = {
|
Login.propTypes = {
|
||||||
teamName: React.PropTypes.string,
|
teamName: React.PropTypes.string,
|
||||||
teamDisplayName: React.PropTypes.string,
|
teamDisplayName: React.PropTypes.string,
|
||||||
authServices: React.PropTypes.string
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
const ChoosePage = require('./team_signup_choose_auth.jsx');
|
const ChoosePage = require('./team_signup_choose_auth.jsx');
|
||||||
const EmailSignUpPage = require('./team_signup_with_email.jsx');
|
const EmailSignUpPage = require('./team_signup_with_email.jsx');
|
||||||
const SSOSignupPage = require('./team_signup_with_sso.jsx');
|
const SSOSignupPage = require('./team_signup_with_sso.jsx');
|
||||||
const Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
|
|
||||||
export default class TeamSignUp extends React.Component {
|
export default class TeamSignUp extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -12,38 +12,32 @@ export default class TeamSignUp extends React.Component {
|
|||||||
|
|
||||||
this.updatePage = this.updatePage.bind(this);
|
this.updatePage = this.updatePage.bind(this);
|
||||||
|
|
||||||
if (props.services.length === 1) {
|
if (global.window.config.AllowSignUpWithEmail && global.window.config.AllowSignUpWithGitLab) {
|
||||||
if (props.services[0] === Constants.EMAIL_SERVICE) {
|
this.state = {page: 'choose'};
|
||||||
this.state = {page: 'email', service: ''};
|
} else if (global.window.config.AllowSignUpWithEmail) {
|
||||||
} else {
|
this.state = {page: 'email'};
|
||||||
this.state = {page: 'service', service: props.services[0]};
|
} else if (global.window.config.AllowSignUpWithGitLab) {
|
||||||
}
|
this.state = {page: 'gitlab'};
|
||||||
} else {
|
|
||||||
this.state = {page: 'choose', service: ''};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updatePage(page, service) {
|
|
||||||
this.setState({page: page, service: service});
|
updatePage(page) {
|
||||||
|
this.setState({page});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
if (this.state.page === 'choose') {
|
||||||
|
return (
|
||||||
|
<ChoosePage
|
||||||
|
updatePage={this.updatePage}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.state.page === 'email') {
|
if (this.state.page === 'email') {
|
||||||
return <EmailSignUpPage />;
|
return <EmailSignUpPage />;
|
||||||
} else if (this.state.page === 'service' && this.state.service !== '') {
|
} else if (this.state.page === 'gitlab') {
|
||||||
return <SSOSignupPage service={this.state.service} />;
|
return <SSOSignupPage service={Constants.GITLAB_SERVICE} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<ChoosePage
|
|
||||||
services={this.props.services}
|
|
||||||
updatePage={this.updatePage}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamSignUp.defaultProps = {
|
|
||||||
services: []
|
|
||||||
};
|
|
||||||
TeamSignUp.propTypes = {
|
|
||||||
services: React.PropTypes.array
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -161,11 +161,8 @@ export default class SignupUserComplete extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
// add options to log in using another service
|
|
||||||
var authServices = JSON.parse(this.props.authServices);
|
|
||||||
|
|
||||||
var signupMessage = [];
|
var signupMessage = [];
|
||||||
if (authServices.indexOf(Constants.GITLAB_SERVICE) >= 0) {
|
if (global.window.config.AllowSignUpWithGitLab) {
|
||||||
signupMessage.push(
|
signupMessage.push(
|
||||||
<a
|
<a
|
||||||
className='btn btn-custom-login gitlab'
|
className='btn btn-custom-login gitlab'
|
||||||
@@ -178,7 +175,7 @@ export default class SignupUserComplete extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var emailSignup;
|
var emailSignup;
|
||||||
if (authServices.indexOf(Constants.EMAIL_SERVICE) !== -1) {
|
if (global.window.config.AllowSignUpWithEmail) {
|
||||||
emailSignup = (
|
emailSignup = (
|
||||||
<div>
|
<div>
|
||||||
<div className='inner__content'>
|
<div className='inner__content'>
|
||||||
@@ -262,7 +259,6 @@ SignupUserComplete.defaultProps = {
|
|||||||
teamId: '',
|
teamId: '',
|
||||||
email: '',
|
email: '',
|
||||||
data: null,
|
data: null,
|
||||||
authServices: '',
|
|
||||||
teamDisplayName: ''
|
teamDisplayName: ''
|
||||||
};
|
};
|
||||||
SignupUserComplete.propTypes = {
|
SignupUserComplete.propTypes = {
|
||||||
@@ -271,6 +267,5 @@ SignupUserComplete.propTypes = {
|
|||||||
teamId: React.PropTypes.string,
|
teamId: React.PropTypes.string,
|
||||||
email: React.PropTypes.string,
|
email: React.PropTypes.string,
|
||||||
data: React.PropTypes.string,
|
data: React.PropTypes.string,
|
||||||
authServices: React.PropTypes.string,
|
|
||||||
teamDisplayName: React.PropTypes.string
|
teamDisplayName: React.PropTypes.string
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
var Constants = require('../utils/constants.jsx');
|
|
||||||
|
|
||||||
export default class ChooseAuthPage extends React.Component {
|
export default class ChooseAuthPage extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -10,7 +8,7 @@ export default class ChooseAuthPage extends React.Component {
|
|||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
var buttons = [];
|
var buttons = [];
|
||||||
if (this.props.services.indexOf(Constants.GITLAB_SERVICE) !== -1) {
|
if (global.window.config.AllowSignUpWithGitLab) {
|
||||||
buttons.push(
|
buttons.push(
|
||||||
<a
|
<a
|
||||||
className='btn btn-custom-login gitlab btn-full'
|
className='btn btn-custom-login gitlab btn-full'
|
||||||
@@ -18,17 +16,17 @@ export default class ChooseAuthPage extends React.Component {
|
|||||||
onClick={
|
onClick={
|
||||||
function clickGit(e) {
|
function clickGit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.updatePage('service', Constants.GITLAB_SERVICE);
|
this.props.updatePage('gitlab');
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span className='icon' />
|
<span className='icon' />
|
||||||
<span>Create new team with GitLab Account</span>
|
<span>{'Create new team with GitLab Account'}</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.services.indexOf(Constants.EMAIL_SERVICE) !== -1) {
|
if (global.window.config.AllowSignUpWithEmail) {
|
||||||
buttons.push(
|
buttons.push(
|
||||||
<a
|
<a
|
||||||
className='btn btn-custom-login email btn-full'
|
className='btn btn-custom-login email btn-full'
|
||||||
@@ -36,18 +34,18 @@ export default class ChooseAuthPage extends React.Component {
|
|||||||
onClick={
|
onClick={
|
||||||
function clickEmail(e) {
|
function clickEmail(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.updatePage('email', '');
|
this.props.updatePage('email');
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span className='fa fa-envelope' />
|
<span className='fa fa-envelope' />
|
||||||
<span>Create new team with email address</span>
|
<span>{'Create new team with email address'}</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttons.length === 0) {
|
if (buttons.length === 0) {
|
||||||
buttons = <span>No sign-up methods configured, please contact your system administrator.</span>;
|
buttons = <span>{'No sign-up methods configured, please contact your system administrator.'}</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -61,10 +59,6 @@ export default class ChooseAuthPage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChooseAuthPage.defaultProps = {
|
|
||||||
services: []
|
|
||||||
};
|
|
||||||
ChooseAuthPage.propTypes = {
|
ChooseAuthPage.propTypes = {
|
||||||
services: React.PropTypes.array,
|
|
||||||
updatePage: React.PropTypes.func
|
updatePage: React.PropTypes.func
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default class TeamSignupSendInvitesPage extends React.Component {
|
|||||||
this.submitSkip = this.submitSkip.bind(this);
|
this.submitSkip = this.submitSkip.bind(this);
|
||||||
this.keySubmit = this.keySubmit.bind(this);
|
this.keySubmit = this.keySubmit.bind(this);
|
||||||
this.state = {
|
this.state = {
|
||||||
emailEnabled: !global.window.config.ByPassEmail
|
emailEnabled: !global.window.config.SendEmailNotifications
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!this.state.emailEnabled) {
|
if (!this.state.emailEnabled) {
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ export default class UserSettingsGeneralTab extends React.Component {
|
|||||||
}
|
}
|
||||||
setupInitialState(props) {
|
setupInitialState(props) {
|
||||||
var user = props.user;
|
var user = props.user;
|
||||||
var emailEnabled = !global.window.config.ByPassEmail;
|
var emailEnabled = !global.window.config.SendEmailNotifications;
|
||||||
return {username: user.username, firstName: user.first_name, lastName: user.last_name, nickname: user.nickname,
|
return {username: user.username, firstName: user.first_name, lastName: user.last_name, nickname: user.nickname,
|
||||||
email: user.email, picture: null, loadingPicture: false, emailEnabled: emailEnabled};
|
email: user.email, picture: null, loadingPicture: false, emailEnabled: emailEnabled};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ function setupLoginPage(props) {
|
|||||||
<Login
|
<Login
|
||||||
teamDisplayName={props.TeamDisplayName}
|
teamDisplayName={props.TeamDisplayName}
|
||||||
teamName={props.TeamName}
|
teamName={props.TeamName}
|
||||||
authServices={props.AuthServices}
|
|
||||||
/>,
|
/>,
|
||||||
document.getElementById('login')
|
document.getElementById('login')
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,11 +3,9 @@
|
|||||||
|
|
||||||
var SignupTeam = require('../components/signup_team.jsx');
|
var SignupTeam = require('../components/signup_team.jsx');
|
||||||
|
|
||||||
function setupSignupTeamPage(props) {
|
function setupSignupTeamPage() {
|
||||||
var services = JSON.parse(props.AuthServices);
|
|
||||||
|
|
||||||
React.render(
|
React.render(
|
||||||
<SignupTeam services={services} />,
|
<SignupTeam />,
|
||||||
document.getElementById('signup-team')
|
document.getElementById('signup-team')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ function setupSignupUserCompletePage(props) {
|
|||||||
email={props.Email}
|
email={props.Email}
|
||||||
hash={props.Hash}
|
hash={props.Hash}
|
||||||
data={props.Data}
|
data={props.Data}
|
||||||
authServices={props.AuthServices}
|
|
||||||
/>,
|
/>,
|
||||||
document.getElementById('signup-user-complete')
|
document.getElementById('signup-user-complete')
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -334,6 +334,21 @@ export function saveConfig(config, success, error) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function testEmail(config, success, error) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/v1/admin/test_email',
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify(config),
|
||||||
|
success,
|
||||||
|
error: function onError(xhr, status, err) {
|
||||||
|
var e = handleError('testEmail', xhr, status, err);
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function getMeSynchronous(success, error) {
|
export function getMeSynchronous(success, error) {
|
||||||
var currentUser = null;
|
var currentUser = null;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|||||||
@@ -143,7 +143,6 @@ func root(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if len(c.Session.UserId) == 0 {
|
if len(c.Session.UserId) == 0 {
|
||||||
page := NewHtmlTemplatePage("signup_team", "Signup")
|
page := NewHtmlTemplatePage("signup_team", "Signup")
|
||||||
page.Props["AuthServices"] = model.ArrayToJson(utils.GetAllowedAuthServices())
|
|
||||||
page.Render(c, w)
|
page.Render(c, w)
|
||||||
} else {
|
} else {
|
||||||
page := NewHtmlTemplatePage("home", "Home")
|
page := NewHtmlTemplatePage("home", "Home")
|
||||||
@@ -159,7 +158,6 @@ func signup(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
page := NewHtmlTemplatePage("signup_team", "Signup")
|
page := NewHtmlTemplatePage("signup_team", "Signup")
|
||||||
page.Props["AuthServices"] = model.ArrayToJson(utils.GetAllowedAuthServices())
|
|
||||||
page.Render(c, w)
|
page.Render(c, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +189,6 @@ func login(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
page := NewHtmlTemplatePage("login", "Login")
|
page := NewHtmlTemplatePage("login", "Login")
|
||||||
page.Props["TeamDisplayName"] = team.DisplayName
|
page.Props["TeamDisplayName"] = team.DisplayName
|
||||||
page.Props["TeamName"] = teamName
|
page.Props["TeamName"] = teamName
|
||||||
page.Props["AuthServices"] = model.ArrayToJson(utils.GetAllowedAuthServices())
|
|
||||||
page.Render(c, w)
|
page.Render(c, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +274,6 @@ func signupUserComplete(c *api.Context, w http.ResponseWriter, r *http.Request)
|
|||||||
page.Props["TeamId"] = props["id"]
|
page.Props["TeamId"] = props["id"]
|
||||||
page.Props["Data"] = data
|
page.Props["Data"] = data
|
||||||
page.Props["Hash"] = hash
|
page.Props["Hash"] = hash
|
||||||
page.Props["AuthServices"] = model.ArrayToJson(utils.GetAllowedAuthServices())
|
|
||||||
page.Render(c, w)
|
page.Render(c, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user