Fixing merge
Этот коммит содержится в:
4
Makefile
4
Makefile
@@ -197,7 +197,7 @@ travis-init:
|
||||
build-container:
|
||||
@echo Building in container
|
||||
|
||||
docker run -e TRAVIS_BUILD_NUMBER=$(TRAVIS_BUILD_NUMBER) --link mattermost-mysql:mysql --link mattermost-postgres:postgres -v `pwd`:/go/src/github.com/mattermost/platform mattermost/builder:latest
|
||||
cd .. && docker run -e TRAVIS_BUILD_NUMBER=$(TRAVIS_BUILD_NUMBER) --link mattermost-mysql:mysql --link mattermost-postgres:postgres -v `pwd`:/go/src/github.com/mattermost mattermost/builder:latest
|
||||
|
||||
stop-docker:
|
||||
@echo Stopping docker containers
|
||||
@@ -255,7 +255,7 @@ nuke: | clean clean-docker
|
||||
|
||||
touch $@
|
||||
|
||||
.prepare-jsx:
|
||||
.prepare-jsx: web/react/package.json
|
||||
@echo Preparation for compiling jsx code
|
||||
|
||||
cd web/react/ && npm install
|
||||
|
||||
@@ -73,7 +73,9 @@ func logClient(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if lvl == "ERROR" {
|
||||
err := model.NewAppError("client", msg, "")
|
||||
err := &model.AppError{}
|
||||
err.Message = msg
|
||||
err.Where = "client"
|
||||
c.LogError(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestGetLogs(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestGetConfig(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -95,7 +95,7 @@ func TestSaveConfig(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -129,7 +129,7 @@ func TestEmailTest(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -157,7 +157,7 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -279,7 +279,7 @@ func TestGetPostCount(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -324,7 +324,7 @@ func TestUserCountsWithPostsByDay(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ func SetupBenchmark() (*model.Team, *model.User, *model.Channel) {
|
||||
|
||||
team := &model.Team{DisplayName: "Benchmark Team", Name: "z-z-" + model.NewId() + "a", Email: "benchmark@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "benchmark@test.com", Nickname: "Mr. Benchmarker", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Mr. Benchmarker", 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")
|
||||
|
||||
@@ -368,7 +368,7 @@ func getChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
// user is already in the team
|
||||
|
||||
if result := <-Srv.Store.Channel().GetChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil {
|
||||
if result.Err.Message == "No channels were found" { // store translation dependant
|
||||
if result.Err.Id == "store.sql_channel.get_channels.not_found.app_error" {
|
||||
// lets make sure the user is valid
|
||||
if result := <-Srv.Store.User().Get(c.Session.UserId); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
|
||||
@@ -138,7 +138,7 @@ func BenchmarkJoinChannel(b *testing.B) {
|
||||
}
|
||||
|
||||
// Secondary test user to join channels created by primary test user
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "random@test.com", Nickname: "That Guy", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "That Guy", 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")
|
||||
|
||||
@@ -22,7 +22,7 @@ func TestCreateChannel(t *testing.T) {
|
||||
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -99,11 +99,11 @@ func TestCreateDirectChannel(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -158,11 +158,11 @@ func TestUpdateChannel(t *testing.T) {
|
||||
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
|
||||
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
|
||||
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
|
||||
userStd.Roles = ""
|
||||
@@ -236,7 +236,7 @@ func TestUpdateChannelHeader(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -276,7 +276,7 @@ func TestUpdateChannelHeader(t *testing.T) {
|
||||
t.Fatal("should have errored on bad channel header")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -295,7 +295,7 @@ func TestUpdateChannelPurpose(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -335,7 +335,7 @@ func TestUpdateChannelPurpose(t *testing.T) {
|
||||
t.Fatal("should have errored on bad channel purpose")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -354,7 +354,7 @@ func TestGetChannel(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -417,7 +417,7 @@ func TestGetMoreChannel(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -429,7 +429,7 @@ func TestGetMoreChannel(t *testing.T) {
|
||||
channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -461,7 +461,7 @@ func TestGetChannelCounts(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -502,7 +502,7 @@ func TestJoinChannel(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -514,7 +514,7 @@ func TestJoinChannel(t *testing.T) {
|
||||
channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
|
||||
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -530,7 +530,7 @@ func TestJoinChannel(t *testing.T) {
|
||||
data["user_id"] = user1.Id
|
||||
rchannel := Client.Must(Client.CreateDirectChannel(data)).Data.(*model.Channel)
|
||||
|
||||
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
|
||||
Client.LoginByEmail(team.Name, user3.Email, "pwd")
|
||||
@@ -546,7 +546,7 @@ func TestLeaveChannel(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -558,7 +558,7 @@ func TestLeaveChannel(t *testing.T) {
|
||||
channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
|
||||
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -599,7 +599,7 @@ func TestDeleteChannel(t *testing.T) {
|
||||
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
|
||||
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
|
||||
|
||||
@@ -631,7 +631,7 @@ func TestDeleteChannel(t *testing.T) {
|
||||
t.Fatal("should have failed to post to deleted channel")
|
||||
}
|
||||
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
|
||||
|
||||
@@ -665,7 +665,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -701,7 +701,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
|
||||
Client2 := model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "tester2@test.com", Nickname: "Tester 2", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Tester 2", Password: "pwd"}
|
||||
user2 = Client2.Must(Client2.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -789,7 +789,7 @@ func TestAddChannelMember(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -798,7 +798,7 @@ func TestAddChannelMember(t *testing.T) {
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -851,7 +851,7 @@ func TestRemoveChannelMember(t *testing.T) {
|
||||
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
|
||||
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
|
||||
|
||||
@@ -867,7 +867,7 @@ func TestRemoveChannelMember(t *testing.T) {
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
|
||||
|
||||
@@ -917,7 +917,7 @@ func TestUpdateNotifyProps(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -1019,7 +1019,7 @@ func TestUpdateNotifyProps(t *testing.T) {
|
||||
t.Fatal("Should have errored - bad mark unread level")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
@@ -1039,7 +1039,7 @@ func TestFuzzyChannel(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ func TestListCommands(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -111,7 +111,7 @@ func TestListTeamCommands(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -182,7 +182,7 @@ func TestDeleteCommand(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -219,7 +219,7 @@ func TestTestCommand(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ type Page struct {
|
||||
User *model.User
|
||||
Team *model.Team
|
||||
Channel *model.Channel
|
||||
Preferences *model.Preferences
|
||||
PostID string
|
||||
SessionTokenIndex int64
|
||||
Locale string
|
||||
|
||||
@@ -398,13 +398,6 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.Err = model.NewLocAppError("getFile", "api.file.get_file.public_invalid.app_error", nil, "")
|
||||
return
|
||||
}
|
||||
props := model.MapFromJson(strings.NewReader(data))
|
||||
|
||||
t, err := strconv.ParseInt(props["time"], 10, 64)
|
||||
if err != nil || model.GetMillis()-t > 1000*60*60*24*7 { // one week
|
||||
c.Err = model.NewLocAppError("getFile", "api.file.get_file.public_expired.app_error", nil, "")
|
||||
return
|
||||
}
|
||||
} else if !c.HasPermissionsToChannel(cchan, "getFile") {
|
||||
return
|
||||
}
|
||||
@@ -484,7 +477,6 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
newProps := make(map[string]string)
|
||||
newProps["filename"] = filename
|
||||
newProps["time"] = fmt.Sprintf("%v", model.GetMillis())
|
||||
|
||||
data := model.MapToJson(newProps)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt))
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestUploadFile(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -142,7 +142,7 @@ func TestGetFile(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -212,7 +212,7 @@ func TestGetFile(t *testing.T) {
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user2 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team2.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -320,11 +320,11 @@ func TestGetPublicLink(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
@@ -65,13 +64,13 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
license = model.LicenseFromJson(strings.NewReader(licenseStr))
|
||||
|
||||
if result := <-Srv.Store.User().AnalyticsUniqueUserCount(""); result.Err != nil {
|
||||
c.Err = model.NewAppError("addLicense", "Unable to count total unique users.", fmt.Sprintf("err=%v", result.Err.Error()))
|
||||
c.Err = model.NewLocAppError("addLicense", "api.license.add_license.invalid_count.app_error", nil, result.Err.Error())
|
||||
return
|
||||
} else {
|
||||
uniqueUserCount := result.Data.(int64)
|
||||
|
||||
if uniqueUserCount > int64(*license.Features.Users) {
|
||||
c.Err = model.NewAppError("addLicense", fmt.Sprintf("This license only supports %d users, when your system has %d unique users. Unique users are counted distinctly by email address. You can see total user count under Site Reports -> View Statistics.", *license.Features.Users, uniqueUserCount), "")
|
||||
c.Err = model.NewLocAppError("addLicense", "api.license.add_license.unique_users.app_error", map[string]interface{}{"Users": *license.Features.Users, "Count": uniqueUserCount}, "")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ func TestRegisterApp(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
@@ -75,7 +75,7 @@ func TestAllowOAuth(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
|
||||
@@ -698,6 +698,7 @@ func sendNotificationsAndForget(c *Context, post *model.Post, team *model.Team,
|
||||
|
||||
message := model.NewMessage(c.Session.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")
|
||||
|
||||
@@ -21,11 +21,11 @@ func TestCreatePost(t *testing.T) {
|
||||
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -103,7 +103,7 @@ func TestCreatePost(t *testing.T) {
|
||||
t.Fatal("Should have been forbidden")
|
||||
}
|
||||
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
@@ -132,11 +132,11 @@ func TestUpdatePost(t *testing.T) {
|
||||
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -200,7 +200,7 @@ func TestGetPosts(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -265,7 +265,7 @@ func TestGetPostsSince(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -335,7 +335,7 @@ func TestGetPostsBeforeAfter(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -412,7 +412,7 @@ func TestSearchPosts(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -462,7 +462,7 @@ func TestSearchHashtagPosts(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -493,7 +493,7 @@ func TestSearchPostsInChannel(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -575,7 +575,7 @@ func TestSearchPostsFromUser(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -590,7 +590,7 @@ func TestSearchPostsFromUser(t *testing.T) {
|
||||
post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
|
||||
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -601,13 +601,11 @@ func TestSearchPostsFromUser(t *testing.T) {
|
||||
post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
|
||||
post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
|
||||
|
||||
// includes "X has joined the channel" messages for both user2 and user3
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user1.Username)).Data.(*model.PostList); len(result.Order) != 1 {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 {
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 1 {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
@@ -615,11 +613,14 @@ func TestSearchPostsFromUser(t *testing.T) {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
post3 := &model.Post{ChannelId: channel1.Id, Message: "hullo"}
|
||||
post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " in:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 1 {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
@@ -630,19 +631,22 @@ func TestSearchPostsFromUser(t *testing.T) {
|
||||
// wait for the join/leave messages to be created for user3 since they're done asynchronously
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 {
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 2 {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username)).Data.(*model.PostList); len(result.Order) != 5 {
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username)).Data.(*model.PostList); len(result.Order) != 2 {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name)).Data.(*model.PostList); len(result.Order) != 3 {
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name)).Data.(*model.PostList); len(result.Order) != 1 {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name + " joined")).Data.(*model.PostList); len(result.Order) != 2 {
|
||||
post4 := &model.Post{ChannelId: channel2.Id, Message: "coconut"}
|
||||
post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
|
||||
|
||||
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " from: " + user3.Username + " in:" + channel2.Name + " coconut")).Data.(*model.PostList); len(result.Order) != 1 {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
}
|
||||
@@ -653,7 +657,7 @@ func TestGetPostsCache(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -706,7 +710,7 @@ func TestDeletePosts(t *testing.T) {
|
||||
userAdmin = Client.Must(Client.CreateUser(userAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userAdmin.Id))
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -763,7 +767,7 @@ func TestEmailMention(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: "corey+test@test.com", Nickname: "Bob Bobby", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: "success+test@simulator.amazonses.com", Nickname: "Bob Bobby", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -785,7 +789,7 @@ func TestFuzzyPosts(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -812,11 +816,11 @@ func TestMakeDirectChannelVisible(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ func TestGetAllPreferences(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -68,7 +68,7 @@ func TestSetPreferences(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -99,7 +99,7 @@ func TestSetPreferences(t *testing.T) {
|
||||
}
|
||||
|
||||
// not able to update as a different user
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -116,11 +116,11 @@ func TestGetPreferenceCategory(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -172,7 +172,7 @@ func TestGetPreference(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var invNum int64 = 0
|
||||
for i, invite := range invites.Invites {
|
||||
if result := <-Srv.Store.User().GetByEmail(c.Session.TeamId, invite["email"]); result.Err == nil || result.Err.Message != store.MISSING_ACCOUNT_ERROR {
|
||||
if result := <-Srv.Store.User().GetByEmail(c.Session.TeamId, invite["email"]); result.Err == nil || result.Err.Id != store.MISSING_ACCOUNT_ERROR {
|
||||
invNum = int64(i)
|
||||
c.Err = model.NewLocAppError("invite_members", "api.team.invite_members.already.app_error", nil, strconv.FormatInt(invNum, 10))
|
||||
return
|
||||
|
||||
@@ -25,7 +25,7 @@ func TestCreateFromSignupTeam(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
props := make(map[string]string)
|
||||
props["email"] = strings.ToLower(model.NewId()) + "corey+test@test.com"
|
||||
props["email"] = strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com"
|
||||
props["name"] = "Test Company name"
|
||||
props["time"] = fmt.Sprintf("%v", model.GetMillis())
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestCreateFromSignupTeam(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
|
||||
|
||||
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"corey+test@test.com"}, Data: data, Hash: hash}
|
||||
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"success+test@simulator.amazonses.com"}, Data: data, Hash: hash}
|
||||
|
||||
rts, err := Client.CreateTeamFromSignup(&ts)
|
||||
if err != nil {
|
||||
@@ -77,7 +77,7 @@ func TestCreateTeam(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user := &model.User{TeamId: rteam.Data.(*model.Team).Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: rteam.Data.(*model.Team).Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -114,7 +114,7 @@ func TestFindTeamByEmail(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -141,7 +141,7 @@ func TestGetAllTeams(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -174,7 +174,7 @@ func TestTeamPermDelete(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -217,7 +217,7 @@ func TestFindTeamByDomain(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -257,7 +257,7 @@ func TestFindTeamByEmailSend(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.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")
|
||||
@@ -282,14 +282,14 @@ func TestInviteMembers(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.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")
|
||||
|
||||
invite := make(map[string]string)
|
||||
invite["email"] = model.NewId() + "corey+test@test.com"
|
||||
invite["email"] = model.NewId() + "success+test@simulator.amazonses.com"
|
||||
invite["first_name"] = "Test"
|
||||
invite["last_name"] = "Guy"
|
||||
invites := &model.Invites{Invites: []map[string]string{invite}}
|
||||
@@ -315,7 +315,7 @@ func TestUpdateTeamDisplayName(t *testing.T) {
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -368,7 +368,7 @@ func TestGetMyTeam(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
|
||||
47
api/user.go
47
api/user.go
@@ -48,6 +48,7 @@ func InitUser(r *mux.Router) {
|
||||
sr.Handle("/logout", ApiUserRequired(logout)).Methods("POST")
|
||||
sr.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST")
|
||||
sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST")
|
||||
sr.Handle("/attach_device", ApiUserRequired(attachDeviceId)).Methods("POST")
|
||||
sr.Handle("/switch_to_sso", ApiAppHandler(switchToSSO)).Methods("POST")
|
||||
sr.Handle("/switch_to_email", ApiUserRequired(switchToEmail)).Methods("POST")
|
||||
|
||||
@@ -546,7 +547,6 @@ func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthWebInDays)
|
||||
}
|
||||
@@ -718,6 +718,49 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(model.MapToJson(props)))
|
||||
}
|
||||
|
||||
func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
deviceId := props["device_id"]
|
||||
if len(deviceId) == 0 {
|
||||
c.SetInvalidParam("attachDevice", "deviceId")
|
||||
return
|
||||
}
|
||||
|
||||
if !(strings.HasPrefix(deviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(deviceId, model.PUSH_NOTIFY_ANDROID+":")) {
|
||||
c.SetInvalidParam("attachDevice", "deviceId")
|
||||
return
|
||||
}
|
||||
|
||||
// A special case where we logout of all other sessions with the same Id
|
||||
if result := <-Srv.Store.Session().GetSessions(c.Session.UserId); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
} else {
|
||||
sessions := result.Data.([]*model.Session)
|
||||
for _, session := range sessions {
|
||||
if session.DeviceId == deviceId && session.Id != c.Session.Id {
|
||||
l4g.Debug(utils.T("api.user.login.revoking.app_error"), session.Id, c.Session.UserId)
|
||||
RevokeSessionById(c, session.Id)
|
||||
if c.Err != nil {
|
||||
c.LogError(c.Err)
|
||||
c.Err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionCache.Remove(c.Session.Token)
|
||||
|
||||
if result := <-Srv.Store.Session().UpdateDeviceId(c.Session.Id, deviceId); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(deviceId))
|
||||
}
|
||||
|
||||
func RevokeSessionById(c *Context, sessionId string) {
|
||||
if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
@@ -1114,7 +1157,7 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
path := "teams/" + c.Session.TeamId + "/users/" + c.Session.UserId + "/profile.png"
|
||||
|
||||
if err := writeFile(buf.Bytes(), path); err != nil {
|
||||
c.Err = model.NewAppError("uploadProfileImage", "Couldn't upload profile image", "")
|
||||
c.Err = model.NewLocAppError("uploadProfileImage", "api.user.upload_profile_user.upload_profile.app_error", nil, "")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestCreateUser(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "hello"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "hello"}
|
||||
|
||||
ruser, err := Client.CreateUser(&user, "")
|
||||
if err != nil {
|
||||
@@ -79,7 +79,7 @@ func TestCreateUserAllowedDomains(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE, AllowedDomains: "spinpunch.com, @nowh.com,@hello.com"}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "hello"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "hello"}
|
||||
|
||||
_, err := Client.CreateUser(&user, "")
|
||||
if err == nil {
|
||||
@@ -99,7 +99,7 @@ func TestLogin(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
@@ -139,7 +139,7 @@ func TestLogin(t *testing.T) {
|
||||
team2 := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE}
|
||||
rteam2 := Client.Must(Client.CreateTeam(&team2))
|
||||
|
||||
user2 := model.User{TeamId: rteam2.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{TeamId: rteam2.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
|
||||
if _, err := Client.CreateUserFromSignup(&user2, "junk", "1231312"); err == nil {
|
||||
t.Fatal("Should have errored, signed up without hashed email")
|
||||
@@ -168,7 +168,7 @@ func TestLoginWithDeviceId(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
@@ -199,7 +199,7 @@ func TestSessions(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
@@ -251,18 +251,18 @@ func TestGetUser(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser2, _ := Client.CreateUser(&user2, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Data.(*model.User).Id))
|
||||
|
||||
team2 := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam2, _ := Client.CreateTeam(&team2)
|
||||
|
||||
user3 := model.User{TeamId: rteam2.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 := model.User{TeamId: rteam2.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser3, _ := Client.CreateUser(&user3, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser3.Data.(*model.User).Id))
|
||||
|
||||
@@ -343,7 +343,7 @@ func TestGetAudits(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
@@ -396,7 +396,7 @@ func TestUserCreateImage(t *testing.T) {
|
||||
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: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -430,7 +430,7 @@ func TestUserUploadProfileImage(t *testing.T) {
|
||||
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: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -536,7 +536,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
|
||||
time1 := model.GetMillis()
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd", LastActivityAt: time1, LastPingAt: time1, Roles: ""}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", LastActivityAt: time1, LastPingAt: time1, Roles: ""}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -592,7 +592,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -611,7 +611,7 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
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: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -654,7 +654,7 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
@@ -674,7 +674,7 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -734,6 +734,34 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserUpdateDeviceId(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: "test@nowhere.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")
|
||||
deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890"
|
||||
|
||||
if _, err := Client.AttachDeviceId(deviceId); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.Session().GetSessions(user.Id); result.Err != nil {
|
||||
t.Fatal(result.Err)
|
||||
} else {
|
||||
sessions := result.Data.([]*model.Session)
|
||||
|
||||
if sessions[0].DeviceId != deviceId {
|
||||
t.Fatal("Missing device Id")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserUpdateActive(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
@@ -744,7 +772,7 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -804,7 +832,7 @@ func TestUserPermDelete(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
@@ -843,7 +871,7 @@ func TestSendPasswordReset(t *testing.T) {
|
||||
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: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -876,7 +904,7 @@ func TestSendPasswordReset(t *testing.T) {
|
||||
t.Fatal("Should have errored - bad name")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", AuthData: "1", AuthService: "random"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", AuthData: "1", AuthService: "random"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -893,7 +921,7 @@ func TestResetPassword(t *testing.T) {
|
||||
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: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -970,7 +998,7 @@ func TestResetPassword(t *testing.T) {
|
||||
t.Fatal("Should have errored - domain team doesn't match user team")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", AuthData: "1", AuthService: "random"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", AuthData: "1", AuthService: "random"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -991,7 +1019,7 @@ func TestUserUpdateNotify(t *testing.T) {
|
||||
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: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd", Roles: ""}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", Roles: ""}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -1086,11 +1114,11 @@ func TestStatuses(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser2 := Client.Must(Client.CreateUser(&user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Id))
|
||||
|
||||
@@ -1123,7 +1151,7 @@ func TestSwitchToSSO(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
@@ -1172,11 +1200,11 @@ func TestSwitchToEmail(t *testing.T) {
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser2 := Client.Must(Client.CreateUser(&user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Id))
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestSocket(t *testing.T) {
|
||||
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)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
@@ -39,7 +39,7 @@ func TestSocket(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
@@ -25,7 +25,7 @@ func TestCreateIncomingHook(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestListIncomingHooks(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -150,7 +150,7 @@ func TestDeleteIncomingHook(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -202,7 +202,7 @@ func TestCreateOutgoingHook(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -277,7 +277,7 @@ func TestListOutgoingHooks(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -327,7 +327,7 @@ func TestDeleteOutgoingHook(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -379,7 +379,7 @@ func TestRegenOutgoingHookToken(t *testing.T) {
|
||||
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@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
|
||||
1168
i18n/en.json
1168
i18n/en.json
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
1158
i18n/es.json
1158
i18n/es.json
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -58,9 +58,9 @@ func main() {
|
||||
|
||||
pwd, _ := os.Getwd()
|
||||
l4g.Info(utils.T("mattermost.current_version"), model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash)
|
||||
l4g.Info("Enterprise Enabled: %v", model.BuildEnterpriseReady)
|
||||
l4g.Info("Current working directory is %v", pwd)
|
||||
l4g.Info("Loaded config file from %v", utils.FindConfigFile(flagConfigFile))
|
||||
l4g.Info(utils.T("mattermost.entreprise_enabled"), model.BuildEnterpriseReady)
|
||||
l4g.Info(utils.T("mattermost.working_dir"), pwd)
|
||||
l4g.Info(utils.T("mattermost.config_file"), utils.FindConfigFile(flagConfigFile))
|
||||
|
||||
api.NewServer()
|
||||
api.InitApi()
|
||||
@@ -118,7 +118,7 @@ func runSecurityAndDiagnosticsJobAndForget() {
|
||||
currentTime := model.GetMillis()
|
||||
|
||||
if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
|
||||
l4g.Debug("Checking for security update from Mattermost")
|
||||
l4g.Debug(utils.T("mattermost.security_checks.debug"))
|
||||
|
||||
v := url.Values{}
|
||||
|
||||
@@ -152,7 +152,7 @@ func runSecurityAndDiagnosticsJobAndForget() {
|
||||
|
||||
res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
|
||||
if err != nil {
|
||||
l4g.Error("Failed to get security update information from Mattermost.")
|
||||
l4g.Error(utils.T("mattermost.security_info.error"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -162,27 +162,27 @@ func runSecurityAndDiagnosticsJobAndForget() {
|
||||
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.")
|
||||
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("Failed to get security bulletin details")
|
||||
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("Failed to read security bulletin details")
|
||||
l4g.Error(utils.T("mattermost.security_bulletin_read.error"))
|
||||
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))
|
||||
l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email)
|
||||
utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ func cmdCreateTeam() {
|
||||
|
||||
api.CreateTeam(c, team)
|
||||
if c.Err != nil {
|
||||
if c.Err.Message != "A team with that domain already exists" {
|
||||
if c.Err.Id != "store.sql_team.save.domain_exists.app_error" {
|
||||
l4g.Error("%v", c.Err)
|
||||
flushLogAndExit(1)
|
||||
}
|
||||
@@ -313,7 +313,7 @@ func cmdCreateUser() {
|
||||
|
||||
_, err := api.CreateUser(team, user)
|
||||
if err != nil {
|
||||
if err.Message != "An account with that email already exists." {
|
||||
if err.Id != "store.sql_user.save.email_exists.app_error" {
|
||||
l4g.Error("%v", err)
|
||||
flushLogAndExit(1)
|
||||
}
|
||||
|
||||
@@ -820,6 +820,17 @@ func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) AttachDeviceId(deviceId string) (*Result, *AppError) {
|
||||
data := make(map[string]string)
|
||||
data["device_id"] = deviceId
|
||||
if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) {
|
||||
data := make(map[string]string)
|
||||
data["user_id"] = userId
|
||||
|
||||
@@ -20,12 +20,7 @@ func splitWordsNoQuotes(text string) []string {
|
||||
words := []string{}
|
||||
|
||||
for _, word := range strings.Fields(text) {
|
||||
word = puncStart.ReplaceAllString(word, "")
|
||||
word = puncEnd.ReplaceAllString(word, "")
|
||||
|
||||
if len(word) != 0 {
|
||||
words = append(words, word)
|
||||
}
|
||||
words = append(words, word)
|
||||
}
|
||||
|
||||
return words
|
||||
@@ -94,7 +89,16 @@ func parseSearchFlags(input []string) ([]string, [][2]string) {
|
||||
}
|
||||
|
||||
if !isFlag {
|
||||
words = append(words, word)
|
||||
// trim off surrounding punctuation
|
||||
word = puncStart.ReplaceAllString(word, "")
|
||||
word = puncEnd.ReplaceAllString(word, "")
|
||||
|
||||
// and remove extra pound #s
|
||||
word = hashtagStart.ReplaceAllString(word, "#")
|
||||
|
||||
if len(word) != 0 {
|
||||
words = append(words, word)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,19 +118,19 @@ func TestParseSearchFlags(t *testing.T) {
|
||||
t.Fatalf("got incorrect flags %v", flags)
|
||||
}
|
||||
|
||||
if words, flags := parseSearchFlags(splitWords("fruit: cherry")); len(words) != 2 || words[0] != "fruit:" || words[1] != "cherry" {
|
||||
if words, flags := parseSearchFlags(splitWords("fruit: cherry")); len(words) != 2 || words[0] != "fruit" || words[1] != "cherry" {
|
||||
t.Fatalf("got incorrect words %v", words)
|
||||
} else if len(flags) != 0 {
|
||||
t.Fatalf("got incorrect flags %v", flags)
|
||||
}
|
||||
|
||||
if words, flags := parseSearchFlags(splitWords("channel:")); len(words) != 1 || words[0] != "channel:" {
|
||||
if words, flags := parseSearchFlags(splitWords("channel:")); len(words) != 1 || words[0] != "channel" {
|
||||
t.Fatalf("got incorrect words %v", words)
|
||||
} else if len(flags) != 0 {
|
||||
t.Fatalf("got incorrect flags %v", flags)
|
||||
}
|
||||
|
||||
if words, flags := parseSearchFlags(splitWords("channel: first in: second from:")); len(words) != 1 || words[0] != "from:" {
|
||||
if words, flags := parseSearchFlags(splitWords("channel: first in: second from:")); len(words) != 1 || words[0] != "from" {
|
||||
t.Fatalf("got incorrect words %v", words)
|
||||
} else if len(flags) != 2 || flags[0][0] != "channel" || flags[0][1] != "first" || flags[1][0] != "in" || flags[1][1] != "second" {
|
||||
t.Fatalf("got incorrect flags %v", flags)
|
||||
@@ -212,4 +212,8 @@ func TestParseSearchParams(t *testing.T) {
|
||||
if sp := ParseSearchParams("testing in:channel from:someone"); len(sp) != 1 || sp[0].Terms != "testing" || len(sp[0].InChannels) != 1 || sp[0].InChannels[0] != "channel" || len(sp[0].FromUsers) != 1 || sp[0].FromUsers[0] != "someone" {
|
||||
t.Fatalf("Incorrect output from parse search params: %v", sp[0])
|
||||
}
|
||||
|
||||
if sp := ParseSearchParams("##hashtag +#plus+"); len(sp) != 1 || sp[0].Terms != "#hashtag #plus" || sp[0].IsHashtag != true || len(sp[0].InChannels) != 0 || len(sp[0].FromUsers) != 0 {
|
||||
t.Fatalf("Incorrect output from parse search params: %v", sp[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,16 +71,6 @@ func AppErrorFromJson(data io.Reader) *AppError {
|
||||
}
|
||||
}
|
||||
|
||||
func NewAppError(where string, message string, details string) *AppError {
|
||||
ap := &AppError{}
|
||||
ap.Message = message
|
||||
ap.Where = where
|
||||
ap.DetailedError = details
|
||||
ap.StatusCode = 500
|
||||
ap.IsOAuth = false
|
||||
return ap
|
||||
}
|
||||
|
||||
func NewLocAppError(where string, id string, params map[string]interface{}, details string) *AppError {
|
||||
ap := &AppError{}
|
||||
ap.Id = id
|
||||
@@ -298,8 +288,9 @@ func Etag(parts ...interface{}) string {
|
||||
}
|
||||
|
||||
var validHashtag = regexp.MustCompile(`^(#[A-Za-zäöüÄÖÜß]+[A-Za-z0-9äöüÄÖÜß_\-]*[A-Za-z0-9äöüÄÖÜß])$`)
|
||||
var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\]+`)
|
||||
var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}';\\]+$`)
|
||||
var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\<>\-+=%^*|]+`)
|
||||
var hashtagStart = regexp.MustCompile(`^#{2,}`)
|
||||
var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}':;\\<>\-+=%^*|]+$`)
|
||||
|
||||
func ParseHashtags(text string) (string, string) {
|
||||
words := strings.Fields(text)
|
||||
@@ -307,8 +298,13 @@ func ParseHashtags(text string) (string, string) {
|
||||
hashtagString := ""
|
||||
plainString := ""
|
||||
for _, word := range words {
|
||||
// trim off surrounding punctuation
|
||||
word = puncStart.ReplaceAllString(word, "")
|
||||
word = puncEnd.ReplaceAllString(word, "")
|
||||
|
||||
// and remove extra pound #s
|
||||
word = hashtagStart.ReplaceAllString(word, "#")
|
||||
|
||||
if validHashtag.MatchString(word) {
|
||||
hashtagString += " " + word
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestRandomString(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAppError(t *testing.T) {
|
||||
err := NewAppError("TestAppError", "message", "")
|
||||
err := NewLocAppError("TestAppError", "message", nil, "")
|
||||
json := err.ToJson()
|
||||
rerr := AppErrorFromJson(strings.NewReader(json))
|
||||
if err.Message != rerr.Message {
|
||||
@@ -83,19 +83,34 @@ func TestEtag(t *testing.T) {
|
||||
}
|
||||
|
||||
var hashtags map[string]string = map[string]string{
|
||||
"#test": "#test",
|
||||
"test": "",
|
||||
"#test123": "#test123",
|
||||
"#123test123": "",
|
||||
"#test-test": "#test-test",
|
||||
"#test?": "#test",
|
||||
"hi #there": "#there",
|
||||
"#bug #idea": "#bug #idea",
|
||||
"#bug or #gif!": "#bug #gif",
|
||||
"#hüllo": "#hüllo",
|
||||
"#?test": "",
|
||||
"#-test": "",
|
||||
"#yo_yo": "#yo_yo",
|
||||
"#test": "#test",
|
||||
"test": "",
|
||||
"#test123": "#test123",
|
||||
"#123test123": "",
|
||||
"#test-test": "#test-test",
|
||||
"#test?": "#test",
|
||||
"hi #there": "#there",
|
||||
"#bug #idea": "#bug #idea",
|
||||
"#bug or #gif!": "#bug #gif",
|
||||
"#hüllo": "#hüllo",
|
||||
"#?test": "",
|
||||
"#-test": "",
|
||||
"#yo_yo": "#yo_yo",
|
||||
"(#brakets)": "#brakets",
|
||||
")#stekarb(": "#stekarb",
|
||||
"<#less_than<": "#less_than",
|
||||
">#greater_than>": "#greater_than",
|
||||
"-#minus-": "#minus",
|
||||
"+#plus+": "#plus",
|
||||
"=#equals=": "#equals",
|
||||
"%#pct%": "#pct",
|
||||
"&#and&": "#and",
|
||||
"^#hat^": "#hat",
|
||||
"##brown#": "#brown",
|
||||
"*#star*": "#star",
|
||||
"|#pipe|": "#pipe",
|
||||
":#colon:": "#colon",
|
||||
";#semi;": "#semi",
|
||||
}
|
||||
|
||||
func TestParseHashtags(t *testing.T) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -25,10 +26,27 @@ var versions = []string{
|
||||
}
|
||||
|
||||
var CurrentVersion string = versions[0]
|
||||
var BuildNumber = "dev"
|
||||
var BuildDate = "Fri Jan 8 14:19:26 UTC 2016"
|
||||
var BuildHash = "001a4448ca5fb0018eeb442915b473b121c04bf3"
|
||||
var BuildEnterpriseReady = "false"
|
||||
|
||||
var BuildNumber = "_BUILD_NUMBER_"
|
||||
var BuildDate = "_BUILD_DATE_"
|
||||
var BuildHash = "_BUILD_HASH_"
|
||||
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_"
|
||||
var versionsWithoutHotFixes []string
|
||||
|
||||
func init() {
|
||||
versionsWithoutHotFixes = make([]string, 0, len(versions))
|
||||
seen := make(map[string]string)
|
||||
|
||||
for _, version := range versions {
|
||||
maj, min, _ := SplitVersion(version)
|
||||
verStr := fmt.Sprintf("%v.%v.0", maj, min)
|
||||
|
||||
if seen[verStr] == "" {
|
||||
versionsWithoutHotFixes = append(versionsWithoutHotFixes, verStr)
|
||||
seen[verStr] = verStr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SplitVersion(version string) (int64, int64, int64) {
|
||||
parts := strings.Split(version, ".")
|
||||
@@ -52,25 +70,17 @@ func SplitVersion(version string) (int64, int64, int64) {
|
||||
return major, minor, patch
|
||||
}
|
||||
|
||||
func GetPreviousVersion(currentVersion string) (int64, int64) {
|
||||
currentIndex := -1
|
||||
currentMajor, currentMinor, _ := SplitVersion(currentVersion)
|
||||
func GetPreviousVersion(version string) string {
|
||||
verMajor, verMinor, _ := SplitVersion(version)
|
||||
verStr := fmt.Sprintf("%v.%v.0", verMajor, verMinor)
|
||||
|
||||
for index, version := range versions {
|
||||
major, minor, _ := SplitVersion(version)
|
||||
|
||||
if currentMajor == major && currentMinor == minor {
|
||||
currentIndex = index
|
||||
}
|
||||
|
||||
if currentIndex >= 0 {
|
||||
if currentMajor != major || currentMinor != minor {
|
||||
return major, minor
|
||||
}
|
||||
for index, v := range versionsWithoutHotFixes {
|
||||
if v == verStr && len(versionsWithoutHotFixes) > index+1 {
|
||||
return versionsWithoutHotFixes[index+1]
|
||||
}
|
||||
}
|
||||
|
||||
return 0, 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func IsOfficalBuild() bool {
|
||||
@@ -88,13 +98,24 @@ func IsCurrentVersion(versionToCheck string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func IsPreviousVersion(versionToCheck string) bool {
|
||||
func IsPreviousVersionsSupported(versionToCheck string) bool {
|
||||
toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
|
||||
prevMajor, prevMinor := GetPreviousVersion(CurrentVersion)
|
||||
versionToCheckStr := fmt.Sprintf("%v.%v.0", toCheckMajor, toCheckMinor)
|
||||
|
||||
if toCheckMajor == prevMajor && toCheckMinor == prevMinor {
|
||||
// Current Supported
|
||||
if versionsWithoutHotFixes[0] == versionToCheckStr {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
// Current - 1 Supported
|
||||
if versionsWithoutHotFixes[1] == versionToCheckStr {
|
||||
return true
|
||||
}
|
||||
|
||||
// Current - 2 Supported
|
||||
if versionsWithoutHotFixes[2] == versionToCheckStr {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -36,20 +36,28 @@ func TestSplitVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetPreviousVersion(t *testing.T) {
|
||||
if major, minor := GetPreviousVersion("1.0.0"); major != 0 || minor != 7 {
|
||||
t.Fatal(major, minor)
|
||||
if GetPreviousVersion("1.3.0") != "1.2.0" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if major, minor := GetPreviousVersion("0.7.0"); major != 0 || minor != 6 {
|
||||
t.Fatal(major, minor)
|
||||
if GetPreviousVersion("1.2.1") != "1.1.0" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if major, minor := GetPreviousVersion("0.7.1"); major != 0 || minor != 6 {
|
||||
t.Fatal(major, minor)
|
||||
if GetPreviousVersion("1.1.0") != "1.0.0" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if major, minor := GetPreviousVersion("0.7111.1"); major != 0 || minor != 0 {
|
||||
t.Fatal(major, minor)
|
||||
if GetPreviousVersion("1.0.0") != "0.7.0" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if GetPreviousVersion("0.7.1") != "0.6.0" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if GetPreviousVersion("0.5.0") != "" {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,3 +80,31 @@ func TestIsCurrentVersion(t *testing.T) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPreviousVersionsSupported(t *testing.T) {
|
||||
|
||||
// 1.4.0 CURRENT RELEASED VERSION
|
||||
if !IsPreviousVersionsSupported(versions[0]) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// 1.3.0
|
||||
if !IsPreviousVersionsSupported(versions[1]) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// 1.2.1
|
||||
if !IsPreviousVersionsSupported(versions[2]) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// 1.2.0
|
||||
if !IsPreviousVersionsSupported(versions[3]) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// 1.1.0 NOT SUPPORTED
|
||||
if IsPreviousVersionsSupported(versions[4]) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ func (s SqlAuditStore) Save(audit *model.Audit) StoreChannel {
|
||||
audit.CreateAt = model.GetMillis()
|
||||
|
||||
if err := s.GetMaster().Insert(audit); err != nil {
|
||||
result.Err = model.NewAppError("SqlAuditStore.Save",
|
||||
"We encountered an error saving the audit", "user_id="+
|
||||
result.Err = model.NewLocAppError("SqlAuditStore.Save",
|
||||
"store.sql_audit.save.saving.app_error", nil, "user_id="+
|
||||
audit.UserId+" action="+audit.Action)
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (s SqlAuditStore) Get(user_id string, limit int) StoreChannel {
|
||||
|
||||
if limit > 1000 {
|
||||
limit = 1000
|
||||
result.Err = model.NewAppError("SqlAuditStore.Get", "Limit exceeded for paging", "user_id="+user_id)
|
||||
result.Err = model.NewLocAppError("SqlAuditStore.Get", "store.sql_audit.get.limit.app_error", nil, "user_id="+user_id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -75,7 +75,7 @@ func (s SqlAuditStore) Get(user_id string, limit int) StoreChannel {
|
||||
var audits model.Audits
|
||||
if _, err := s.GetReplica().Select(&audits, "SELECT * FROM Audits WHERE UserId = :user_id ORDER BY CreateAt DESC LIMIT :limit",
|
||||
map[string]interface{}{"user_id": user_id, "limit": limit}); err != nil {
|
||||
result.Err = model.NewAppError("SqlAuditStore.Get", "We encountered an error finding the audits", "user_id="+user_id)
|
||||
result.Err = model.NewLocAppError("SqlAuditStore.Get", "store.sql_audit.get.finding.app_error", nil, "user_id="+user_id)
|
||||
} else {
|
||||
result.Data = audits
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func (s SqlAuditStore) PermanentDeleteByUser(userId string) StoreChannel {
|
||||
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM Audits WHERE UserId = :userId",
|
||||
map[string]interface{}{"userId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlAuditStore.Delete", "We encountered an error deleting the audits", "user_id="+userId)
|
||||
result.Err = model.NewLocAppError("SqlAuditStore.Delete", "store.sql_audit.permanent_delete_by_user.app_error", nil, "user_id="+userId)
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
|
||||
@@ -55,17 +55,17 @@ func (s SqlChannelStore) Save(channel *model.Channel) StoreChannel {
|
||||
go func() {
|
||||
var result StoreResult
|
||||
if channel.Type == model.CHANNEL_DIRECT {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Save", "Use SaveDirectChannel to create a direct channel", "")
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Save", "store.sql_channel.save.direct_channel.app_error", nil, "")
|
||||
} else {
|
||||
if transaction, err := s.GetMaster().Begin(); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Save", "Unable to open transaction", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Save", "store.sql_channel.save.open_transaction.app_error", nil, err.Error())
|
||||
} else {
|
||||
result = s.saveChannelT(transaction, channel)
|
||||
if result.Err != nil {
|
||||
transaction.Rollback()
|
||||
} else {
|
||||
if err := transaction.Commit(); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Save", "Unable to commit transaction", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Save", "store.sql_channel.save.commit_transaction.app_error", nil, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,10 +85,10 @@ func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1
|
||||
var result StoreResult
|
||||
|
||||
if directchannel.Type != model.CHANNEL_DIRECT {
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "Not a direct channel attempted to be created with SaveDirectChannel", "")
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.not_direct.app_error", nil, "")
|
||||
} else {
|
||||
if transaction, err := s.GetMaster().Begin(); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "Unable to open transaction", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.open_transaction.app_error", nil, err.Error())
|
||||
} else {
|
||||
channelResult := s.saveChannelT(transaction, directchannel)
|
||||
|
||||
@@ -113,10 +113,10 @@ func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1
|
||||
if member2Result.Err != nil {
|
||||
details += "Member2Err: " + member2Result.Err.Message
|
||||
}
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "Unable to add direct channel members", details)
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.add_members.app_error", nil, details)
|
||||
} else {
|
||||
if err := transaction.Commit(); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "Ubable to commit transaction", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.commit.app_error", nil, err.Error())
|
||||
} else {
|
||||
result = channelResult
|
||||
}
|
||||
@@ -136,7 +136,7 @@ func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *mo
|
||||
result := StoreResult{}
|
||||
|
||||
if len(channel.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Save", "Must call update for exisiting channel", "id="+channel.Id)
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.existing.app_error", nil, "id="+channel.Id)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -147,10 +147,10 @@ func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *mo
|
||||
|
||||
if channel.Type != model.CHANNEL_DIRECT {
|
||||
if count, err := transaction.SelectInt("SELECT COUNT(0) FROM Channels WHERE TeamId = :TeamId AND DeleteAt = 0 AND (Type = 'O' OR Type = 'P')", map[string]interface{}{"TeamId": channel.TeamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Save", "Failed to get current channel count", "teamId="+channel.TeamId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.current_count.app_error", nil, "teamId="+channel.TeamId+", "+err.Error())
|
||||
return result
|
||||
} else if count > 1000 {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Save", "You've reached the limit of the number of allowed channels.", "teamId="+channel.TeamId)
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.limit.app_error", nil, "teamId="+channel.TeamId)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -160,12 +160,12 @@ func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *mo
|
||||
dupChannel := model.Channel{}
|
||||
s.GetMaster().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name = :Name AND DeleteAt > 0", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name})
|
||||
if dupChannel.DeleteAt > 0 {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Update", "A channel with that URL was previously created", "id="+channel.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Update", "store.sql_channel.save_channel.previously.app_error", nil, "id="+channel.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Update", "A channel with that URL already exists", "id="+channel.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Update", "store.sql_channel.save_channel.exists.app_error", nil, "id="+channel.Id+", "+err.Error())
|
||||
}
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Save", "We couldn't save the channel", "id="+channel.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.save.app_error", nil, "id="+channel.Id+", "+err.Error())
|
||||
}
|
||||
} else {
|
||||
result.Data = channel
|
||||
@@ -194,15 +194,15 @@ func (s SqlChannelStore) Update(channel *model.Channel) StoreChannel {
|
||||
dupChannel := model.Channel{}
|
||||
s.GetReplica().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name= :Name AND DeleteAt > 0", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name})
|
||||
if dupChannel.DeleteAt > 0 {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Update", "A channel with that handle was previously created", "id="+channel.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Update", "store.sql_channel.update.previously.app_error", nil, "id="+channel.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Update", "A channel with that handle already exists", "id="+channel.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Update", "store.sql_channel.update.exists.app_error", nil, "id="+channel.Id+", "+err.Error())
|
||||
}
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Update", "We encountered an error updating the channel", "id="+channel.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Update", "store.sql_channel.update.updating.app_error", nil, "id="+channel.Id+", "+err.Error())
|
||||
}
|
||||
} else if count != 1 {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Update", "We couldn't update the channel", "id="+channel.Id)
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Update", "store.sql_channel.update.app_error", nil, "id="+channel.Id)
|
||||
} else {
|
||||
result.Data = channel
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func (s SqlChannelStore) extraUpdated(channel *model.Channel) StoreChannel {
|
||||
map[string]interface{}{"Id": channel.Id, "Time": channel.ExtraUpdateAt})
|
||||
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.extraUpdated", "Problem updating members last updated time", "id="+channel.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.extraUpdated", "store.sql_channel.extra_updated.app_error", nil, "id="+channel.Id+", "+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -264,9 +264,9 @@ func (s SqlChannelStore) get(id string, master bool) StoreChannel {
|
||||
}
|
||||
|
||||
if obj, err := db.Get(model.Channel{}, id); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Get", "We encountered an error finding the channel", "id="+id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Get", "store.sql_channel.get.find.app_error", nil, "id="+id+", "+err.Error())
|
||||
} else if obj == nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Get", "We couldn't find the existing channel", "id="+id)
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Get", "store.sql_channel.get.existing.app_error", nil, "id="+id)
|
||||
} else {
|
||||
result.Data = obj.(*model.Channel)
|
||||
}
|
||||
@@ -286,7 +286,7 @@ func (s SqlChannelStore) Delete(channelId string, time int64) StoreChannel {
|
||||
|
||||
_, err := s.GetMaster().Exec("Update Channels SET DeleteAt = :Time, UpdateAt = :Time WHERE Id = :ChannelId", map[string]interface{}{"Time": time, "ChannelId": channelId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.Delete", "We couldn't delete the channel", "id="+channelId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.Delete", "store.sql_channel.delete.channel.app_error", nil, "id="+channelId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -303,7 +303,7 @@ func (s SqlChannelStore) PermanentDeleteByTeam(teamId string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM Channels WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeam", "We couldn't delete the channels", "teamId="+teamId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.PermanentDeleteByTeam", "store.sql_channel.permanent_delete_by_team.app_error", nil, "teamId="+teamId+", "+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -328,7 +328,7 @@ func (s SqlChannelStore) GetChannels(teamId string, userId string) StoreChannel
|
||||
_, err := s.GetReplica().Select(&data, "SELECT * FROM Channels, ChannelMembers WHERE Id = ChannelId AND TeamId = :TeamId AND UserId = :UserId AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
|
||||
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetChannels", "We couldn't get the channels", "teamId="+teamId+", userId="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error())
|
||||
} else {
|
||||
channels := &model.ChannelList{make([]*model.Channel, len(data)), make(map[string]*model.ChannelMember)}
|
||||
for i := range data {
|
||||
@@ -338,7 +338,7 @@ func (s SqlChannelStore) GetChannels(teamId string, userId string) StoreChannel
|
||||
}
|
||||
|
||||
if len(channels.Channels) == 0 {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetChannels", "No channels were found", "teamId="+teamId+", userId="+userId)
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.not_found.app_error", nil, "teamId="+teamId+", userId="+userId)
|
||||
} else {
|
||||
result.Data = channels
|
||||
}
|
||||
@@ -381,7 +381,7 @@ func (s SqlChannelStore) GetMoreChannels(teamId string, userId string) StoreChan
|
||||
map[string]interface{}{"TeamId1": teamId, "TeamId2": teamId, "UserId": userId})
|
||||
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetMoreChannels", "We couldn't get the channels", "teamId="+teamId+", userId="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetMoreChannels", "store.sql_channel.get_more_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error())
|
||||
} else {
|
||||
result.Data = &model.ChannelList{data, make(map[string]*model.ChannelMember)}
|
||||
}
|
||||
@@ -409,7 +409,7 @@ func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) StoreCha
|
||||
_, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND TeamId = :TeamId AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
|
||||
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetChannelCounts", "We couldn't get the channel counts", "teamId="+teamId+", userId="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetChannelCounts", "store.sql_channel.get_channel_counts.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error())
|
||||
} else {
|
||||
counts := &model.ChannelCounts{Counts: make(map[string]int64), UpdateTimes: make(map[string]int64)}
|
||||
for i := range data {
|
||||
@@ -437,7 +437,7 @@ func (s SqlChannelStore) GetByName(teamId string, name string) StoreChannel {
|
||||
channel := model.Channel{}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&channel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name= :Name AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetByName", "We couldn't find the existing channel", "teamId="+teamId+", "+"name="+name+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetByName", "store.sql_channel.get_by_name.existing.app_error", nil, "teamId="+teamId+", "+"name="+name+", "+err.Error())
|
||||
} else {
|
||||
result.Data = &channel
|
||||
}
|
||||
@@ -461,14 +461,14 @@ func (s SqlChannelStore) SaveMember(member *model.ChannelMember) StoreChannel {
|
||||
channel := cr.Data.(*model.Channel)
|
||||
|
||||
if transaction, err := s.GetMaster().Begin(); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveMember", "Unable to open transaction", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.open_transaction.app_error", nil, err.Error())
|
||||
} else {
|
||||
result = s.saveMemberT(transaction, member, channel)
|
||||
if result.Err != nil {
|
||||
transaction.Rollback()
|
||||
} else {
|
||||
if err := transaction.Commit(); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveMember", "Unable to commit transaction", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.commit_transaction.app_error", nil, err.Error())
|
||||
}
|
||||
// If sucessfull record members have changed in channel
|
||||
if mu := <-s.extraUpdated(channel); mu.Err != nil {
|
||||
@@ -495,9 +495,9 @@ func (s SqlChannelStore) saveMemberT(transaction *gorp.Transaction, member *mode
|
||||
|
||||
if err := transaction.Insert(member); err != nil {
|
||||
if IsUniqueConstraintError(err.Error(), "ChannelId", "channelmembers_pkey") {
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveMember", "A channel member with that id already exists", "channel_id="+member.ChannelId+", user_id="+member.UserId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.exists.app_error", nil, "channel_id="+member.ChannelId+", user_id="+member.UserId+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlChannelStore.SaveMember", "We couldn't save the channel member", "channel_id="+member.ChannelId+", user_id="+member.UserId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.save.app_error", nil, "channel_id="+member.ChannelId+", user_id="+member.UserId+", "+err.Error())
|
||||
}
|
||||
} else {
|
||||
result.Data = member
|
||||
@@ -521,7 +521,7 @@ func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) StoreChannel
|
||||
}
|
||||
|
||||
if _, err := s.GetMaster().Update(member); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.UpdateMember", "We encountered an error updating the channel member",
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.UpdateMember", "store.sql_channel.update_member.app_error", nil,
|
||||
"channel_id="+member.ChannelId+", "+"user_id="+member.UserId+", "+err.Error())
|
||||
} else {
|
||||
result.Data = member
|
||||
@@ -543,7 +543,7 @@ func (s SqlChannelStore) GetMembers(channelId string) StoreChannel {
|
||||
var members []model.ChannelMember
|
||||
_, err := s.GetReplica().Select(&members, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetMembers", "We couldn't get the channel members", "channel_id="+channelId+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetMembers", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+err.Error())
|
||||
} else {
|
||||
result.Data = members
|
||||
}
|
||||
@@ -564,7 +564,7 @@ func (s SqlChannelStore) GetMember(channelId string, userId string) StoreChannel
|
||||
var member model.ChannelMember
|
||||
err := s.GetReplica().SelectOne(&member, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetMember", "We couldn't get the channel member", "channel_id="+channelId+"user_id="+userId+","+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetMember", "store.sql_channel.get_member.app_error", nil, "channel_id="+channelId+"user_id="+userId+","+err.Error())
|
||||
} else {
|
||||
result.Data = member
|
||||
}
|
||||
@@ -593,7 +593,7 @@ func (s SqlChannelStore) GetMemberCount(channelId string) StoreChannel {
|
||||
AND ChannelMembers.ChannelId = :ChannelId
|
||||
AND Users.DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetMemberCount", "We couldn't get the channel member count", "channel_id="+channelId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetMemberCount", "store.sql_channel.get_member_count.app_error", nil, "channel_id="+channelId+", "+err.Error())
|
||||
} else {
|
||||
result.Data = count
|
||||
}
|
||||
@@ -621,7 +621,7 @@ func (s SqlChannelStore) GetExtraMembers(channelId string, limit int) StoreChann
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetExtraMembers", "We couldn't get the extra info for channel members", "channel_id="+channelId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetExtraMembers", "store.sql_channel.get_extra_members.app_error", nil, "channel_id="+channelId+", "+err.Error())
|
||||
} else {
|
||||
for i := range members {
|
||||
members[i].Sanitize(utils.Cfg.GetSanitizeOptions())
|
||||
@@ -650,7 +650,7 @@ func (s SqlChannelStore) RemoveMember(channelId string, userId string) StoreChan
|
||||
|
||||
_, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "We couldn't remove the channel member", "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
} else {
|
||||
// If sucessfull record members have changed in channel
|
||||
if mu := <-s.extraUpdated(channel); mu.Err != nil {
|
||||
@@ -673,7 +673,7 @@ func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) StoreChanne
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "We couldn't remove the channel member", "user_id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.RemoveMember", "store.sql_channel.permanent_delete_members_by_user.app_error", nil, "user_id="+userId+", "+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -703,7 +703,7 @@ func (s SqlChannelStore) CheckPermissionsTo(teamId string, channelId string, use
|
||||
AND ChannelMembers.UserId = :UserId`,
|
||||
map[string]interface{}{"TeamId": teamId, "ChannelId": channelId, "UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.CheckPermissionsTo", "We couldn't check the permissions", "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.CheckPermissionsTo", "store.sql_channel.check_permissions.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
} else {
|
||||
result.Data = count
|
||||
}
|
||||
@@ -735,7 +735,7 @@ func (s SqlChannelStore) CheckPermissionsToByName(teamId string, channelName str
|
||||
AND ChannelMembers.UserId = :UserId`,
|
||||
map[string]interface{}{"TeamId": teamId, "Name": channelName, "UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.CheckPermissionsToByName", "We couldn't check the permissions", "channel_id="+channelName+", user_id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.CheckPermissionsToByName", "store.sql_channel.check_permissions_by_name.app_error", nil, "channel_id="+channelName+", user_id="+userId+", "+err.Error())
|
||||
} else {
|
||||
result.Data = channelId
|
||||
}
|
||||
@@ -764,7 +764,7 @@ func (s SqlChannelStore) CheckOpenChannelPermissions(teamId string, channelId st
|
||||
AND Channels.Type = :ChannelType`,
|
||||
map[string]interface{}{"ChannelId": channelId, "TeamId": teamId, "ChannelType": model.CHANNEL_OPEN})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.CheckOpenChannelPermissions", "We couldn't check the permissions", "channel_id="+channelId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.CheckOpenChannelPermissions", "store.sql_channel.check_open_channel_permissions.app_error", nil, "channel_id="+channelId+", "+err.Error())
|
||||
} else {
|
||||
result.Data = count
|
||||
}
|
||||
@@ -814,7 +814,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelId string, userId string) Sto
|
||||
|
||||
_, err := s.GetMaster().Exec(query, map[string]interface{}{"ChannelId": channelId, "UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.UpdateLastViewedAt", "We couldn't update the last viewed at time", "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.UpdateLastViewedAt", "store.sql_channel.update_last_viewed_at.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -840,7 +840,7 @@ func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string)
|
||||
AND ChannelId = :ChannelId`,
|
||||
map[string]interface{}{"ChannelId": channelId, "UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.IncrementMentionCount", "We couldn't increment the mention count", "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.IncrementMentionCount", "store.sql_channel.increment_mention_count.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -860,7 +860,7 @@ func (s SqlChannelStore) GetForExport(teamId string) StoreChannel {
|
||||
_, err := s.GetReplica().Select(&data, "SELECT * FROM Channels WHERE TeamId = :TeamId AND DeleteAt = 0 AND Type = 'O'", map[string]interface{}{"TeamId": teamId})
|
||||
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetAllChannels", "We couldn't get all the channels", "teamId="+teamId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.GetAllChannels", "store.sql_channel.get_for_export.app_error", nil, "teamId="+teamId+", err="+err.Error())
|
||||
} else {
|
||||
result.Data = data
|
||||
}
|
||||
@@ -886,7 +886,7 @@ func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) S
|
||||
|
||||
v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.AnalyticsTypeCount", "We couldn't get channel type counts", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlChannelStore.AnalyticsTypeCount", "store.sql_channel.analytics_type_count.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = v
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func (as SqlOAuthStore) SaveApp(app *model.OAuthApp) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if len(app.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.SaveApp", "Must call update for exisiting app", "app_id="+app.Id)
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.SaveApp", "store.sql_oauth.save_app.existing.app_error", nil, "app_id="+app.Id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -74,7 +74,7 @@ func (as SqlOAuthStore) SaveApp(app *model.OAuthApp) StoreChannel {
|
||||
}
|
||||
|
||||
if err := as.GetMaster().Insert(app); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.SaveApp", "We couldn't save the app.", "app_id="+app.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.SaveApp", "store.sql_oauth.save_app.save.app_error", nil, "app_id="+app.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Data = app
|
||||
}
|
||||
@@ -102,9 +102,9 @@ func (as SqlOAuthStore) UpdateApp(app *model.OAuthApp) StoreChannel {
|
||||
}
|
||||
|
||||
if oldAppResult, err := as.GetMaster().Get(model.OAuthApp{}, app.Id); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.UpdateApp", "We encountered an error finding the app", "app_id="+app.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.UpdateApp", "store.sql_oauth.update_app.finding.app_error", nil, "app_id="+app.Id+", "+err.Error())
|
||||
} else if oldAppResult == nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.UpdateApp", "We couldn't find the existing app to update", "app_id="+app.Id)
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.UpdateApp", "store.sql_oauth.update_app.find.app_error", nil, "app_id="+app.Id)
|
||||
} else {
|
||||
oldApp := oldAppResult.(*model.OAuthApp)
|
||||
app.CreateAt = oldApp.CreateAt
|
||||
@@ -112,9 +112,9 @@ func (as SqlOAuthStore) UpdateApp(app *model.OAuthApp) StoreChannel {
|
||||
app.CreatorId = oldApp.CreatorId
|
||||
|
||||
if count, err := as.GetMaster().Update(app); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.UpdateApp", "We encountered an error updating the app", "app_id="+app.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.UpdateApp", "store.sql_oauth.update_app.updating.app_error", nil, "app_id="+app.Id+", "+err.Error())
|
||||
} else if count != 1 {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.UpdateApp", "We couldn't update the app", "app_id="+app.Id)
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.UpdateApp", "store.sql_oauth.update_app.update.app_error", nil, "app_id="+app.Id)
|
||||
} else {
|
||||
result.Data = [2]*model.OAuthApp{app, oldApp}
|
||||
}
|
||||
@@ -135,9 +135,9 @@ func (as SqlOAuthStore) GetApp(id string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if obj, err := as.GetReplica().Get(model.OAuthApp{}, id); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.GetApp", "We encountered an error finding the app", "app_id="+id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.GetApp", "store.sql_oauth.get_app.finding.app_error", nil, "app_id="+id+", "+err.Error())
|
||||
} else if obj == nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.GetApp", "We couldn't find the existing app", "app_id="+id)
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.GetApp", "store.sql_oauth.get_app.find.app_error", nil, "app_id="+id)
|
||||
} else {
|
||||
result.Data = obj.(*model.OAuthApp)
|
||||
}
|
||||
@@ -160,7 +160,7 @@ func (as SqlOAuthStore) GetAppByUser(userId string) StoreChannel {
|
||||
var apps []*model.OAuthApp
|
||||
|
||||
if _, err := as.GetReplica().Select(&apps, "SELECT * FROM OAuthApps WHERE CreatorId = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.GetAppByUser", "We couldn't find any existing apps", "user_id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.GetAppByUser", "store.sql_oauth.get_app_by_user.find.app_error", nil, "user_id="+userId+", "+err.Error())
|
||||
}
|
||||
|
||||
result.Data = apps
|
||||
@@ -186,7 +186,7 @@ func (as SqlOAuthStore) SaveAccessData(accessData *model.AccessData) StoreChanne
|
||||
}
|
||||
|
||||
if err := as.GetMaster().Insert(accessData); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.SaveAccessData", "We couldn't save the access token.", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.SaveAccessData", "store.sql_oauth.save_access_data.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = accessData
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func (as SqlOAuthStore) GetAccessData(token string) StoreChannel {
|
||||
accessData := model.AccessData{}
|
||||
|
||||
if err := as.GetReplica().SelectOne(&accessData, "SELECT * FROM OAuthAccessData WHERE Token = :Token", map[string]interface{}{"Token": token}); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.GetAccessData", "We encountered an error finding the access token", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.GetAccessData", "store.sql_oauth.get_access_data.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = &accessData
|
||||
}
|
||||
@@ -234,7 +234,7 @@ func (as SqlOAuthStore) GetAccessDataByAuthCode(authCode string) StoreChannel {
|
||||
if strings.Contains(err.Error(), "no rows") {
|
||||
result.Data = nil
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.GetAccessDataByAuthCode", "We encountered an error finding the access token", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.GetAccessDataByAuthCode", "store.sql_oauth.get_access_data_by_code.app_error", nil, err.Error())
|
||||
}
|
||||
} else {
|
||||
result.Data = &accessData
|
||||
@@ -255,7 +255,7 @@ func (as SqlOAuthStore) RemoveAccessData(token string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := as.GetMaster().Exec("DELETE FROM OAuthAccessData WHERE Token = :Token", map[string]interface{}{"Token": token}); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.RemoveAccessData", "We couldn't remove the access token", "err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.RemoveAccessData", "store.sql_oauth.remove_access_data.app_error", nil, "err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -280,7 +280,7 @@ func (as SqlOAuthStore) SaveAuthData(authData *model.AuthData) StoreChannel {
|
||||
}
|
||||
|
||||
if err := as.GetMaster().Insert(authData); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.SaveAuthData", "We couldn't save the authorization code.", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.SaveAuthData", "store.sql_oauth.save_auth_data.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = authData
|
||||
}
|
||||
@@ -300,9 +300,9 @@ func (as SqlOAuthStore) GetAuthData(code string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if obj, err := as.GetReplica().Get(model.AuthData{}, code); err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.GetAuthData", "We encountered an error finding the authorization code", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.GetAuthData", "store.sql_oauth.get_auth_data.finding.app_error", nil, err.Error())
|
||||
} else if obj == nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.GetAuthData", "We couldn't find the existing authorization code", "")
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.GetAuthData", "store.sql_oauth.get_auth_data.find.app_error", nil, "")
|
||||
} else {
|
||||
result.Data = obj.(*model.AuthData)
|
||||
}
|
||||
@@ -323,7 +323,7 @@ func (as SqlOAuthStore) RemoveAuthData(code string) StoreChannel {
|
||||
|
||||
_, err := as.GetMaster().Exec("DELETE FROM OAuthAuthData WHERE Code = :Code", map[string]interface{}{"Code": code})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.RemoveAuthData", "We couldn't remove the authorization code", "err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.RemoveAuthData", "store.sql_oauth.remove_auth_data.app_error", nil, "err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -341,7 +341,7 @@ func (as SqlOAuthStore) PermanentDeleteAuthDataByUser(userId string) StoreChanne
|
||||
|
||||
_, err := as.GetMaster().Exec("DELETE FROM OAuthAuthData WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlOAuthStore.RemoveAuthDataByUserId", "We couldn't remove the authorization code", "err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlOAuthStore.RemoveAuthDataByUserId", "store.sql_oauth.permanent_delete_auth_data_by_user.app_error", nil, "err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
|
||||
@@ -38,6 +38,11 @@ func NewSqlPostStore(sqlStore *SqlStore) PostStore {
|
||||
}
|
||||
|
||||
func (s SqlPostStore) UpgradeSchemaIfNeeded() {
|
||||
// ADDED for 1.3 REMOVE for 1.6
|
||||
s.RemoveColumnIfExists("Posts", "ImgCount")
|
||||
|
||||
// ADDED for 1.3 REMOVE for 1.6
|
||||
s.GetMaster().Exec(`UPDATE Preferences SET Type = :NewType WHERE Type = :CurrentType`, map[string]string{"NewType": model.POST_JOIN_LEAVE, "CurrentType": "join_leave"})
|
||||
}
|
||||
|
||||
func (s SqlPostStore) CreateIndexesIfNotExists() {
|
||||
@@ -57,8 +62,8 @@ func (s SqlPostStore) Save(post *model.Post) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if len(post.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlPostStore.Save",
|
||||
"You cannot update an existing Post", "id="+post.Id)
|
||||
result.Err = model.NewLocAppError("SqlPostStore.Save",
|
||||
"store.sql_post.save.existing.app_error", nil, "id="+post.Id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -72,7 +77,7 @@ func (s SqlPostStore) Save(post *model.Post) StoreChannel {
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(post); err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.Save", "We couldn't save the Post", "id="+post.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.Save", "store.sql_post.save.app_error", nil, "id="+post.Id+", "+err.Error())
|
||||
} else {
|
||||
time := model.GetMillis()
|
||||
|
||||
@@ -120,7 +125,7 @@ func (s SqlPostStore) Update(oldPost *model.Post, newMessage string, newHashtags
|
||||
}
|
||||
|
||||
if _, err := s.GetMaster().Update(&editPost); err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.Update", "We couldn't update the Post", "id="+editPost.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.Update", "store.sql_post.update.app_error", nil, "id="+editPost.Id+", "+err.Error())
|
||||
} else {
|
||||
time := model.GetMillis()
|
||||
s.GetMaster().Exec("UPDATE Channels SET LastPostAt = :LastPostAt WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": time, "ChannelId": editPost.ChannelId})
|
||||
@@ -152,7 +157,7 @@ func (s SqlPostStore) Get(id string) StoreChannel {
|
||||
var post model.Post
|
||||
err := s.GetReplica().SelectOne(&post, "SELECT * FROM Posts WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetPost", "We couldn't get the post", "id="+id+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetPost", "store.sql_post.get.app_error", nil, "id="+id+err.Error())
|
||||
}
|
||||
|
||||
pl.AddPost(&post)
|
||||
@@ -167,7 +172,7 @@ func (s SqlPostStore) Get(id string) StoreChannel {
|
||||
var posts []*model.Post
|
||||
_, err = s.GetReplica().Select(&posts, "SELECT * FROM Posts WHERE (Id = :Id OR RootId = :RootId) AND DeleteAt = 0", map[string]interface{}{"Id": rootId, "RootId": rootId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetPost", "We couldn't get the post", "root_id="+rootId+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetPost", "store.sql_post.get.app_error", nil, "root_id="+rootId+err.Error())
|
||||
} else {
|
||||
for _, p := range posts {
|
||||
pl.AddPost(p)
|
||||
@@ -217,7 +222,7 @@ func (s SqlPostStore) Delete(postId string, time int64) StoreChannel {
|
||||
|
||||
_, err := s.GetMaster().Exec("Update Posts SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id OR ParentId = :ParentId OR RootId = :RootId", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": postId, "ParentId": postId, "RootId": postId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.Delete", "We couldn't delete the post", "id="+postId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.Delete", "store.sql_post.delete.app_error", nil, "id="+postId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -235,7 +240,7 @@ func (s SqlPostStore) permanentDelete(postId string) StoreChannel {
|
||||
|
||||
_, err := s.GetMaster().Exec("DELETE FROM Posts WHERE Id = :Id OR ParentId = :ParentId OR RootId = :RootId", map[string]interface{}{"Id": postId, "ParentId": postId, "RootId": postId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.Delete", "We couldn't delete the post", "id="+postId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.Delete", "store.sql_post.permanent_delete.app_error", nil, "id="+postId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -253,7 +258,7 @@ func (s SqlPostStore) permanentDeleteAllCommentByUser(userId string) StoreChanne
|
||||
|
||||
_, err := s.GetMaster().Exec("DELETE FROM Posts WHERE UserId = :UserId AND RootId != ''", map[string]interface{}{"UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.permanentDeleteAllCommentByUser", "We couldn't delete the comments for user", "userId="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.permanentDeleteAllCommentByUser", "store.sql_post.permanent_delete_all_comments_by_user.app_error", nil, "userId="+userId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -286,7 +291,7 @@ func (s SqlPostStore) PermanentDeleteByUser(userId string) StoreChannel {
|
||||
var ids []string
|
||||
_, err := s.GetMaster().Select(&ids, "SELECT Id FROM Posts WHERE UserId = :UserId LIMIT 1000", map[string]interface{}{"UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.PermanentDeleteByUser.select", "We couldn't select the posts to delete for the user", "userId="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.PermanentDeleteByUser.select", "store.sql_post.permanent_delete_by_user.app_error", nil, "userId="+userId+", err="+err.Error())
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -306,7 +311,7 @@ func (s SqlPostStore) PermanentDeleteByUser(userId string) StoreChannel {
|
||||
// This is a fail safe, give up if more than 10K messages
|
||||
count = count + 1
|
||||
if count >= 10 {
|
||||
result.Err = model.NewAppError("SqlPostStore.PermanentDeleteByUser.toolarge", "We couldn't select the posts to delete for the user (too many), please re-run", "userId="+userId)
|
||||
result.Err = model.NewLocAppError("SqlPostStore.PermanentDeleteByUser.toolarge", "store.sql_post.permanent_delete_by_user.too_many.app_error", nil, "userId="+userId)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -327,7 +332,7 @@ func (s SqlPostStore) GetPosts(channelId string, offset int, limit int) StoreCha
|
||||
result := StoreResult{}
|
||||
|
||||
if limit > 1000 {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetLinearPosts", "Limit exceeded for paging", "channelId="+channelId)
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetLinearPosts", "store.sql_post.get_posts.app_error", nil, "channelId="+channelId)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -403,7 +408,7 @@ func (s SqlPostStore) GetPostsSince(channelId string, time int64) StoreChannel {
|
||||
map[string]interface{}{"ChannelId": channelId, "Time": time})
|
||||
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetPostsSince", "We couldn't get the posts for the channel", "channelId="+channelId+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetPostsSince", "store.sql_post.get_posts_since.app_error", nil, "channelId="+channelId+err.Error())
|
||||
} else {
|
||||
|
||||
list := &model.PostList{Order: make([]string, 0, len(posts))}
|
||||
@@ -488,9 +493,9 @@ func (s SqlPostStore) getPostsAround(channelId string, postId string, numPosts i
|
||||
map[string]interface{}{"ChannelId": channelId, "PostId": postId, "NumPosts": numPosts, "Offset": offset})
|
||||
|
||||
if err1 != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetPostContext", "We couldn't get the posts for the channel", "channelId="+channelId+err1.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetPostContext", "store.sql_post.get_posts_around.get.app_error", nil, "channelId="+channelId+err1.Error())
|
||||
} else if err2 != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetPostContext", "We couldn't get the parent posts for the channel", "channelId="+channelId+err2.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetPostContext", "store.sql_post.get_posts_around.get_parent.app_error", nil, "channelId="+channelId+err2.Error())
|
||||
} else {
|
||||
|
||||
list := &model.PostList{Order: make([]string, 0, len(posts))}
|
||||
@@ -532,7 +537,7 @@ func (s SqlPostStore) getRootPosts(channelId string, offset int, limit int) Stor
|
||||
var posts []*model.Post
|
||||
_, err := s.GetReplica().Select(&posts, "SELECT * FROM Posts WHERE ChannelId = :ChannelId AND DeleteAt = 0 ORDER BY CreateAt DESC LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetLinearPosts", "We couldn't get the posts for the channel", "channelId="+channelId+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetLinearPosts", "store.sql_post.get_root_posts.app_error", nil, "channelId="+channelId+err.Error())
|
||||
} else {
|
||||
result.Data = posts
|
||||
}
|
||||
@@ -577,7 +582,7 @@ func (s SqlPostStore) getParentsPosts(channelId string, offset int, limit int) S
|
||||
ORDER BY CreateAt`,
|
||||
map[string]interface{}{"ChannelId1": channelId, "Offset": offset, "Limit": limit, "ChannelId2": channelId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetLinearPosts", "We couldn't get the parent post for the channel", "channelId="+channelId+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetLinearPosts", "store.sql_post.get_parents_posts.app_error", nil, "channelId="+channelId+err.Error())
|
||||
} else {
|
||||
result.Data = posts
|
||||
}
|
||||
@@ -642,6 +647,7 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP
|
||||
Posts
|
||||
WHERE
|
||||
DeleteAt = 0
|
||||
AND Type NOT LIKE '` + model.POST_SYSTEM_MESSAGE_PREFIX + `%'
|
||||
POST_FILTER
|
||||
AND ChannelId IN (
|
||||
SELECT
|
||||
@@ -733,7 +739,7 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP
|
||||
|
||||
_, err := s.GetReplica().Select(&posts, searchQuery, queryParams)
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.Search", "We encountered an error while searching for posts", "teamId="+teamId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.Search", "store.sql_post.search.app_error", nil, "teamId="+teamId+", err="+err.Error())
|
||||
}
|
||||
|
||||
list := &model.PostList{Order: make([]string, 0, len(posts))}
|
||||
@@ -777,7 +783,7 @@ func (s SqlPostStore) GetForExport(channelId string) StoreChannel {
|
||||
"SELECT * FROM Posts WHERE ChannelId = :ChannelId AND DeleteAt = 0",
|
||||
map[string]interface{}{"ChannelId": channelId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.GetForExport", "We couldn't get the posts for the channel", "channelId="+channelId+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.GetForExport", "store.sql_post.get_for_export.app_error", nil, "channelId="+channelId+err.Error())
|
||||
} else {
|
||||
result.Data = posts
|
||||
}
|
||||
@@ -849,7 +855,7 @@ func (s SqlPostStore) AnalyticsUserCountsWithPostsByDay(teamId string) StoreChan
|
||||
query,
|
||||
map[string]interface{}{"TeamId": teamId, "EndTime": end})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.AnalyticsUserCountsWithPostsByDay", "We couldn't get user counts with posts", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.AnalyticsUserCountsWithPostsByDay", "store.sql_post.analytics_user_counts_posts_by_day.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = rows
|
||||
}
|
||||
@@ -922,7 +928,7 @@ func (s SqlPostStore) AnalyticsPostCountsByDay(teamId string) StoreChannel {
|
||||
query,
|
||||
map[string]interface{}{"TeamId": teamId, "StartTime": start, "EndTime": end})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.AnalyticsPostCountsByDay", "We couldn't get post counts by day", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.AnalyticsPostCountsByDay", "store.sql_post.analytics_posts_count_by_day.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = rows
|
||||
}
|
||||
@@ -955,7 +961,7 @@ func (s SqlPostStore) AnalyticsPostCount(teamId string) StoreChannel {
|
||||
|
||||
v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.AnalyticsPostCount", "We couldn't get post counts", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPostStore.AnalyticsPostCount", "store.sql_post.analytics_posts_count.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = v
|
||||
}
|
||||
|
||||
@@ -676,6 +676,13 @@ func TestPostStoreSearch(t *testing.T) {
|
||||
o1.Message = "corey mattermost new york"
|
||||
o1 = (<-store.Post().Save(o1)).Data.(*model.Post)
|
||||
|
||||
o1a := &model.Post{}
|
||||
o1a.ChannelId = c1.Id
|
||||
o1a.UserId = model.NewId()
|
||||
o1a.Message = "corey mattermost new york"
|
||||
o1a.Type = model.POST_JOIN_LEAVE
|
||||
o1a = (<-store.Post().Save(o1a)).Data.(*model.Post)
|
||||
|
||||
o2 := &model.Post{}
|
||||
o2.ChannelId = c1.Id
|
||||
o2.UserId = model.NewId()
|
||||
|
||||
@@ -42,7 +42,7 @@ func (s SqlPreferenceStore) CreateIndexesIfNotExists() {
|
||||
}
|
||||
|
||||
func (s SqlPreferenceStore) DeleteUnusedFeatures() {
|
||||
l4g.Debug("Deleting any unused pre-release features")
|
||||
l4g.Debug(utils.T("store.sql_preference.delete_unused_features.debug"))
|
||||
|
||||
sql := `DELETE
|
||||
FROM Preferences
|
||||
@@ -67,7 +67,7 @@ func (s SqlPreferenceStore) Save(preferences *model.Preferences) StoreChannel {
|
||||
// wrap in a transaction so that if one fails, everything fails
|
||||
transaction, err := s.GetMaster().Begin()
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.Save", "Unable to open transaction to save preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.Save", "store.sql_preference.save.open_transaction.app_error", nil, err.Error())
|
||||
} else {
|
||||
for _, preference := range *preferences {
|
||||
if upsertResult := s.save(transaction, &preference); upsertResult.Err != nil {
|
||||
@@ -79,13 +79,13 @@ func (s SqlPreferenceStore) Save(preferences *model.Preferences) StoreChannel {
|
||||
if result.Err == nil {
|
||||
if err := transaction.Commit(); err != nil {
|
||||
// don't need to rollback here since the transaction is already closed
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.Save", "Unable to commit transaction to save preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.Save", "store.sql_preference.save.commit_transaction.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = len(*preferences)
|
||||
}
|
||||
} else {
|
||||
if err := transaction.Rollback(); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.Save", "Unable to rollback transaction to save preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.Save", "store.sql_preference.save.rollback_transaction.app_error", nil, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *mode
|
||||
(:UserId, :Category, :Name, :Value)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
Value = :Value`, params); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.save", "We encountered an error while updating preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error())
|
||||
}
|
||||
} else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES {
|
||||
// postgres has no way to upsert values until version 9.5 and trying inserting and then updating causes transactions to abort
|
||||
@@ -134,7 +134,7 @@ func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *mode
|
||||
AND Category = :Category
|
||||
AND Name = :Name`, params)
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.save", "We encountered an error while updating preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error())
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *mode
|
||||
s.insert(transaction, preference)
|
||||
}
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.save", "We encountered an error while updating preferences",
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.save", "store.sql_preference.save.missing_driver.app_error", nil,
|
||||
"Failed to update preference because of missing driver")
|
||||
}
|
||||
|
||||
@@ -156,10 +156,10 @@ func (s SqlPreferenceStore) insert(transaction *gorp.Transaction, preference *mo
|
||||
|
||||
if err := transaction.Insert(preference); err != nil {
|
||||
if IsUniqueConstraintError(err.Error(), "UserId", "preferences_pkey") {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.insert", "A preference with that user id, category, and name already exists",
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.exists.app_error", nil,
|
||||
"user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.insert", "We couldn't save the preference",
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.save.app_error", nil,
|
||||
"user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error())
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ func (s SqlPreferenceStore) update(transaction *gorp.Transaction, preference *mo
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := transaction.Update(preference); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.update", "We couldn't update the preference",
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.update", "store.sql_preference.update.app_error", nil,
|
||||
"user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error())
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ func (s SqlPreferenceStore) Get(userId string, category string, name string) Sto
|
||||
UserId = :UserId
|
||||
AND Category = :Category
|
||||
AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.Get", "We encountered an error while finding preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.Get", "store.sql_preference.get.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = preference
|
||||
}
|
||||
@@ -223,7 +223,7 @@ func (s SqlPreferenceStore) GetCategory(userId string, category string) StoreCha
|
||||
WHERE
|
||||
UserId = :UserId
|
||||
AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.GetCategory", "We encountered an error while finding preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.GetCategory", "store.sql_preference.get_category.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = preferences
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func (s SqlPreferenceStore) GetAll(userId string) StoreChannel {
|
||||
Preferences
|
||||
WHERE
|
||||
UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.GetAll", "We encountered an error while finding preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.GetAll", "store.sql_preference.get_all.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = preferences
|
||||
}
|
||||
@@ -270,7 +270,7 @@ func (s SqlPreferenceStore) PermanentDeleteByUser(userId string) StoreChannel {
|
||||
|
||||
if _, err := s.GetMaster().Exec(
|
||||
`DELETE FROM Preferences WHERE UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.Delete", "We encountered an error while deleteing preferences", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.Delete", "store.sql_preference.permanent_delete_by_user.app_error", nil, err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -293,7 +293,7 @@ func (s SqlPreferenceStore) IsFeatureEnabled(feature, userId string) StoreChanne
|
||||
UserId = :UserId
|
||||
AND Category = :Category
|
||||
AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS, "Name": FEATURE_TOGGLE_PREFIX + feature}); err != nil {
|
||||
result.Err = model.NewAppError("SqlPreferenceStore.IsFeatureEnabled", "We encountered an error while finding a pre release feature preference", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlPreferenceStore.IsFeatureEnabled", "store.sql_preference.is_feature_enabled.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = value == "true"
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package store
|
||||
import (
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
)
|
||||
|
||||
type SqlSessionStore struct {
|
||||
@@ -45,7 +46,7 @@ func (me SqlSessionStore) Save(session *model.Session) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if len(session.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlSessionStore.Save", "Cannot update existing session", "id="+session.Id)
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.existing.app_error", nil, "id="+session.Id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -54,11 +55,11 @@ func (me SqlSessionStore) Save(session *model.Session) StoreChannel {
|
||||
session.PreSave()
|
||||
|
||||
if cur := <-me.CleanUpExpiredSessions(session.UserId); cur.Err != nil {
|
||||
l4g.Error("Failed to cleanup sessions in Save err=%v", cur.Err)
|
||||
l4g.Error(utils.T("store.sql_session.save.cleanup.error"), cur.Err)
|
||||
}
|
||||
|
||||
if err := me.GetMaster().Insert(session); err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.Save", "We couldn't save the session", "id="+session.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Data = session
|
||||
}
|
||||
@@ -80,9 +81,9 @@ func (me SqlSessionStore) Get(sessionIdOrToken string) StoreChannel {
|
||||
var sessions []*model.Session
|
||||
|
||||
if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE Token = :Token OR Id = :Id LIMIT 1", map[string]interface{}{"Token": sessionIdOrToken, "Id": sessionIdOrToken}); err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.Get", "We encountered an error finding the session", "sessionIdOrToken="+sessionIdOrToken+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+err.Error())
|
||||
} else if sessions == nil || len(sessions) == 0 {
|
||||
result.Err = model.NewAppError("SqlSessionStore.Get", "We encountered an error finding the session", "sessionIdOrToken="+sessionIdOrToken)
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken)
|
||||
} else {
|
||||
result.Data = sessions[0]
|
||||
}
|
||||
@@ -101,7 +102,7 @@ func (me SqlSessionStore) GetSessions(userId string) StoreChannel {
|
||||
go func() {
|
||||
|
||||
if cur := <-me.CleanUpExpiredSessions(userId); cur.Err != nil {
|
||||
l4g.Error("Failed to cleanup sessions in getSessions err=%v", cur.Err)
|
||||
l4g.Error(utils.T("store.sql_session.get_sessions.error"), cur.Err)
|
||||
}
|
||||
|
||||
result := StoreResult{}
|
||||
@@ -109,7 +110,7 @@ func (me SqlSessionStore) GetSessions(userId string) StoreChannel {
|
||||
var sessions []*model.Session
|
||||
|
||||
if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE UserId = :UserId ORDER BY LastActivityAt DESC", map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.GetSessions", "We encountered an error while finding user sessions", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, err.Error())
|
||||
} else {
|
||||
|
||||
result.Data = sessions
|
||||
@@ -130,7 +131,7 @@ func (me SqlSessionStore) Remove(sessionIdOrToken string) StoreChannel {
|
||||
|
||||
_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE Id = :Id Or Token = :Token", map[string]interface{}{"Id": sessionIdOrToken, "Token": sessionIdOrToken})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.RemoveSession", "We couldn't remove the session", "id="+sessionIdOrToken+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.RemoveSession", "store.sql_session.remove.app_error", nil, "id="+sessionIdOrToken+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -148,7 +149,7 @@ func (me SqlSessionStore) RemoveAllSessionsForTeam(teamId string) StoreChannel {
|
||||
|
||||
_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.RemoveAllSessionsForTeam", "We couldn't remove all the sessions for the team", "id="+teamId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessionsForTeam", "store.sql_session.remove_all_sessions_for_team.app_error", nil, "id="+teamId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -166,7 +167,7 @@ func (me SqlSessionStore) PermanentDeleteSessionsByUser(userId string) StoreChan
|
||||
|
||||
_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.RemoveAllSessionsForUser", "We couldn't remove all the sessions for the user", "id="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessionsForUser", "store.sql_session.permanent_delete_sessions_by_user.app_error", nil, "id="+userId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -183,7 +184,7 @@ func (me SqlSessionStore) CleanUpExpiredSessions(userId string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId AND ExpiresAt != 0 AND :ExpiresAt > ExpiresAt", map[string]interface{}{"UserId": userId, "ExpiresAt": model.GetMillis()}); err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.CleanUpExpiredSessions", "We encountered an error while deleting expired user sessions", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.CleanUpExpiredSessions", "store.sql_session.cleanup_expired_sessions.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -202,7 +203,7 @@ func (me SqlSessionStore) UpdateLastActivityAt(sessionId string, time int64) Sto
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := me.GetMaster().Exec("UPDATE Sessions SET LastActivityAt = :LastActivityAt WHERE Id = :Id", map[string]interface{}{"LastActivityAt": time, "Id": sessionId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.UpdateLastActivityAt", "We couldn't update the last_activity_at", "sessionId="+sessionId)
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.UpdateLastActivityAt", "store.sql_session.update_last_activity.app_error", nil, "sessionId="+sessionId)
|
||||
} else {
|
||||
result.Data = sessionId
|
||||
}
|
||||
@@ -220,7 +221,7 @@ func (me SqlSessionStore) UpdateRoles(userId, roles string) StoreChannel {
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
if _, err := me.GetMaster().Exec("UPDATE Sessions SET Roles = :Roles WHERE UserId = :UserId", map[string]interface{}{"Roles": roles, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlSessionStore.UpdateRoles", "We couldn't update the roles", "userId="+userId)
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.UpdateRoles", "store.sql_session.update_roles.app_error", nil, "userId="+userId)
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -231,3 +232,21 @@ func (me SqlSessionStore) UpdateRoles(userId, roles string) StoreChannel {
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel {
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id}); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, "")
|
||||
} else {
|
||||
result.Data = deviceId
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
@@ -157,6 +157,28 @@ func TestSessionRemoveToken(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionUpdateDeviceId(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
s1 := model.Session{}
|
||||
s1.UserId = model.NewId()
|
||||
s1.TeamId = model.NewId()
|
||||
Must(store.Session().Save(&s1))
|
||||
|
||||
if rs1 := (<-store.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs1.Err != nil {
|
||||
t.Fatal(rs1.Err)
|
||||
}
|
||||
|
||||
s2 := model.Session{}
|
||||
s2.UserId = model.NewId()
|
||||
s2.TeamId = model.NewId()
|
||||
Must(store.Session().Save(&s2))
|
||||
|
||||
if rs2 := (<-store.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs2.Err != nil {
|
||||
t.Fatal(rs2.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionStoreUpdateLastActivityAt(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
|
||||
@@ -74,43 +74,24 @@ func NewSqlStore() Store {
|
||||
}
|
||||
|
||||
schemaVersion := sqlStore.GetCurrentSchemaVersion()
|
||||
isSchemaVersion07 := false // REMOVE AFTER 1.2 SHIP see PLT-828
|
||||
isSchemaVersion10 := false // REMOVE AFTER 1.2 SHIP see PLT-828
|
||||
|
||||
// If the version is already set then we are potentially in an 'upgrade needed' state
|
||||
if schemaVersion != "" {
|
||||
// Check to see if it's the most current database schema version
|
||||
if !model.IsCurrentVersion(schemaVersion) {
|
||||
// If we are upgrading from the previous version then print a warning and continue
|
||||
|
||||
// Special case
|
||||
if schemaVersion == "0.7.1" || schemaVersion == "0.7.0" {
|
||||
isSchemaVersion07 = true
|
||||
}
|
||||
|
||||
if schemaVersion == "1.0.0" {
|
||||
isSchemaVersion10 = true
|
||||
}
|
||||
|
||||
if model.IsPreviousVersion(schemaVersion) || isSchemaVersion07 || isSchemaVersion10 {
|
||||
l4g.Warn("The database schema version of " + schemaVersion + " appears to be out of date")
|
||||
l4g.Warn("Attempting to upgrade the database schema version to " + model.CurrentVersion)
|
||||
if model.IsPreviousVersionsSupported(schemaVersion) {
|
||||
l4g.Warn(utils.T("store.sql.schema_out_of_date.warn"), schemaVersion)
|
||||
l4g.Warn(utils.T("store.sql.schema_upgrade_attempt.warn"), model.CurrentVersion)
|
||||
} else {
|
||||
// If this is an 'upgrade needed' state but the user is attempting to skip a version then halt the world
|
||||
l4g.Critical("The database schema version of " + schemaVersion + " cannot be upgraded. You must not skip a version.")
|
||||
l4g.Critical(utils.T("store.sql.schema_version.critical"), schemaVersion)
|
||||
time.Sleep(time.Second)
|
||||
panic("The database schema version of " + schemaVersion + " cannot be upgraded. You must not skip a version.")
|
||||
panic(fmt.Sprintf(utils.T("store.sql.schema_version.critical"), schemaVersion))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REMOVE AFTER 1.2 SHIP see PLT-828
|
||||
if sqlStore.DoesTableExist("Sessions") {
|
||||
if sqlStore.DoesColumnExist("Sessions", "AltId") {
|
||||
sqlStore.GetMaster().Exec("DROP TABLE IF EXISTS Sessions")
|
||||
}
|
||||
}
|
||||
|
||||
sqlStore.team = NewSqlTeamStore(sqlStore)
|
||||
sqlStore.channel = NewSqlChannelStore(sqlStore)
|
||||
sqlStore.post = NewSqlPostStore(sqlStore)
|
||||
@@ -125,7 +106,7 @@ func NewSqlStore() Store {
|
||||
|
||||
err := sqlStore.master.CreateTablesIfNotExists()
|
||||
if err != nil {
|
||||
l4g.Critical("Error creating database tables: %v", err)
|
||||
l4g.Critical(utils.T("store.sql.creating_tables.critical"), err)
|
||||
}
|
||||
|
||||
sqlStore.team.(*SqlTeamStore).UpgradeSchemaIfNeeded()
|
||||
@@ -154,14 +135,14 @@ func NewSqlStore() Store {
|
||||
|
||||
sqlStore.preference.(*SqlPreferenceStore).DeleteUnusedFeatures()
|
||||
|
||||
if model.IsPreviousVersion(schemaVersion) || isSchemaVersion07 || isSchemaVersion10 {
|
||||
if model.IsPreviousVersionsSupported(schemaVersion) {
|
||||
sqlStore.system.Update(&model.System{Name: "Version", Value: model.CurrentVersion})
|
||||
l4g.Warn("The database schema has been upgraded to version " + model.CurrentVersion)
|
||||
l4g.Warn(utils.T("store.sql.upgraded.warn"), model.CurrentVersion)
|
||||
}
|
||||
|
||||
if schemaVersion == "" {
|
||||
sqlStore.system.Save(&model.System{Name: "Version", Value: model.CurrentVersion})
|
||||
l4g.Info("The database schema has been set to version " + model.CurrentVersion)
|
||||
l4g.Info(utils.T("store.sql.schema_set.info"), model.CurrentVersion)
|
||||
}
|
||||
|
||||
return sqlStore
|
||||
@@ -171,17 +152,17 @@ func setupConnection(con_type string, driver string, dataSource string, maxIdle
|
||||
|
||||
db, err := dbsql.Open(driver, dataSource)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to open sql connection to err:%v", err)
|
||||
l4g.Critical(utils.T("store.sql.open_conn.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to open sql connection" + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.open_conn.critical"), err.Error()))
|
||||
}
|
||||
|
||||
l4g.Info("Pinging sql %v database", con_type)
|
||||
l4g.Info(utils.T("store.sql.pinging.info"), con_type)
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to ping db err:%v", err)
|
||||
l4g.Critical(utils.T("store.sql.ping.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to open sql connection " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.open_conn.panic"), err.Error()))
|
||||
}
|
||||
|
||||
db.SetMaxIdleConns(maxIdle)
|
||||
@@ -196,9 +177,9 @@ func setupConnection(con_type string, driver string, dataSource string, maxIdle
|
||||
} else if driver == model.DATABASE_DRIVER_POSTGRES {
|
||||
dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.PostgresDialect{}}
|
||||
} else {
|
||||
l4g.Critical("Failed to create dialect specific driver")
|
||||
l4g.Critical(utils.T("store.sql.dialect_driver.critical"))
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create dialect specific driver " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.dialect_driver.panic"), err.Error()))
|
||||
}
|
||||
|
||||
if trace {
|
||||
@@ -232,9 +213,9 @@ func (ss SqlStore) DoesTableExist(tableName string) bool {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to check if table exists %v", err)
|
||||
l4g.Critical(utils.T("store.sql.table_exists.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check if table exists " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.table_exists.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return count > 0
|
||||
@@ -254,17 +235,17 @@ func (ss SqlStore) DoesTableExist(tableName string) bool {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to check if table exists %v", err)
|
||||
l4g.Critical(utils.T("store.sql.table_exists.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check if table exists " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.table_exists.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return count > 0
|
||||
|
||||
} else {
|
||||
l4g.Critical("Failed to check if column exists because of missing driver")
|
||||
l4g.Critical(utils.T("store.sql.column_exists_missing_driver.critical"))
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check if column exists because of missing driver")
|
||||
panic(utils.T("store.sql.column_exists_missing_driver.critical"))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -286,9 +267,9 @@ func (ss SqlStore) DoesColumnExist(tableName string, columnName string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
l4g.Critical("Failed to check if column exists %v", err)
|
||||
l4g.Critical(utils.T("store.sql.column_exists.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check if column exists " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.column_exists.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return count > 0
|
||||
@@ -309,17 +290,17 @@ func (ss SqlStore) DoesColumnExist(tableName string, columnName string) bool {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to check if column exists %v", err)
|
||||
l4g.Critical(utils.T("store.sql.column_exists.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check if column exists " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.column_exists.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return count > 0
|
||||
|
||||
} else {
|
||||
l4g.Critical("Failed to check if column exists because of missing driver")
|
||||
l4g.Critical(utils.T("store.sql.column_exists_missing_driver.critical"))
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check if column exists because of missing driver")
|
||||
panic(utils.T("store.sql.column_exists_missing_driver.critical"))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -333,9 +314,9 @@ func (ss SqlStore) CreateColumnIfNotExists(tableName string, columnName string,
|
||||
if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES {
|
||||
_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " ADD " + columnName + " " + postgresColType + " DEFAULT '" + defaultValue + "'")
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create column %v", err)
|
||||
l4g.Critical(utils.T("store.sql.create_column.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create column " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.create_column.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -343,17 +324,17 @@ func (ss SqlStore) CreateColumnIfNotExists(tableName string, columnName string,
|
||||
} else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL {
|
||||
_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " ADD " + columnName + " " + mySqlColType + " DEFAULT '" + defaultValue + "'")
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create column %v", err)
|
||||
l4g.Critical(utils.T("store.sql.create_column.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create column " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.create_column.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
} else {
|
||||
l4g.Critical("Failed to create column because of missing driver")
|
||||
l4g.Critical(utils.T("store.sql.create_column_missing_driver.critical"))
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create column because of missing driver")
|
||||
panic(utils.T("store.sql.create_column_missing_driver.critical"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,9 +346,9 @@ func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) boo
|
||||
|
||||
_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to drop column %v", err)
|
||||
l4g.Critical(utils.T("store.sql.drop_column.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to drop column " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.drop_column.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -386,9 +367,9 @@ func (ss SqlStore) RenameColumnIfExists(tableName string, oldColumnName string,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to rename column %v", err)
|
||||
l4g.Critical(utils.T("store.sql.rename_column.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to drop column " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.rename_column.critical"), err.Error()))
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -420,17 +401,17 @@ func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, co
|
||||
|
||||
_, err = ss.GetMaster().Exec(query)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create index %v", err)
|
||||
l4g.Critical(utils.T("store.sql.create_index.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create index " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.create_index.critical"), err.Error()))
|
||||
}
|
||||
} else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL {
|
||||
|
||||
count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to check index %v", err)
|
||||
l4g.Critical(utils.T("store.sql.check_index.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check index " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.check_index.critical"), err.Error()))
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
@@ -444,14 +425,14 @@ func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, co
|
||||
|
||||
_, err = ss.GetMaster().Exec("CREATE " + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + columnName + ")")
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create index %v", err)
|
||||
l4g.Critical(utils.T("store.sql.create_index.critical"), err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create index " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.create_index.critical"), err.Error()))
|
||||
}
|
||||
} else {
|
||||
l4g.Critical("Failed to create index because of missing driver")
|
||||
l4g.Critical(utils.T("store.sql.create_index_missing_driver.critical"))
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create index because of missing driver")
|
||||
panic(utils.T("store.sql.create_index_missing_driver.critical"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,9 +448,9 @@ func (ss SqlStore) GetColumnDataType(tableName, columnName string) string {
|
||||
"Columnname": columnName,
|
||||
})
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to get data type for column %s from table %s: %v", columnName, tableName, err.Error())
|
||||
l4g.Critical(utils.T("store.sql.table_column_type.critical"), columnName, tableName, err.Error())
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to get get data type for column " + columnName + " from table " + tableName + ": " + err.Error())
|
||||
panic(fmt.Sprintf(utils.T("store.sql.table_column_type.critical"), columnName, tableName, err.Error()))
|
||||
}
|
||||
|
||||
return dataType
|
||||
@@ -491,7 +472,7 @@ func (ss SqlStore) GetAllConns() []*gorp.DbMap {
|
||||
}
|
||||
|
||||
func (ss SqlStore) Close() {
|
||||
l4g.Info("Closing SqlStore")
|
||||
l4g.Info(utils.T("store.sql.closing.info"))
|
||||
ss.master.Db.Close()
|
||||
for _, replica := range ss.replicas {
|
||||
replica.Db.Close()
|
||||
@@ -566,7 +547,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool)
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New("FromDb: Unable to convert StringMap to *string")
|
||||
return errors.New(utils.T("store.sql.convert_string_map"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
@@ -576,7 +557,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool)
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New("FromDb: Unable to convert StringArray to *string")
|
||||
return errors.New(utils.T("store.sql.convert_string_array"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
@@ -586,7 +567,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool)
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New("FromDb: Unable to convert EncryptStringMap to *string")
|
||||
return errors.New(utils.T("store.sql.convert_encrypt_string_map"))
|
||||
}
|
||||
|
||||
ue, err := decrypt([]byte(utils.Cfg.SqlSettings.AtRestEncryptKey), *s)
|
||||
@@ -602,7 +583,7 @@ func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool)
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New("FromDb: Unable to convert StringInterface to *string")
|
||||
return errors.New(utils.T("store.sql.convert_string_interface"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
@@ -659,14 +640,14 @@ func decrypt(key []byte, cryptoText string) (string, error) {
|
||||
ekey, akey := skey[:32], skey[32:]
|
||||
macfn := hmac.New(sha256.New, akey)
|
||||
if len(ciphertext) < aes.BlockSize+macfn.Size() {
|
||||
return "", errors.New("short ciphertext")
|
||||
return "", errors.New(utils.T("store.sql.short_ciphertext"))
|
||||
}
|
||||
|
||||
macfn.Write(ciphertext[aes.BlockSize+macfn.Size():])
|
||||
expectedMac := macfn.Sum(nil)
|
||||
mac := ciphertext[aes.BlockSize : aes.BlockSize+macfn.Size()]
|
||||
if hmac.Equal(expectedMac, mac) != true {
|
||||
return "", errors.New("Incorrect MAC for the given ciphertext")
|
||||
return "", errors.New(utils.T("store.sql.incorrect_mac"))
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(ekey)
|
||||
@@ -675,7 +656,7 @@ func decrypt(key []byte, cryptoText string) (string, error) {
|
||||
}
|
||||
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
return "", errors.New("ciphertext too short")
|
||||
return "", errors.New(utils.T("store.sql.too_short_ciphertext"))
|
||||
}
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize+macfn.Size():]
|
||||
|
||||
@@ -16,6 +16,7 @@ var store Store
|
||||
func Setup() {
|
||||
if store == nil {
|
||||
utils.LoadConfig("config.json")
|
||||
utils.InitTranslations()
|
||||
store = NewSqlStore()
|
||||
|
||||
store.MarkSystemRanUnitTests()
|
||||
|
||||
@@ -37,7 +37,7 @@ func (s SqlSystemStore) Save(system *model.System) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if err := s.GetMaster().Insert(system); err != nil {
|
||||
result.Err = model.NewAppError("SqlSystemStore.Save", "We encountered an error saving the system property", "")
|
||||
result.Err = model.NewLocAppError("SqlSystemStore.Save", "store.sql_system.save.app_error", nil, "")
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -55,7 +55,7 @@ func (s SqlSystemStore) Update(system *model.System) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Update(system); err != nil {
|
||||
result.Err = model.NewAppError("SqlSystemStore.Save", "We encountered an error updating the system property", "")
|
||||
result.Err = model.NewLocAppError("SqlSystemStore.Update", "store.sql_system.update.app_error", nil, "")
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -75,7 +75,7 @@ func (s SqlSystemStore) Get() StoreChannel {
|
||||
var systems []model.System
|
||||
props := make(model.StringMap)
|
||||
if _, err := s.GetReplica().Select(&systems, "SELECT * FROM Systems"); err != nil {
|
||||
result.Err = model.NewAppError("SqlSystemStore.Get", "We encountered an error finding the system properties", "")
|
||||
result.Err = model.NewLocAppError("SqlSystemStore.Get", "store.sql_system.get.app_error", nil, "")
|
||||
} else {
|
||||
for _, prop := range systems {
|
||||
props[prop.Name] = prop.Value
|
||||
|
||||
@@ -44,8 +44,8 @@ func (s SqlTeamStore) Save(team *model.Team) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if len(team.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Save",
|
||||
"Must call update for exisiting team", "id="+team.Id)
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Save",
|
||||
"store.sql_team.save.existing.app_error", nil, "id="+team.Id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -61,9 +61,9 @@ func (s SqlTeamStore) Save(team *model.Team) StoreChannel {
|
||||
|
||||
if err := s.GetMaster().Insert(team); err != nil {
|
||||
if IsUniqueConstraintError(err.Error(), "Name", "teams_name_key") {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Save", "A team with that domain already exists", "id="+team.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Save", "store.sql_team.save.domain_exists.app_error", nil, "id="+team.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Save", "We couldn't save the team", "id="+team.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Save", "store.sql_team.save.app_error", nil, "id="+team.Id+", "+err.Error())
|
||||
}
|
||||
} else {
|
||||
result.Data = team
|
||||
@@ -92,9 +92,9 @@ func (s SqlTeamStore) Update(team *model.Team) StoreChannel {
|
||||
}
|
||||
|
||||
if oldResult, err := s.GetMaster().Get(model.Team{}, team.Id); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Update", "We encountered an error finding the team", "id="+team.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Update", "store.sql_team.update.finding.app_error", nil, "id="+team.Id+", "+err.Error())
|
||||
} else if oldResult == nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Update", "We couldn't find the existing team to update", "id="+team.Id)
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Update", "store.sql_team.update.find.app_error", nil, "id="+team.Id)
|
||||
} else {
|
||||
oldTeam := oldResult.(*model.Team)
|
||||
team.CreateAt = oldTeam.CreateAt
|
||||
@@ -102,9 +102,9 @@ func (s SqlTeamStore) Update(team *model.Team) StoreChannel {
|
||||
team.Name = oldTeam.Name
|
||||
|
||||
if count, err := s.GetMaster().Update(team); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Update", "We encountered an error updating the team", "id="+team.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Update", "store.sql_team.update.updating.app_error", nil, "id="+team.Id+", "+err.Error())
|
||||
} else if count != 1 {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Update", "We couldn't update the team", "id="+team.Id)
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Update", "store.sql_team.update.app_error", nil, "id="+team.Id)
|
||||
} else {
|
||||
result.Data = team
|
||||
}
|
||||
@@ -125,7 +125,7 @@ func (s SqlTeamStore) UpdateDisplayName(name string, teamId string) StoreChannel
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Exec("UPDATE Teams SET DisplayName = :Name WHERE Id = :Id", map[string]interface{}{"Name": name, "Id": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.UpdateName", "We couldn't update the team name", "team_id="+teamId)
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.UpdateName", "store.sql_team.update_display_name.app_error", nil, "team_id="+teamId)
|
||||
} else {
|
||||
result.Data = teamId
|
||||
}
|
||||
@@ -144,9 +144,9 @@ func (s SqlTeamStore) Get(id string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if obj, err := s.GetReplica().Get(model.Team{}, id); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Get", "We encountered an error finding the team", "id="+id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Get", "store.sql_team.get.finding.app_error", nil, "id="+id+", "+err.Error())
|
||||
} else if obj == nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Get", "We couldn't find the existing team", "id="+id)
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Get", "store.sql_team.get.find.app_error", nil, "id="+id)
|
||||
} else {
|
||||
team := obj.(*model.Team)
|
||||
if len(team.InviteId) == 0 {
|
||||
@@ -172,7 +172,7 @@ func (s SqlTeamStore) GetByInviteId(inviteId string) StoreChannel {
|
||||
team := model.Team{}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Id = :InviteId OR InviteId = :InviteId", map[string]interface{}{"InviteId": inviteId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetByInviteId", "We couldn't find the existing team", "inviteId="+inviteId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.finding.app_error", nil, "inviteId="+inviteId+", "+err.Error())
|
||||
}
|
||||
|
||||
if len(team.InviteId) == 0 {
|
||||
@@ -180,7 +180,7 @@ func (s SqlTeamStore) GetByInviteId(inviteId string) StoreChannel {
|
||||
}
|
||||
|
||||
if len(inviteId) == 0 || team.InviteId != inviteId {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetByInviteId", "We couldn't find the existing team", "inviteId="+inviteId)
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.find.app_error", nil, "inviteId="+inviteId)
|
||||
}
|
||||
|
||||
result.Data = &team
|
||||
@@ -201,7 +201,7 @@ func (s SqlTeamStore) GetByName(name string) StoreChannel {
|
||||
team := model.Team{}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetByName", "We couldn't find the existing team", "name="+name+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.GetByName", "store.sql_team.get_by_name.app_error", nil, "name="+name+", "+err.Error())
|
||||
}
|
||||
|
||||
if len(team.InviteId) == 0 {
|
||||
@@ -225,7 +225,7 @@ func (s SqlTeamStore) GetTeamsForEmail(email string) StoreChannel {
|
||||
|
||||
var data []*model.Team
|
||||
if _, err := s.GetReplica().Select(&data, "SELECT Teams.* FROM Teams, Users WHERE Teams.Id = Users.TeamId AND Users.Email = :Email", map[string]interface{}{"Email": email}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetTeamsForEmail", "We encountered a problem when looking up teams", "email="+email+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.GetTeamsForEmail", "store.sql_team.get_teams_for_email.app_error", nil, "email="+email+", "+err.Error())
|
||||
}
|
||||
|
||||
for _, team := range data {
|
||||
@@ -251,7 +251,7 @@ func (s SqlTeamStore) GetAll() StoreChannel {
|
||||
|
||||
var data []*model.Team
|
||||
if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams"); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "We could not get all teams", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error())
|
||||
}
|
||||
|
||||
for _, team := range data {
|
||||
@@ -283,7 +283,7 @@ func (s SqlTeamStore) GetAllTeamListing() StoreChannel {
|
||||
|
||||
var data []*model.Team
|
||||
if _, err := s.GetReplica().Select(&data, query); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "We could not get all teams", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all_team_listing.app_error", nil, err.Error())
|
||||
}
|
||||
|
||||
for _, team := range data {
|
||||
@@ -308,7 +308,7 @@ func (s SqlTeamStore) PermanentDelete(teamId string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM Teams WHERE Id = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Delete", "We couldn't delete the existing team", "teamId="+teamId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlTeamStore.Delete", "store.sql_team.permanent_delete.app_error", nil, "teamId="+teamId+", "+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MISSING_ACCOUNT_ERROR = "We couldn't find an existing account matching your email address for this team. This team may require an invite from the team owner to join."
|
||||
MISSING_ACCOUNT_ERROR = "store.sql_user.missing_account.const"
|
||||
)
|
||||
|
||||
type SqlUserStore struct {
|
||||
@@ -46,7 +46,8 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore {
|
||||
}
|
||||
|
||||
func (us SqlUserStore) UpgradeSchemaIfNeeded() {
|
||||
us.CreateColumnIfNotExists("Users", "Locale", "varchar(5)", "character varying(5)", model.DEFAULT_LOCALE) // Added After 1.4
|
||||
// ADDED for 1.5 REMOVE for 1.8
|
||||
us.CreateColumnIfNotExists("Users", "Locale", "varchar(5)", "character varying(5)", model.DEFAULT_LOCALE)
|
||||
}
|
||||
|
||||
func (us SqlUserStore) CreateIndexesIfNotExists() {
|
||||
@@ -62,7 +63,7 @@ func (us SqlUserStore) Save(user *model.User) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if len(user.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlUserStore.Save", "Must call update for exisiting user", "user_id="+user.Id)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.existing.app_error", nil, "user_id="+user.Id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -76,12 +77,12 @@ func (us SqlUserStore) Save(user *model.User) StoreChannel {
|
||||
}
|
||||
|
||||
if count, err := us.GetMaster().SelectInt("SELECT COUNT(0) FROM Users WHERE TeamId = :TeamId AND DeleteAt = 0", map[string]interface{}{"TeamId": user.TeamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.Save", "Failed to get current team member count", "teamId="+user.TeamId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, "teamId="+user.TeamId+", "+err.Error())
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
} else if int(count) > utils.Cfg.TeamSettings.MaxUsersPerTeam {
|
||||
result.Err = model.NewAppError("SqlUserStore.Save", "This team has reached the maxmium number of allowed accounts. Contact your systems administrator to set a higher limit.", "teamId="+user.TeamId)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.max_accounts.app_error", nil, "teamId="+user.TeamId)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -89,11 +90,11 @@ func (us SqlUserStore) Save(user *model.User) StoreChannel {
|
||||
|
||||
if err := us.GetMaster().Insert(user); err != nil {
|
||||
if IsUniqueConstraintError(err.Error(), "Email", "users_email_teamid_key") {
|
||||
result.Err = model.NewAppError("SqlUserStore.Save", "An account with that email already exists.", "user_id="+user.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.email_exists.app_error", nil, "user_id="+user.Id+", "+err.Error())
|
||||
} else if IsUniqueConstraintError(err.Error(), "Username", "users_username_teamid_key") {
|
||||
result.Err = model.NewAppError("SqlUserStore.Save", "An account with that username already exists.", "user_id="+user.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.username_exists.app_error", nil, "user_id="+user.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlUserStore.Save", "We couldn't save the account.", "user_id="+user.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.app_error", nil, "user_id="+user.Id+", "+err.Error())
|
||||
}
|
||||
} else {
|
||||
result.Data = user
|
||||
@@ -122,9 +123,9 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha
|
||||
}
|
||||
|
||||
if oldUserResult, err := us.GetMaster().Get(model.User{}, user.Id); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.Update", "We encountered an error finding the account", "user_id="+user.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.finding.app_error", nil, "user_id="+user.Id+", "+err.Error())
|
||||
} else if oldUserResult == nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.Update", "We couldn't find the existing account to update", "user_id="+user.Id)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.find.app_error", nil, "user_id="+user.Id)
|
||||
} else {
|
||||
oldUser := oldUserResult.(*model.User)
|
||||
user.CreateAt = oldUser.CreateAt
|
||||
@@ -163,14 +164,14 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha
|
||||
|
||||
if count, err := us.GetMaster().Update(user); err != nil {
|
||||
if IsUniqueConstraintError(err.Error(), "Email", "users_email_teamid_key") {
|
||||
result.Err = model.NewAppError("SqlUserStore.Update", "This email is already taken. Please choose another.", "user_id="+user.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.email_taken.app_error", nil, "user_id="+user.Id+", "+err.Error())
|
||||
} else if IsUniqueConstraintError(err.Error(), "Username", "users_username_teamid_key") {
|
||||
result.Err = model.NewAppError("SqlUserStore.Update", "This username is already taken. Please choose another.", "user_id="+user.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.username_taken.app_error", nil, "user_id="+user.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlUserStore.Update", "We encountered an error updating the account", "user_id="+user.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.updating.app_error", nil, "user_id="+user.Id+", "+err.Error())
|
||||
}
|
||||
} else if count != 1 {
|
||||
result.Err = model.NewAppError("SqlUserStore.Update", "We couldn't update the account", fmt.Sprintf("user_id=%v, count=%v", user.Id, count))
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.app_error", nil, fmt.Sprintf("user_id=%v, count=%v", user.Id, count))
|
||||
} else {
|
||||
result.Data = [2]*model.User{user, oldUser}
|
||||
}
|
||||
@@ -192,7 +193,7 @@ func (us SqlUserStore) UpdateLastPictureUpdate(userId string) StoreChannel {
|
||||
curTime := model.GetMillis()
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "We couldn't update the update_at", "user_id="+userId)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdateUpdateAt", "store.sql_user.update_last_picture_update.app_error", nil, "user_id="+userId)
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -211,7 +212,7 @@ func (us SqlUserStore) UpdateLastPingAt(userId string, time int64) StoreChannel
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET LastPingAt = :LastPingAt WHERE Id = :UserId", map[string]interface{}{"LastPingAt": time, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateLastPingAt", "We couldn't update the last_ping_at", "user_id="+userId)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdateLastPingAt", "store.sql_user.update_last_ping.app_error", nil, "user_id="+userId)
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -230,7 +231,7 @@ func (us SqlUserStore) UpdateLastActivityAt(userId string, time int64) StoreChan
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET LastActivityAt = :LastActivityAt WHERE Id = :UserId", map[string]interface{}{"LastActivityAt": time, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateLastActivityAt", "We couldn't update the last_activity_at", "user_id="+userId)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdateLastActivityAt", "store.sql_user.update_last_activity.app_error", nil, "user_id="+userId)
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -249,9 +250,9 @@ func (us SqlUserStore) UpdateUserAndSessionActivity(userId string, sessionId str
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET LastActivityAt = :UserLastActivityAt WHERE Id = :UserId", map[string]interface{}{"UserLastActivityAt": time, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateLastActivityAt", "We couldn't update the last_activity_at", "1 user_id="+userId+" session_id="+sessionId+" err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdateLastActivityAt", "store.sql_user.update_last_activity.app_error", nil, "1 user_id="+userId+" session_id="+sessionId+" err="+err.Error())
|
||||
} else if _, err := us.GetMaster().Exec("UPDATE Sessions SET LastActivityAt = :SessionLastActivityAt WHERE Id = :SessionId", map[string]interface{}{"SessionLastActivityAt": time, "SessionId": sessionId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateLastActivityAt", "We couldn't update the last_activity_at", "2 user_id="+userId+" session_id="+sessionId+" err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdateLastActivityAt", "store.sql_user.update_last_activity.app_error", nil, "2 user_id="+userId+" session_id="+sessionId+" err="+err.Error())
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -273,7 +274,7 @@ func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) StoreChanne
|
||||
updateAt := model.GetMillis()
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET Password = :Password, LastPasswordUpdate = :LastPasswordUpdate, UpdateAt = :UpdateAt, AuthData = '', AuthService = '', FailedAttempts = 0 WHERE Id = :UserId", map[string]interface{}{"Password": hashedPassword, "LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdatePassword", "We couldn't update the user password", "id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdatePassword", "store.sql_user.update_password.app_error", nil, "id="+userId+", "+err.Error())
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -292,7 +293,7 @@ func (us SqlUserStore) UpdateFailedPasswordAttempts(userId string, attempts int)
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET FailedAttempts = :FailedAttempts WHERE Id = :UserId", map[string]interface{}{"FailedAttempts": attempts, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateFailedPasswordAttempts", "We couldn't update the failed_attempts", "user_id="+userId)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdateFailedPasswordAttempts", "store.sql_user.update_failed_pwd_attempts.app_error", nil, "user_id="+userId)
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -314,7 +315,7 @@ func (us SqlUserStore) UpdateAuthData(userId, service, authData string) StoreCha
|
||||
updateAt := model.GetMillis()
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET Password = '', LastPasswordUpdate = :LastPasswordUpdate, UpdateAt = :UpdateAt, FailedAttempts = 0, AuthService = :AuthService, AuthData = :AuthData WHERE Id = :UserId", map[string]interface{}{"LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId, "AuthService": service, "AuthData": authData}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateAuthData", "We couldn't update the auth data", "id="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.UpdateAuthData", "store.sql_user.update_auth_data.app_error", nil, "id="+userId+", "+err.Error())
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
@@ -334,9 +335,9 @@ func (us SqlUserStore) Get(id string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if obj, err := us.GetReplica().Get(model.User{}, id); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.Get", "We encountered an error finding the account", "user_id="+id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Get", "store.sql_user.get.app_error", nil, "user_id="+id+", "+err.Error())
|
||||
} else if obj == nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.Get", MISSING_ACCOUNT_ERROR, "user_id="+id)
|
||||
result.Err = model.NewLocAppError("SqlUserStore.Get", MISSING_ACCOUNT_ERROR, nil, "user_id="+id)
|
||||
} else {
|
||||
result.Data = obj.(*model.User)
|
||||
}
|
||||
@@ -379,7 +380,7 @@ func (us SqlUserStore) GetProfiles(teamId string) StoreChannel {
|
||||
var users []*model.User
|
||||
|
||||
if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetProfiles", "We encountered an error while finding user profiles", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error())
|
||||
} else {
|
||||
|
||||
userMap := make(map[string]*model.User)
|
||||
@@ -410,7 +411,7 @@ func (us SqlUserStore) GetSystemAdminProfiles() StoreChannel {
|
||||
var users []*model.User
|
||||
|
||||
if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Roles = :Roles", map[string]interface{}{"Roles": "system_admin"}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetSystemAdminProfiles", "We encountered an error while finding user profiles", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetSystemAdminProfiles", "store.sql_user.get_sysadmin_profiles.app_error", nil, err.Error())
|
||||
} else {
|
||||
|
||||
userMap := make(map[string]*model.User)
|
||||
@@ -441,7 +442,7 @@ func (us SqlUserStore) GetByEmail(teamId string, email string) StoreChannel {
|
||||
user := model.User{}
|
||||
|
||||
if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE TeamId = :TeamId AND Email = :Email", map[string]interface{}{"TeamId": teamId, "Email": email}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetByEmail", MISSING_ACCOUNT_ERROR, "teamId="+teamId+", email="+email+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetByEmail", MISSING_ACCOUNT_ERROR, nil, "teamId="+teamId+", email="+email+", "+err.Error())
|
||||
}
|
||||
|
||||
result.Data = &user
|
||||
@@ -463,7 +464,8 @@ func (us SqlUserStore) GetByAuth(teamId string, authData string, authService str
|
||||
user := model.User{}
|
||||
|
||||
if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE TeamId = :TeamId AND AuthData = :AuthData AND AuthService = :AuthService", map[string]interface{}{"TeamId": teamId, "AuthData": authData, "AuthService": authService}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetByAuth", "We couldn't find an existing account matching your authentication type for this team. This team may require an invite from the team owner to join.", "teamId="+teamId+", authData="+authData+", authService="+authService+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.app_error",
|
||||
nil, "teamId="+teamId+", authData="+authData+", authService="+authService+", "+err.Error())
|
||||
}
|
||||
|
||||
result.Data = &user
|
||||
@@ -485,7 +487,8 @@ func (us SqlUserStore) GetByUsername(teamId string, username string) StoreChanne
|
||||
user := model.User{}
|
||||
|
||||
if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE TeamId = :TeamId AND Username = :Username", map[string]interface{}{"TeamId": teamId, "Username": username}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetByUsername", "We couldn't find an existing account matching your username for this team. This team may require an invite from the team owner to join.", "teamId="+teamId+", username="+username+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetByUsername", "store.sql_user.get_by_username.app_error",
|
||||
nil, "teamId="+teamId+", username="+username+", "+err.Error())
|
||||
}
|
||||
|
||||
result.Data = &user
|
||||
@@ -504,7 +507,7 @@ func (us SqlUserStore) VerifyEmail(userId string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET EmailVerified = '1' WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.VerifyEmail", "Unable to update verify email field", "userId="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.VerifyEmail", "store.sql_user.verify_email.app_error", nil, "userId="+userId+", "+err.Error())
|
||||
}
|
||||
|
||||
result.Data = userId
|
||||
@@ -526,7 +529,7 @@ func (us SqlUserStore) GetForExport(teamId string) StoreChannel {
|
||||
var users []*model.User
|
||||
|
||||
if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetProfiles", "We encountered an error while finding user profiles", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetProfiles", "store.sql_user.get_for_export.app_error", nil, err.Error())
|
||||
} else {
|
||||
for _, u := range users {
|
||||
u.Password = ""
|
||||
@@ -550,7 +553,7 @@ func (us SqlUserStore) GetTotalUsersCount() StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users"); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetTotalUsersCount", "We could not count the users", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetTotalUsersCount", "store.sql_user.get_total_users_count.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = count
|
||||
}
|
||||
@@ -571,7 +574,7 @@ func (us SqlUserStore) GetTotalActiveUsersCount() StoreChannel {
|
||||
time := model.GetMillis() - (1000 * 60 * 60 * 24)
|
||||
|
||||
if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE LastActivityAt > :Time", map[string]interface{}{"Time": time}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetTotalActiveUsersCount", "We could not count the users", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetTotalActiveUsersCount", "store.sql_user.get_total_active_users_count.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = count
|
||||
}
|
||||
@@ -591,7 +594,7 @@ func (us SqlUserStore) PermanentDelete(userId string) StoreChannel {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := us.GetMaster().Exec("DELETE FROM Users WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetByEmail", "We couldn't delete the existing account", "userId="+userId+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetByEmail", "store.sql_user.permanent_delete.app_error", nil, "userId="+userId+", "+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -616,7 +619,7 @@ func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) StoreChannel {
|
||||
|
||||
v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.AnalyticsUniqueUserCount", "We couldn't get the unique user count", err.Error())
|
||||
result.Err = model.NewLocAppError("SqlUserStore.AnalyticsUniqueUserCount", "store.sql_user.analytics_unique_user_count.app_error", nil, err.Error())
|
||||
} else {
|
||||
result.Data = v
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) StoreChann
|
||||
result := StoreResult{}
|
||||
|
||||
if len(webhook.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.SaveIncoming",
|
||||
"You cannot overwrite an existing IncomingWebhook", "id="+webhook.Id)
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.SaveIncoming",
|
||||
"store.sql_webhooks.save_incoming.existing.app_error", nil, "id="+webhook.Id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -65,7 +65,7 @@ func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) StoreChann
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(webhook); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.SaveIncoming", "We couldn't save the IncomingWebhook", "id="+webhook.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.SaveIncoming", "store.sql_webhooks.save_incoming.app_error", nil, "id="+webhook.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Data = webhook
|
||||
}
|
||||
@@ -86,7 +86,7 @@ func (s SqlWebhookStore) GetIncoming(id string) StoreChannel {
|
||||
var webhook model.IncomingWebhook
|
||||
|
||||
if err := s.GetReplica().SelectOne(&webhook, "SELECT * FROM IncomingWebhooks WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.GetIncoming", "We couldn't get the webhook", "id="+id+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.GetIncoming", "store.sql_webhooks.get_incoming.app_error", nil, "id="+id+", err="+err.Error())
|
||||
}
|
||||
|
||||
result.Data = &webhook
|
||||
@@ -106,7 +106,7 @@ func (s SqlWebhookStore) DeleteIncoming(webhookId string, time int64) StoreChann
|
||||
|
||||
_, err := s.GetMaster().Exec("Update IncomingWebhooks SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": webhookId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.DeleteIncoming", "We couldn't delete the webhook", "id="+webhookId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteIncoming", "store.sql_webhooks.delete_incoming.app_error", nil, "id="+webhookId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -124,7 +124,7 @@ func (s SqlWebhookStore) PermanentDeleteIncomingByUser(userId string) StoreChann
|
||||
|
||||
_, err := s.GetMaster().Exec("DELETE FROM IncomingWebhooks WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.DeleteIncomingByUser", "We couldn't delete the webhook", "id="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteIncomingByUser", "store.sql_webhooks.permanent_delete_incoming_by_user.app_error", nil, "id="+userId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -143,7 +143,7 @@ func (s SqlWebhookStore) GetIncomingByTeam(teamId string) StoreChannel {
|
||||
var webhooks []*model.IncomingWebhook
|
||||
|
||||
if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE TeamId = :TeamId AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.GetIncomingByUser", "We couldn't get the webhook", "teamId="+teamId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.GetIncomingByUser", "store.sql_webhooks.get_incoming_by_user.app_error", nil, "teamId="+teamId+", err="+err.Error())
|
||||
}
|
||||
|
||||
result.Data = webhooks
|
||||
@@ -164,7 +164,7 @@ func (s SqlWebhookStore) GetIncomingByChannel(channelId string) StoreChannel {
|
||||
var webhooks []*model.IncomingWebhook
|
||||
|
||||
if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0", map[string]interface{}{"ChannelId": channelId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.GetIncomingByChannel", "We couldn't get the webhooks", "channelId="+channelId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.GetIncomingByChannel", "store.sql_webhooks.get_incoming_by_channel.app_error", nil, "channelId="+channelId+", err="+err.Error())
|
||||
}
|
||||
|
||||
result.Data = webhooks
|
||||
@@ -183,8 +183,8 @@ func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) StoreChann
|
||||
result := StoreResult{}
|
||||
|
||||
if len(webhook.Id) > 0 {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.SaveOutgoing",
|
||||
"You cannot overwrite an existing OutgoingWebhook", "id="+webhook.Id)
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.SaveOutgoing",
|
||||
"store.sql_webhooks.save_outgoing.override.app_error", nil, "id="+webhook.Id)
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
@@ -198,7 +198,7 @@ func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) StoreChann
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(webhook); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.SaveOutgoing", "We couldn't save the OutgoingWebhook", "id="+webhook.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.SaveOutgoing", "store.sql_webhooks.save_outgoing.app_error", nil, "id="+webhook.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Data = webhook
|
||||
}
|
||||
@@ -219,7 +219,7 @@ func (s SqlWebhookStore) GetOutgoing(id string) StoreChannel {
|
||||
var webhook model.OutgoingWebhook
|
||||
|
||||
if err := s.GetReplica().SelectOne(&webhook, "SELECT * FROM OutgoingWebhooks WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.GetOutgoing", "We couldn't get the webhook", "id="+id+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.GetOutgoing", "store.sql_webhooks.get_outgoing.app_error", nil, "id="+id+", err="+err.Error())
|
||||
}
|
||||
|
||||
result.Data = &webhook
|
||||
@@ -240,7 +240,7 @@ func (s SqlWebhookStore) GetOutgoingByChannel(channelId string) StoreChannel {
|
||||
var webhooks []*model.OutgoingWebhook
|
||||
|
||||
if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM OutgoingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0", map[string]interface{}{"ChannelId": channelId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.GetOutgoingByChannel", "We couldn't get the webhooks", "channelId="+channelId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.GetOutgoingByChannel", "store.sql_webhooks.get_outgoing_by_channel.app_error", nil, "channelId="+channelId+", err="+err.Error())
|
||||
}
|
||||
|
||||
result.Data = webhooks
|
||||
@@ -261,7 +261,7 @@ func (s SqlWebhookStore) GetOutgoingByTeam(teamId string) StoreChannel {
|
||||
var webhooks []*model.OutgoingWebhook
|
||||
|
||||
if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM OutgoingWebhooks WHERE TeamId = :TeamId AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.GetOutgoingByTeam", "We couldn't get the webhooks", "teamId="+teamId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.GetOutgoingByTeam", "store.sql_webhooks.get_outgoing_by_team.app_error", nil, "teamId="+teamId+", err="+err.Error())
|
||||
}
|
||||
|
||||
result.Data = webhooks
|
||||
@@ -281,7 +281,7 @@ func (s SqlWebhookStore) DeleteOutgoing(webhookId string, time int64) StoreChann
|
||||
|
||||
_, err := s.GetMaster().Exec("Update OutgoingWebhooks SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": webhookId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.DeleteOutgoing", "We couldn't delete the webhook", "id="+webhookId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteOutgoing", "store.sql_webhooks.delete_outgoing.app_error", nil, "id="+webhookId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -299,7 +299,7 @@ func (s SqlWebhookStore) PermanentDeleteOutgoingByUser(userId string) StoreChann
|
||||
|
||||
_, err := s.GetMaster().Exec("DELETE FROM OutgoingWebhooks WHERE CreatorId = :UserId", map[string]interface{}{"UserId": userId})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.DeleteOutgoingByUser", "We couldn't delete the webhook", "id="+userId+", err="+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteOutgoingByUser", "store.sql_webhooks.permanent_delete_outgoing_by_user.app_error", nil, "id="+userId+", err="+err.Error())
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
@@ -318,7 +318,7 @@ func (s SqlWebhookStore) UpdateOutgoing(hook *model.OutgoingWebhook) StoreChanne
|
||||
hook.UpdateAt = model.GetMillis()
|
||||
|
||||
if _, err := s.GetMaster().Update(hook); err != nil {
|
||||
result.Err = model.NewAppError("SqlWebhookStore.UpdateOutgoing", "We couldn't update the webhook", "id="+hook.Id+", "+err.Error())
|
||||
result.Err = model.NewLocAppError("SqlWebhookStore.UpdateOutgoing", "store.sql_webhooks.update_outgoing.app_error", nil, "id="+hook.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Data = hook
|
||||
}
|
||||
|
||||
@@ -138,6 +138,7 @@ type SessionStore interface {
|
||||
PermanentDeleteSessionsByUser(teamId string) StoreChannel
|
||||
UpdateLastActivityAt(sessionId string, time int64) StoreChannel
|
||||
UpdateRoles(userId string, roles string) StoreChannel
|
||||
UpdateDeviceId(id string, deviceId string) StoreChannel
|
||||
}
|
||||
|
||||
type AuditStore interface {
|
||||
|
||||
@@ -44,7 +44,7 @@ func GetTranslationsBySystemLocale() i18n.TranslateFunc {
|
||||
panic("Failed to load system translations for '" + model.DEFAULT_LOCALE + "'")
|
||||
}
|
||||
|
||||
translations, _ := i18n.Tfunc(locale)
|
||||
translations := TfuncWithFallback(locale)
|
||||
if translations == nil {
|
||||
panic("Failed to load system translations")
|
||||
}
|
||||
@@ -58,22 +58,34 @@ func GetUserTranslations(locale string) i18n.TranslateFunc {
|
||||
locale = model.DEFAULT_LOCALE
|
||||
}
|
||||
|
||||
translations, _ := i18n.Tfunc(locale)
|
||||
translations := TfuncWithFallback(locale)
|
||||
return translations
|
||||
}
|
||||
|
||||
func SetTranslations(locale string) i18n.TranslateFunc {
|
||||
translations, _ := i18n.Tfunc(locale)
|
||||
translations := TfuncWithFallback(locale)
|
||||
return translations
|
||||
}
|
||||
|
||||
func GetTranslationsAndLocale(w http.ResponseWriter, r *http.Request) (i18n.TranslateFunc, string) {
|
||||
headerLocale := strings.Split(strings.Split(r.Header.Get("Accept-Language"), ",")[0], "-")[0]
|
||||
if locales[headerLocale] != "" {
|
||||
translations, _ := i18n.Tfunc(headerLocale)
|
||||
translations := TfuncWithFallback(headerLocale)
|
||||
return translations, headerLocale
|
||||
}
|
||||
|
||||
translations, _ := i18n.Tfunc(model.DEFAULT_LOCALE)
|
||||
translations := TfuncWithFallback(model.DEFAULT_LOCALE)
|
||||
return translations, model.DEFAULT_LOCALE
|
||||
}
|
||||
|
||||
func TfuncWithFallback(pref string) i18n.TranslateFunc {
|
||||
t, _ := i18n.Tfunc(pref)
|
||||
return func(translationID string, args ...interface{}) string {
|
||||
if translated := t(translationID, args...); translated != translationID {
|
||||
return translated
|
||||
}
|
||||
|
||||
t, _ := i18n.Tfunc("en")
|
||||
return t(translationID, args...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
var Modal = ReactBootstrap.Modal;
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class AboutBuildModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -17,13 +19,28 @@ export default class AboutBuildModal extends React.Component {
|
||||
const config = global.window.mm_config;
|
||||
const license = global.window.mm_license;
|
||||
|
||||
let title = 'Team Edition';
|
||||
let title = (
|
||||
<FormattedMessage
|
||||
id='about.teamEdtion'
|
||||
defaultMessage='Team Edition'
|
||||
/>
|
||||
);
|
||||
let licensee;
|
||||
if (config.BuildEnterpriseReady === 'true' && license.IsLicensed === 'true') {
|
||||
title = 'Enterprise Edition';
|
||||
title = (
|
||||
<FormattedMessage
|
||||
id='about.enterpriseEdition'
|
||||
defaultMessage='Enterprise Edition'
|
||||
/>
|
||||
);
|
||||
licensee = (
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>{'Licensed by:'}</div>
|
||||
<div className='col-sm-3 info__label'>
|
||||
<FormattedMessage
|
||||
id='about.licensed'
|
||||
defaultMessage='Licensed by:'
|
||||
/>
|
||||
</div>
|
||||
<div className='col-sm-9'>{license.Company}</div>
|
||||
</div>
|
||||
);
|
||||
@@ -35,25 +52,50 @@ export default class AboutBuildModal extends React.Component {
|
||||
onHide={this.doHide}
|
||||
>
|
||||
<Modal.Header closeButton={true}>
|
||||
<Modal.Title>{'About Mattermost'}</Modal.Title>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id='about.title'
|
||||
defaultMessage='About Mattermost'
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<h4>{`Mattermost ${title}`}</h4>
|
||||
<h4>{'Mattermost'} {title}</h4>
|
||||
{licensee}
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>{'Version:'}</div>
|
||||
<div className='col-sm-3 info__label'>
|
||||
<FormattedMessage
|
||||
id='about.version'
|
||||
defaultMessage='Version:'
|
||||
/>
|
||||
</div>
|
||||
<div className='col-sm-9'>{config.Version}</div>
|
||||
</div>
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>{'Build Number:'}</div>
|
||||
<div className='col-sm-3 info__label'>
|
||||
<FormattedMessage
|
||||
id='about.number'
|
||||
defaultMessage='Build Number:'
|
||||
/>
|
||||
</div>
|
||||
<div className='col-sm-9'>{config.BuildNumber}</div>
|
||||
</div>
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>{'Build Date:'}</div>
|
||||
<div className='col-sm-3 info__label'>
|
||||
<FormattedMessage
|
||||
id='about.date'
|
||||
defaultMessage='Build Date:'
|
||||
/>
|
||||
</div>
|
||||
<div className='col-sm-9'>{config.BuildDate}</div>
|
||||
</div>
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>{'Build Hash:'}</div>
|
||||
<div className='col-sm-3 info__label'>
|
||||
<FormattedMessage
|
||||
id='about.hash'
|
||||
defaultMessage='Build Hash:'
|
||||
/>
|
||||
</div>
|
||||
<div className='col-sm-9'>{config.BuildHash}</div>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
@@ -63,7 +105,10 @@ export default class AboutBuildModal extends React.Component {
|
||||
className='btn btn-default'
|
||||
onClick={this.doHide}
|
||||
>
|
||||
{'Close'}
|
||||
<FormattedMessage
|
||||
id='about.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
|
||||
@@ -8,7 +8,188 @@ import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
export default class AccessHistoryModal extends React.Component {
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
sessionRevoked: {
|
||||
id: 'access_history.sessionRevoked',
|
||||
defaultMessage: 'The session with id {sessionId} was revoked'
|
||||
},
|
||||
channelCreated: {
|
||||
id: 'access_history.channelCreated',
|
||||
defaultMessage: 'Created the {channelName} channel/group'
|
||||
},
|
||||
establishedDM: {
|
||||
id: 'access_history.establishedDM',
|
||||
defaultMessage: 'Established a direct message channel with {username}'
|
||||
},
|
||||
nameUpdated: {
|
||||
id: 'access_history.nameUpdated',
|
||||
defaultMessage: 'Updated the {channelName} channel/group name'
|
||||
},
|
||||
headerUpdated: {
|
||||
id: 'access_history.headerUpdated',
|
||||
defaultMessage: 'Updated the {channelName} channel/group header'
|
||||
},
|
||||
channelDeleted: {
|
||||
id: 'access_history.channelDeleted',
|
||||
defaultMessage: 'Deleted the channel/group with the URL {url}'
|
||||
},
|
||||
userAdded: {
|
||||
id: 'access_history.userAdded',
|
||||
defaultMessage: 'Added {username} to the {channelName} channel/group'
|
||||
},
|
||||
userRemoved: {
|
||||
id: 'access_history.userRemoved',
|
||||
defaultMessage: 'Removed {username} to the {channelName} channel/group'
|
||||
},
|
||||
attemptedRegisterApp: {
|
||||
id: 'access_history.attemptedRegisterApp',
|
||||
defaultMessage: 'Attempted to register a new OAuth Application with ID {id}'
|
||||
},
|
||||
attemptedAllowOAuthAccess: {
|
||||
id: 'access_history.attemptedAllowOAuthAccess',
|
||||
defaultMessage: 'Attempted to allow a new OAuth service access'
|
||||
},
|
||||
successfullOAuthAccess: {
|
||||
id: 'access_history.successfullOAuthAccess',
|
||||
defaultMessage: 'Successfully gave a new OAuth service access'
|
||||
},
|
||||
failedOAuthAccess: {
|
||||
id: 'access_history.failedOAuthAccess',
|
||||
defaultMessage: 'Failed to allow a new OAuth service access - the redirect URI did not match the previously registered callback'
|
||||
},
|
||||
attemptedOAuthToken: {
|
||||
id: 'access_history.attemptedOAuthToken',
|
||||
defaultMessage: 'Attempted to get an OAuth access token'
|
||||
},
|
||||
successfullOAuthToken: {
|
||||
id: 'access_history.successfullOAuthToken',
|
||||
defaultMessage: 'Successfully added a new OAuth service'
|
||||
},
|
||||
oauthTokenFailed: {
|
||||
id: 'access_history.oauthTokenFailed',
|
||||
defaultMessage: 'Failed to get an OAuth access token - {token}'
|
||||
},
|
||||
attemptedLogin: {
|
||||
id: 'access_history.attemptedLogin',
|
||||
defaultMessage: 'Attempted to login'
|
||||
},
|
||||
successfullLogin: {
|
||||
id: 'access_history.successfullLogin',
|
||||
defaultMessage: 'Successfully logged in'
|
||||
},
|
||||
failedLogin: {
|
||||
id: 'access_history.failedLogin',
|
||||
defaultMessage: 'FAILED login attempt'
|
||||
},
|
||||
updatePicture: {
|
||||
id: 'access_history.updatePicture',
|
||||
defaultMessage: 'Updated your profile picture'
|
||||
},
|
||||
updateGeneral: {
|
||||
id: 'access_history.updateGeneral',
|
||||
defaultMessage: 'Updated the general settings of your account'
|
||||
},
|
||||
attemptedPassword: {
|
||||
id: 'access_history.attemptedPassword',
|
||||
defaultMessage: 'Attempted to change password'
|
||||
},
|
||||
successfullPassword: {
|
||||
id: 'access_history.successfullPassword',
|
||||
defaultMessage: 'Successfully changed password'
|
||||
},
|
||||
failedPassword: {
|
||||
id: 'access_history.failedPassword',
|
||||
defaultMessage: 'Failed to change password - tried to update user password who was logged in through oauth'
|
||||
},
|
||||
updatedRol: {
|
||||
id: 'access_history.updatedRol',
|
||||
defaultMessage: 'Updated user role(s) to '
|
||||
},
|
||||
member: {
|
||||
id: 'access_history.member',
|
||||
defaultMessage: 'member'
|
||||
},
|
||||
accountActive: {
|
||||
id: 'access_history.accountActive',
|
||||
defaultMessage: 'Account made active'
|
||||
},
|
||||
accountInactive: {
|
||||
id: 'access_history.accountInactive',
|
||||
defaultMessage: 'Account made inactive'
|
||||
},
|
||||
by: {
|
||||
id: 'access_history.by',
|
||||
defaultMessage: ' by {username}'
|
||||
},
|
||||
byAdmin: {
|
||||
id: 'access_history.byAdmin',
|
||||
defaultMessage: ' by an admin'
|
||||
},
|
||||
sentEmail: {
|
||||
id: 'access_history.sentEmail',
|
||||
defaultMessage: 'Sent an email to {email} to reset your password'
|
||||
},
|
||||
attemptedReset: {
|
||||
id: 'access_history.attemptedReset',
|
||||
defaultMessage: 'Attempted to reset password'
|
||||
},
|
||||
successfullReset: {
|
||||
id: 'access_history.successfullReset',
|
||||
defaultMessage: 'Successfully reset password'
|
||||
},
|
||||
updateGlobalNotifications: {
|
||||
id: 'access_history.updateGlobalNotifications',
|
||||
defaultMessage: 'Updated your global notification settings'
|
||||
},
|
||||
attemptedWebhookCreate: {
|
||||
id: 'access_history.attemptedWebhookCreate',
|
||||
defaultMessage: 'Attempted to create a webhook'
|
||||
},
|
||||
succcessfullWebhookCreate: {
|
||||
id: 'access_history.successfullWebhookCreate',
|
||||
defaultMessage: 'Successfully created a webhook'
|
||||
},
|
||||
failedWebhookCreate: {
|
||||
id: 'access_history.failedWebhookCreate',
|
||||
defaultMessage: 'Failed to create a webhook - bad channel permissions'
|
||||
},
|
||||
attemptedWebhookDelete: {
|
||||
id: 'access_history.attemptedWebhookDelete',
|
||||
defaultMessage: 'Attempted to delete a webhook'
|
||||
},
|
||||
successfullWebhookDelete: {
|
||||
id: 'access_history.successfullWebhookDelete',
|
||||
defaultMessage: 'Successfully deleted a webhook'
|
||||
},
|
||||
failedWebhookDelete: {
|
||||
id: 'access_history.failedWebhookDelete',
|
||||
defaultMessage: 'Failed to delete a webhook - inappropriate conditions'
|
||||
},
|
||||
logout: {
|
||||
id: 'access_history.logout',
|
||||
defaultMessage: 'Logged out of your account'
|
||||
},
|
||||
verified: {
|
||||
id: 'access_history.verified',
|
||||
defaultMessage: 'Sucessfully verified your email address'
|
||||
},
|
||||
revokedAll: {
|
||||
id: 'access_history.revokedAll',
|
||||
defaultMessage: 'Revoked all current sessions for the team'
|
||||
},
|
||||
loginAttempt: {
|
||||
id: 'access_history.loginAttempt',
|
||||
defaultMessage: ' (Login attempt)'
|
||||
},
|
||||
loginFailure: {
|
||||
id: 'access_history.loginFailure',
|
||||
defaultMessage: ' (Login failure)'
|
||||
}
|
||||
});
|
||||
|
||||
class AccessHistoryModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -70,11 +251,12 @@ export default class AccessHistoryModal extends React.Component {
|
||||
this.setState({moreInfo: newMoreInfo});
|
||||
}
|
||||
handleRevokedSession(sessionId) {
|
||||
return 'The session with id ' + sessionId + ' was revoked';
|
||||
return this.props.intl.formatMessage(holders.sessionRevoked, {sessionId: sessionId});
|
||||
}
|
||||
formatAuditInfo(currentAudit) {
|
||||
const currentActionURL = currentAudit.action.replace(/\/api\/v[1-9]/, '');
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
let currentAuditDesc = '';
|
||||
|
||||
if (currentActionURL.indexOf('/channels') === 0) {
|
||||
@@ -96,17 +278,17 @@ export default class AccessHistoryModal extends React.Component {
|
||||
|
||||
switch (currentActionURL) {
|
||||
case '/channels/create':
|
||||
currentAuditDesc = 'Created the ' + channelName + ' channel/group';
|
||||
currentAuditDesc = formatMessage(holders.channelCreated, {channelName: channelName});
|
||||
break;
|
||||
case '/channels/create_direct':
|
||||
currentAuditDesc = 'Established a direct message channel with ' + Utils.getDirectTeammate(channelObj.id).username;
|
||||
currentAuditDesc = formatMessage(holders.establishedDM, {username: Utils.getDirectTeammate(channelObj.id).username});
|
||||
break;
|
||||
case '/channels/update':
|
||||
currentAuditDesc = 'Updated the ' + channelName + ' channel/group name';
|
||||
currentAuditDesc = formatMessage(holders.nameUpdated, {channelName: channelName});
|
||||
break;
|
||||
case '/channels/update_desc': // support the old path
|
||||
case '/channels/update_header':
|
||||
currentAuditDesc = 'Updated the ' + channelName + ' channel/group header';
|
||||
currentAuditDesc = formatMessage(holders.headerUpdated, {channelName: channelName});
|
||||
break;
|
||||
default: {
|
||||
let userIdField = [];
|
||||
@@ -123,11 +305,11 @@ export default class AccessHistoryModal extends React.Component {
|
||||
}
|
||||
|
||||
if (/\/channels\/[A-Za-z0-9]+\/delete/.test(currentActionURL)) {
|
||||
currentAuditDesc = 'Deleted the channel/group with the URL ' + channelURL;
|
||||
currentAuditDesc = formatMessage(holders.channelDeleted, {url: channelURL});
|
||||
} else if (/\/channels\/[A-Za-z0-9]+\/add/.test(currentActionURL)) {
|
||||
currentAuditDesc = 'Added ' + username + ' to the ' + channelName + ' channel/group';
|
||||
currentAuditDesc = formatMessage(holders.userAdded, {username: username, channelName: channelName});
|
||||
} else if (/\/channels\/[A-Za-z0-9]+\/remove/.test(currentActionURL)) {
|
||||
currentAuditDesc = 'Removed ' + username + ' from the ' + channelName + ' channel/group';
|
||||
currentAuditDesc = formatMessage(holders.userRemoved, {username: username, channelName: channelName});
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -141,31 +323,31 @@ export default class AccessHistoryModal extends React.Component {
|
||||
const clientIdField = oauthInfo[0].split('=');
|
||||
|
||||
if (clientIdField[0] === 'client_id') {
|
||||
currentAuditDesc = 'Attempted to register a new OAuth Application with ID ' + clientIdField[1];
|
||||
currentAuditDesc = formatMessage(holders.attemptedRegisterApp, {id: clientIdField[1]});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case '/oauth/allow':
|
||||
if (oauthInfo[0] === 'attempt') {
|
||||
currentAuditDesc = 'Attempted to allow a new OAuth service access';
|
||||
currentAuditDesc = formatMessage(holders.attemptedAllowOAuthAccess);
|
||||
} else if (oauthInfo[0] === 'success') {
|
||||
currentAuditDesc = 'Successfully gave a new OAuth service access';
|
||||
currentAuditDesc = formatMessage(holders.successfullOAuthAccess);
|
||||
} else if (oauthInfo[0] === 'fail - redirect_uri did not match registered callback') {
|
||||
currentAuditDesc = 'Failed to allow a new OAuth service access - the redirect URI did not match the previously registered callback';
|
||||
currentAuditDesc = formatMessage(holders.failedOAuthAccess);
|
||||
}
|
||||
|
||||
break;
|
||||
case '/oauth/access_token':
|
||||
if (oauthInfo[0] === 'attempt') {
|
||||
currentAuditDesc = 'Attempted to get an OAuth access token';
|
||||
currentAuditDesc = formatMessage(holders.attemptedOAuthToken);
|
||||
} else if (oauthInfo[0] === 'success') {
|
||||
currentAuditDesc = 'Successfully added a new OAuth service';
|
||||
currentAuditDesc = formatMessage(holders.successfullOAuthToken);
|
||||
} else {
|
||||
const oauthTokenFailure = oauthInfo[0].split('-');
|
||||
|
||||
if (oauthTokenFailure[0].trim() === 'fail' && oauthTokenFailure[1]) {
|
||||
currentAuditDesc = 'Failed to get an OAuth access token - ' + oauthTokenFailure[1].trim();
|
||||
currentAuditDesc = formatMessage(oauthTokenFailure, {token: oauthTokenFailure[1].trim()});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,11 +361,11 @@ export default class AccessHistoryModal extends React.Component {
|
||||
switch (currentActionURL) {
|
||||
case '/users/login':
|
||||
if (userInfo[0] === 'attempt') {
|
||||
currentAuditDesc = 'Attempted to login';
|
||||
currentAuditDesc = formatMessage(holders.attemptedLogin);
|
||||
} else if (userInfo[0] === 'success') {
|
||||
currentAuditDesc = 'Successfully logged in';
|
||||
currentAuditDesc = formatMessage(holders.successfullLogin);
|
||||
} else if (userInfo[0]) {
|
||||
currentAuditDesc = 'FAILED login attempt';
|
||||
currentAuditDesc = formatMessage(holders.failedLogin);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -191,29 +373,29 @@ export default class AccessHistoryModal extends React.Component {
|
||||
currentAuditDesc = this.handleRevokedSession(userInfo[0].split('=')[1]);
|
||||
break;
|
||||
case '/users/newimage':
|
||||
currentAuditDesc = 'Updated your profile picture';
|
||||
currentAuditDesc = formatMessage(holders.updatePicture);
|
||||
break;
|
||||
case '/users/update':
|
||||
currentAuditDesc = 'Updated the general settings of your account';
|
||||
currentAuditDesc = formatMessage(holders.updateGeneral);
|
||||
break;
|
||||
case '/users/newpassword':
|
||||
if (userInfo[0] === 'attempted') {
|
||||
currentAuditDesc = 'Attempted to change password';
|
||||
currentAuditDesc = formatMessage(holders.attemptedPassword);
|
||||
} else if (userInfo[0] === 'completed') {
|
||||
currentAuditDesc = 'Successfully changed password';
|
||||
currentAuditDesc = formatMessage(holders.successfullPassword);
|
||||
} else if (userInfo[0] === 'failed - tried to update user password who was logged in through oauth') {
|
||||
currentAuditDesc = 'Failed to change password - tried to update user password who was logged in through oauth';
|
||||
currentAuditDesc = formatMessage(holders.failedPassword);
|
||||
}
|
||||
|
||||
break;
|
||||
case '/users/update_roles': {
|
||||
const userRoles = userInfo[0].split('=')[1];
|
||||
|
||||
currentAuditDesc = 'Updated user role(s) to ';
|
||||
currentAuditDesc = formatMessage(holders.updatedRol);
|
||||
if (userRoles.trim()) {
|
||||
currentAuditDesc += userRoles;
|
||||
} else {
|
||||
currentAuditDesc += 'member';
|
||||
currentAuditDesc += formatMessage(holders.member);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -225,9 +407,9 @@ export default class AccessHistoryModal extends React.Component {
|
||||
/* Either describes account activation/deactivation or a revoked session as part of an account deactivation */
|
||||
if (updateType === 'active') {
|
||||
if (updateField === 'true') {
|
||||
currentAuditDesc = 'Account made active';
|
||||
currentAuditDesc = formatMessage(holders.accountActive);
|
||||
} else if (updateField === 'false') {
|
||||
currentAuditDesc = 'Account made inactive';
|
||||
currentAuditDesc = formatMessage(holders.accountInactive);
|
||||
}
|
||||
|
||||
const actingUserInfo = userInfo[1].split('=');
|
||||
@@ -235,9 +417,9 @@ export default class AccessHistoryModal extends React.Component {
|
||||
const actingUser = UserStore.getProfile(actingUserInfo[1]);
|
||||
const currentUser = UserStore.getCurrentUser();
|
||||
if (currentUser && actingUser && (Utils.isAdmin(currentUser.roles) || Utils.isSystemAdmin(currentUser.roles))) {
|
||||
currentAuditDesc += ' by ' + actingUser.username;
|
||||
currentAuditDesc += formatMessage(holders.by, {username: actingUser.username});
|
||||
} else if (currentUser && actingUser) {
|
||||
currentAuditDesc += ' by an admin';
|
||||
currentAuditDesc += formatMessage(holders.byAdmin);
|
||||
}
|
||||
}
|
||||
} else if (updateType === 'session_id') {
|
||||
@@ -247,18 +429,18 @@ export default class AccessHistoryModal extends React.Component {
|
||||
break;
|
||||
}
|
||||
case '/users/send_password_reset':
|
||||
currentAuditDesc = 'Sent an email to ' + userInfo[0].split('=')[1] + ' to reset your password';
|
||||
currentAuditDesc = formatMessage(holders.sentEmail, {email: userInfo[0].split('=')[1]});
|
||||
break;
|
||||
case '/users/reset_password':
|
||||
if (userInfo[0] === 'attempt') {
|
||||
currentAuditDesc = 'Attempted to reset password';
|
||||
currentAuditDesc = formatMessage(holders.attemptedReset);
|
||||
} else if (userInfo[0] === 'success') {
|
||||
currentAuditDesc = 'Successfully reset password';
|
||||
currentAuditDesc = formatMessage(holders.successfullReset);
|
||||
}
|
||||
|
||||
break;
|
||||
case '/users/update_notify':
|
||||
currentAuditDesc = 'Updated your global notification settings';
|
||||
currentAuditDesc = formatMessage(holders.updateGlobalNotifications);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -269,21 +451,21 @@ export default class AccessHistoryModal extends React.Component {
|
||||
switch (currentActionURL) {
|
||||
case '/hooks/incoming/create':
|
||||
if (webhookInfo[0] === 'attempt') {
|
||||
currentAuditDesc = 'Attempted to create a webhook';
|
||||
currentAuditDesc = formatMessage(holders.attemptedWebhookCreate);
|
||||
} else if (webhookInfo[0] === 'success') {
|
||||
currentAuditDesc = 'Successfully created a webhook';
|
||||
currentAuditDesc = formatMessage(holders.succcessfullWebhookCreate);
|
||||
} else if (webhookInfo[0] === 'fail - bad channel permissions') {
|
||||
currentAuditDesc = 'Failed to create a webhook - bad channel permissions';
|
||||
currentAuditDesc = formatMessage(holders.failedWebhookCreate);
|
||||
}
|
||||
|
||||
break;
|
||||
case '/hooks/incoming/delete':
|
||||
if (webhookInfo[0] === 'attempt') {
|
||||
currentAuditDesc = 'Attempted to delete a webhook';
|
||||
currentAuditDesc = formatMessage(holders.attemptedWebhookDelete);
|
||||
} else if (webhookInfo[0] === 'success') {
|
||||
currentAuditDesc = 'Successfully deleted a webhook';
|
||||
currentAuditDesc = formatMessage(holders.successfullWebhookDelete);
|
||||
} else if (webhookInfo[0] === 'fail - inappropriate conditions') {
|
||||
currentAuditDesc = 'Failed to delete a webhook - inappropriate conditions';
|
||||
currentAuditDesc = formatMessage(holders.failedWebhookDelete);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -293,10 +475,10 @@ export default class AccessHistoryModal extends React.Component {
|
||||
} else {
|
||||
switch (currentActionURL) {
|
||||
case '/logout':
|
||||
currentAuditDesc = 'Logged out of your account';
|
||||
currentAuditDesc = formatMessage(holders.logout);
|
||||
break;
|
||||
case '/verify_email':
|
||||
currentAuditDesc = 'Sucessfully verified your email address';
|
||||
currentAuditDesc = formatMessage(holders.verified);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -307,7 +489,7 @@ export default class AccessHistoryModal extends React.Component {
|
||||
if (!currentAuditDesc) {
|
||||
/* Currently not called anywhere */
|
||||
if (currentAudit.extra_info.indexOf('revoked_all=') >= 0) {
|
||||
currentAuditDesc = 'Revoked all current sessions for the team';
|
||||
currentAuditDesc = formatMessage(holders.revokedAll);
|
||||
} else {
|
||||
let currentActionDesc = '';
|
||||
if (currentActionURL && currentActionURL.lastIndexOf('/') !== -1) {
|
||||
@@ -328,12 +510,14 @@ export default class AccessHistoryModal extends React.Component {
|
||||
}
|
||||
|
||||
const currentDate = new Date(currentAudit.create_at);
|
||||
const currentAuditInfo = currentDate.toDateString() + ' - ' + currentDate.toLocaleTimeString(navigator.language, {hour: '2-digit', minute: '2-digit'}) + ' | ' + currentAuditDesc;
|
||||
const currentAuditInfo = currentDate.toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'}) + ' - ' +
|
||||
currentDate.toLocaleTimeString(global.window.mm_locale, {hour: '2-digit', minute: '2-digit'}) + ' | ' + currentAuditDesc;
|
||||
return currentAuditInfo;
|
||||
}
|
||||
render() {
|
||||
var accessList = [];
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
for (var i = 0; i < this.state.audits.length; i++) {
|
||||
const currentAudit = this.state.audits[i];
|
||||
const currentAuditInfo = this.formatAuditInfo(currentAudit);
|
||||
@@ -344,7 +528,10 @@ export default class AccessHistoryModal extends React.Component {
|
||||
className='theme'
|
||||
onClick={this.handleMoreInfo.bind(this, i)}
|
||||
>
|
||||
{'More info'}
|
||||
<FormattedMessage
|
||||
id='access_history.moreInfo'
|
||||
defaultMessage='More info'
|
||||
/>
|
||||
</a>
|
||||
);
|
||||
|
||||
@@ -354,17 +541,33 @@ export default class AccessHistoryModal extends React.Component {
|
||||
|
||||
if (currentAudit.action.search('/users/login') >= 0) {
|
||||
if (currentAudit.extra_info === 'attempt') {
|
||||
currentAudit.session_id += ' (Login attempt)';
|
||||
currentAudit.session_id += formatMessage(holders.loginAttempt);
|
||||
} else {
|
||||
currentAudit.session_id += ' (Login failure)';
|
||||
currentAudit.session_id += formatMessage(holders.loginFailure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moreInfo = (
|
||||
<div>
|
||||
<div>{'IP: ' + currentAudit.ip_address}</div>
|
||||
<div>{'Session ID: ' + currentAudit.session_id}</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='access_history.ip'
|
||||
defaultMessage='IP: {ip}'
|
||||
values={{
|
||||
ip: currentAudit.ip_address
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='access_history.session'
|
||||
defaultMessage='Session ID: {id}'
|
||||
values={{
|
||||
id: currentAudit.session_id
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -404,7 +607,12 @@ export default class AccessHistoryModal extends React.Component {
|
||||
bsSize='large'
|
||||
>
|
||||
<Modal.Header closeButton={true}>
|
||||
<Modal.Title>{'Access History'}</Modal.Title>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id='access_history.title'
|
||||
defaultMessage='Access History'
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body ref='modalBody'>
|
||||
{content}
|
||||
@@ -415,6 +623,9 @@ export default class AccessHistoryModal extends React.Component {
|
||||
}
|
||||
|
||||
AccessHistoryModal.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
onHide: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(AccessHistoryModal);
|
||||
@@ -8,6 +8,8 @@ const Modal = ReactBootstrap.Modal;
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class ActivityLogModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -100,15 +102,33 @@ export default class ActivityLogModal extends React.Component {
|
||||
|
||||
if (currentSession.props.platform === 'Windows') {
|
||||
devicePicture = 'fa fa-windows';
|
||||
} else if (currentSession.device_id && currentSession.device_id.indexOf('apple:') === 0) {
|
||||
devicePicture = 'fa fa-apple';
|
||||
devicePlatform = (
|
||||
<FormattedMessage
|
||||
id='activity_log_modal.iphoneNativeApp'
|
||||
defaultMessage='iPhone Native App'
|
||||
/>
|
||||
);
|
||||
} else if (currentSession.device_id && currentSession.device_id.indexOf('android:') === 0) {
|
||||
devicePlatform = (
|
||||
<FormattedMessage
|
||||
id='activity_log_modal.androidNativeApp'
|
||||
defaultMessage='Android Native App'
|
||||
/>
|
||||
);
|
||||
devicePicture = 'fa fa-android';
|
||||
} else if (currentSession.props.platform === 'Macintosh' ||
|
||||
currentSession.props.platform === 'iPhone') {
|
||||
devicePicture = 'fa fa-apple';
|
||||
} else if (currentSession.props.platform.browser.indexOf('Mattermost/') === 0) {
|
||||
devicePicture = 'fa fa-apple';
|
||||
devicePlatform = 'iPhone';
|
||||
} else if (currentSession.props.platform === 'Linux') {
|
||||
if (currentSession.props.os.indexOf('Android') >= 0) {
|
||||
devicePlatform = 'Android';
|
||||
devicePlatform = (
|
||||
<FormattedMessage
|
||||
id='activity_log_modal.android'
|
||||
defaultMessage='Android'
|
||||
/>
|
||||
);
|
||||
devicePicture = 'fa fa-android';
|
||||
} else {
|
||||
devicePicture = 'fa fa-linux';
|
||||
@@ -119,10 +139,43 @@ export default class ActivityLogModal extends React.Component {
|
||||
if (this.state.moreInfo[i]) {
|
||||
moreInfo = (
|
||||
<div>
|
||||
<div>{`First time active: ${firstAccessTime.toDateString()}, ${lastAccessTime.toLocaleTimeString()}`}</div>
|
||||
<div>{`OS: ${currentSession.props.os}`}</div>
|
||||
<div>{`Browser: ${currentSession.props.browser}`}</div>
|
||||
<div>{`Session ID: ${currentSession.id}`}</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='activity_log.firstTime'
|
||||
defaultMessage='First time active: {date}, {time}'
|
||||
values={{
|
||||
date: firstAccessTime.toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'}),
|
||||
time: lastAccessTime.toLocaleTimeString(global.window.mm_locale, {hour: '2-digit', minute: '2-digit'})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='activity_log.os'
|
||||
defaultMessage='OS: {os}'
|
||||
values={{
|
||||
os: currentSession.props.os
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='activity_log.browser'
|
||||
defaultMessage='Browser: {browser}'
|
||||
values={{
|
||||
browser: currentSession.props.browser
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='activity_log.sessionId'
|
||||
defaultMessage='Session ID: {id}'
|
||||
values={{
|
||||
id: currentSession.id
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
@@ -132,7 +185,10 @@ export default class ActivityLogModal extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMoreInfo.bind(this, i)}
|
||||
>
|
||||
More info
|
||||
<FormattedMessage
|
||||
id='activity_log.moreInfo'
|
||||
defaultMessage='More info'
|
||||
/>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -145,7 +201,16 @@ export default class ActivityLogModal extends React.Component {
|
||||
<div className='activity-log__report'>
|
||||
<div className='report__platform'><i className={devicePicture} />{devicePlatform}</div>
|
||||
<div className='report__info'>
|
||||
<div>{`Last activity: ${lastAccessTime.toDateString()}, ${lastAccessTime.toLocaleTimeString()}`}</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='activity_log.lastActivity'
|
||||
defaultMessage='Last activity: {date}, {time}'
|
||||
values={{
|
||||
date: lastAccessTime.toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'}),
|
||||
time: lastAccessTime.toLocaleTimeString(global.window.mm_locale, {hour: '2-digit', minute: '2-digit'})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{moreInfo}
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,7 +219,10 @@ export default class ActivityLogModal extends React.Component {
|
||||
onClick={this.submitRevoke.bind(this, currentSession.id)}
|
||||
className='btn btn-primary'
|
||||
>
|
||||
Logout
|
||||
<FormattedMessage
|
||||
id='activity_log.logout'
|
||||
defaultMessage='Logout'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -175,10 +243,20 @@ export default class ActivityLogModal extends React.Component {
|
||||
bsSize='large'
|
||||
>
|
||||
<Modal.Header closeButton={true}>
|
||||
<Modal.Title>{'Active Sessions'}</Modal.Title>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id='activity_log.activeSessions'
|
||||
defaultMessage='Active Sessions'
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body ref='modalBody'>
|
||||
<p className='session-help-text'>{'Sessions are created when you log in with your email and password to a new browser on a device. Sessions let you use Mattermost for up to 30 days without having to log in again. If you want to log out sooner, use the \'Logout\' button below to end a session.'}</p>
|
||||
<p className='session-help-text'>
|
||||
<FormattedMessage
|
||||
id='activity_log.sessionsDescription'
|
||||
defaultMessage="Sessions are created when you log in with your email and password to a new browser on a device. Sessions let you use Mattermost for up to 30 days without having to log in again. If you want to log out sooner, use the 'Logout' button below to end a session."
|
||||
/>
|
||||
</p>
|
||||
{content}
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
|
||||
@@ -7,6 +7,8 @@ import TeamStore from '../../stores/team_store.jsx';
|
||||
|
||||
import Constants from '../../utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
function getStateFromStores() {
|
||||
return {currentTeam: TeamStore.getCurrent()};
|
||||
}
|
||||
@@ -66,7 +68,13 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
<a
|
||||
href={Utils.getWindowLocationOrigin() + '/' + this.state.currentTeam.name}
|
||||
>
|
||||
{'Switch to ' + this.state.currentTeam.display_name}
|
||||
<FormattedMessage
|
||||
id='admin.nav.switch'
|
||||
defaultMessage='Switch to {display_name}'
|
||||
values={{
|
||||
display_name: this.state.currentTeam.display_name
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -74,7 +82,10 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleLogoutClick}
|
||||
>
|
||||
{'Logout'}
|
||||
<FormattedMessage
|
||||
id='admin.nav.logout'
|
||||
defaultMessage='Logout'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li className='divider'></li>
|
||||
@@ -83,7 +94,10 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
target='_blank'
|
||||
href='/static/help/help.html'
|
||||
>
|
||||
{'Help'}
|
||||
<FormattedMessage
|
||||
id='admin.nav.help'
|
||||
defaultMessage='Help'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -91,7 +105,10 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
target='_blank'
|
||||
href='/static/help/report_problem.html'
|
||||
>
|
||||
{'Report a Problem'}
|
||||
<FormattedMessage
|
||||
id='admin.nav.report'
|
||||
defaultMessage='Report a Problem'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -5,6 +5,8 @@ import AdminSidebarHeader from './admin_sidebar_header.jsx';
|
||||
import SelectTeamModal from './select_team_modal.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
const Tooltip = ReactBootstrap.Tooltip;
|
||||
const OverlayTrigger = ReactBootstrap.OverlayTrigger;
|
||||
|
||||
@@ -82,12 +84,27 @@ export default class AdminSidebar extends React.Component {
|
||||
|
||||
render() {
|
||||
var count = '*';
|
||||
var teams = 'Loading';
|
||||
var teams = (
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.loading'
|
||||
defaultMessage='Loading'
|
||||
/>
|
||||
);
|
||||
const removeTooltip = (
|
||||
<Tooltip id='remove-team-tooltip'>{'Remove team from sidebar menu'}</Tooltip>
|
||||
<Tooltip id='remove-team-tooltip'>
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.rmTeamSidebar'
|
||||
defaultMessage='Remove team from sidebar menu'
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
const addTeamTooltip = (
|
||||
<Tooltip id='add-team-tooltip'>{'Add team from sidebar menu'}</Tooltip>
|
||||
<Tooltip id='add-team-tooltip'>
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.addTeamSidebar'
|
||||
defaultMessage='Add team from sidebar menu'
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
if (this.props.teams != null) {
|
||||
@@ -134,7 +151,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('team_users', team.id)}
|
||||
onClick={this.handleClick.bind(this, 'team_users', team.id)}
|
||||
>
|
||||
{'- Users'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.users'
|
||||
defaultMessage='- Users'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -143,7 +163,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('team_analytics', team.id)}
|
||||
onClick={this.handleClick.bind(this, 'team_analytics', team.id)}
|
||||
>
|
||||
{'- Statistics'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.statistics'
|
||||
defaultMessage='- Statistics'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -166,7 +189,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('ldap_settings')}
|
||||
onClick={this.handleClick.bind(this, 'ldap_settings', null)}
|
||||
>
|
||||
{'LDAP Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.ldap'
|
||||
defaultMessage='LDAP Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -179,7 +205,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('license')}
|
||||
onClick={this.handleClick.bind(this, 'license', null)}
|
||||
>
|
||||
{'Edition and License'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.license'
|
||||
defaultMessage='Edition and License'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -196,7 +225,12 @@ export default class AdminSidebar extends React.Component {
|
||||
<li>
|
||||
<h4>
|
||||
<span className='icon fa fa-gear'></span>
|
||||
<span>{'SITE REPORTS'}</span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.reports'
|
||||
defaultMessage='SITE REPORTS'
|
||||
/>
|
||||
</span>
|
||||
</h4>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -207,7 +241,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('system_analytics')}
|
||||
onClick={this.handleClick.bind(this, 'system_analytics', null)}
|
||||
>
|
||||
{'View Statistics'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.view_statistics'
|
||||
defaultMessage='View Statistics'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -215,7 +252,12 @@ export default class AdminSidebar extends React.Component {
|
||||
<li>
|
||||
<h4>
|
||||
<span className='icon fa fa-gear'></span>
|
||||
<span>{'SETTINGS'}</span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.settings'
|
||||
defaultMessage='SETTINGS'
|
||||
/>
|
||||
</span>
|
||||
</h4>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -226,7 +268,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('service_settings')}
|
||||
onClick={this.handleClick.bind(this, 'service_settings', null)}
|
||||
>
|
||||
{'Service Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.service'
|
||||
defaultMessage='Service Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -235,7 +280,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('team_settings')}
|
||||
onClick={this.handleClick.bind(this, 'team_settings', null)}
|
||||
>
|
||||
{'Team Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.team'
|
||||
defaultMessage='Team Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -244,7 +292,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('sql_settings')}
|
||||
onClick={this.handleClick.bind(this, 'sql_settings', null)}
|
||||
>
|
||||
{'SQL Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.sql'
|
||||
defaultMessage='SQL Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -253,7 +304,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('email_settings')}
|
||||
onClick={this.handleClick.bind(this, 'email_settings', null)}
|
||||
>
|
||||
{'Email Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.email'
|
||||
defaultMessage='Email Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -262,7 +316,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('image_settings')}
|
||||
onClick={this.handleClick.bind(this, 'image_settings', null)}
|
||||
>
|
||||
{'File Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.file'
|
||||
defaultMessage='File Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -271,7 +328,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('log_settings')}
|
||||
onClick={this.handleClick.bind(this, 'log_settings', null)}
|
||||
>
|
||||
{'Log Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.log'
|
||||
defaultMessage='Log Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -280,7 +340,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('rate_settings')}
|
||||
onClick={this.handleClick.bind(this, 'rate_settings', null)}
|
||||
>
|
||||
{'Rate Limit Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.rate_limit'
|
||||
defaultMessage='Rate Limit Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -289,7 +352,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('privacy_settings')}
|
||||
onClick={this.handleClick.bind(this, 'privacy_settings', null)}
|
||||
>
|
||||
{'Privacy Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.privacy'
|
||||
defaultMessage='Privacy Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@@ -298,7 +364,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('gitlab_settings')}
|
||||
onClick={this.handleClick.bind(this, 'gitlab_settings', null)}
|
||||
>
|
||||
{'GitLab Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.gitlab'
|
||||
defaultMessage='GitLab Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
{ldapSettings}
|
||||
@@ -308,7 +377,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('legal_and_support_settings')}
|
||||
onClick={this.handleClick.bind(this, 'legal_and_support_settings', null)}
|
||||
>
|
||||
{'Legal and Support Settings'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.support'
|
||||
defaultMessage='Legal and Support Settings'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -316,7 +388,15 @@ export default class AdminSidebar extends React.Component {
|
||||
<li>
|
||||
<h4>
|
||||
<span className='icon fa fa-gear'></span>
|
||||
<span>{'TEAMS (' + count + ')'}</span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.teams'
|
||||
defaultMessage='TEAMS ({count})'
|
||||
values={{
|
||||
count: count
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
<span className='menu-icon--right'>
|
||||
<OverlayTrigger
|
||||
delayShow={1000}
|
||||
@@ -345,7 +425,12 @@ export default class AdminSidebar extends React.Component {
|
||||
<li>
|
||||
<h4>
|
||||
<span className='icon fa fa-gear'></span>
|
||||
<span>{'OTHER'}</span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.other'
|
||||
defaultMessage='OTHER'
|
||||
/>
|
||||
</span>
|
||||
</h4>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -357,7 +442,10 @@ export default class AdminSidebar extends React.Component {
|
||||
className={this.isSelected('logs')}
|
||||
onClick={this.handleClick.bind(this, 'logs', null)}
|
||||
>
|
||||
{'Logs'}
|
||||
<FormattedMessage
|
||||
id='admin.sidebar.logs'
|
||||
defaultMessage='Logs'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -5,6 +5,8 @@ import AdminNavbarDropdown from './admin_navbar_dropdown.jsx';
|
||||
import UserStore from '../../stores/user_store.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class SidebarHeader extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -51,7 +53,12 @@ export default class SidebarHeader extends React.Component {
|
||||
{profilePicture}
|
||||
<div className='header__info'>
|
||||
<div className='user__name'>{'@' + me.username}</div>
|
||||
<div className='team__name'>{'System Console'}</div>
|
||||
<div className='team__name'>
|
||||
<FormattedMessage
|
||||
id='admin.sidebarHeader.systemConsole'
|
||||
defaultMessage='System Console'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<AdminNavbarDropdown ref='dropdown' />
|
||||
|
||||
@@ -8,6 +8,8 @@ import LineChart from './line_chart.jsx';
|
||||
var Tooltip = ReactBootstrap.Tooltip;
|
||||
var OverlayTrigger = ReactBootstrap.OverlayTrigger;
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class Analytics extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -21,11 +23,23 @@ export default class Analytics extends React.Component {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.props.serverError}</label></div>;
|
||||
}
|
||||
|
||||
let loading = (
|
||||
<FormattedMessage
|
||||
id='admin.analytics.loading'
|
||||
defaultMessage='Loading...'
|
||||
/>
|
||||
);
|
||||
|
||||
var totalCount = (
|
||||
<div className='col-sm-3'>
|
||||
<div className='total-count'>
|
||||
<div className='title'>{'Total Users'}<i className='fa fa-users'/></div>
|
||||
<div className='content'>{this.props.uniqueUserCount == null ? 'Loading...' : this.props.uniqueUserCount}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.totalUsers'
|
||||
defaultMessage='Total Users'
|
||||
/>
|
||||
<i className='fa fa-users'/></div>
|
||||
<div className='content'>{this.props.uniqueUserCount == null ? loading : this.props.uniqueUserCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -33,8 +47,13 @@ export default class Analytics extends React.Component {
|
||||
var openChannelCount = (
|
||||
<div className='col-sm-3'>
|
||||
<div className='total-count'>
|
||||
<div className='title'>{'Public Channels'}<i className='fa fa-globe'/></div>
|
||||
<div className='content'>{this.props.channelOpenCount == null ? 'Loading...' : this.props.channelOpenCount}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.publicChannels'
|
||||
defaultMessage='Public Channels'
|
||||
/>
|
||||
<i className='fa fa-globe'/></div>
|
||||
<div className='content'>{this.props.channelOpenCount == null ? loading : this.props.channelOpenCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -42,8 +61,13 @@ export default class Analytics extends React.Component {
|
||||
var openPrivateCount = (
|
||||
<div className='col-sm-3'>
|
||||
<div className='total-count'>
|
||||
<div className='title'>{'Private Groups'}<i className='fa fa-lock'/></div>
|
||||
<div className='content'>{this.props.channelPrivateCount == null ? 'Loading...' : this.props.channelPrivateCount}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.privateGroups'
|
||||
defaultMessage='Private Groups'
|
||||
/>
|
||||
<i className='fa fa-lock'/></div>
|
||||
<div className='content'>{this.props.channelPrivateCount == null ? loading : this.props.channelPrivateCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -51,8 +75,13 @@ export default class Analytics extends React.Component {
|
||||
var postCount = (
|
||||
<div className='col-sm-3'>
|
||||
<div className='total-count'>
|
||||
<div className='title'>{'Total Posts'}<i className='fa fa-comment'/></div>
|
||||
<div className='content'>{this.props.postCount == null ? 'Loading...' : this.props.postCount}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.totalPosts'
|
||||
defaultMessage='Total Posts'
|
||||
/>
|
||||
<i className='fa fa-comment'/></div>
|
||||
<div className='content'>{this.props.postCount == null ? loading : this.props.postCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -60,8 +89,13 @@ export default class Analytics extends React.Component {
|
||||
var postCountsByDay = (
|
||||
<div className='col-sm-12'>
|
||||
<div className='total-count by-day'>
|
||||
<div className='title'>{'Total Posts'}</div>
|
||||
<div className='content'>{'Loading...'}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.totalPosts'
|
||||
defaultMessage='Total Posts'
|
||||
/>
|
||||
</div>
|
||||
<div className='content'>{loading}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -69,7 +103,14 @@ export default class Analytics extends React.Component {
|
||||
if (this.props.postCountsDay != null) {
|
||||
let content;
|
||||
if (this.props.postCountsDay.labels.length === 0) {
|
||||
content = 'Not enough data for a meaningful representation.';
|
||||
content = (
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.meaningful'
|
||||
defaultMessage='Not enough data for a meaningful representation.'
|
||||
/>
|
||||
</h5>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<LineChart
|
||||
@@ -82,7 +123,12 @@ export default class Analytics extends React.Component {
|
||||
postCountsByDay = (
|
||||
<div className='col-sm-12'>
|
||||
<div className='total-count by-day'>
|
||||
<div className='title'>{'Total Posts'}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.totalPosts'
|
||||
defaultMessage='Total Posts'
|
||||
/>
|
||||
</div>
|
||||
<div className='content'>
|
||||
{content}
|
||||
</div>
|
||||
@@ -94,8 +140,13 @@ export default class Analytics extends React.Component {
|
||||
var usersWithPostsByDay = (
|
||||
<div className='col-sm-12'>
|
||||
<div className='total-count by-day'>
|
||||
<div className='title'>{'Active Users With Posts'}</div>
|
||||
<div className='content'>{'Loading...'}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.activeUsers'
|
||||
defaultMessage='Active Users With Posts'
|
||||
/>
|
||||
</div>
|
||||
<div className='content'>{loading}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -103,7 +154,14 @@ export default class Analytics extends React.Component {
|
||||
if (this.props.userCountsWithPostsDay != null) {
|
||||
let content;
|
||||
if (this.props.userCountsWithPostsDay.labels.length === 0) {
|
||||
content = 'Not enough data for a meaningful representation.';
|
||||
content = (
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.meaningful'
|
||||
defaultMessage='Not enough data for a meaningful representation.'
|
||||
/>
|
||||
</h5>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<LineChart
|
||||
@@ -116,7 +174,12 @@ export default class Analytics extends React.Component {
|
||||
usersWithPostsByDay = (
|
||||
<div className='col-sm-12'>
|
||||
<div className='total-count by-day'>
|
||||
<div className='title'>{'Active Users With Posts'}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.activeUsers'
|
||||
defaultMessage='Active Users With Posts'
|
||||
/>
|
||||
</div>
|
||||
<div className='content'>
|
||||
{content}
|
||||
</div>
|
||||
@@ -129,7 +192,7 @@ export default class Analytics extends React.Component {
|
||||
if (this.props.recentActiveUsers != null) {
|
||||
let content;
|
||||
if (this.props.recentActiveUsers.length === 0) {
|
||||
content = 'Loading...';
|
||||
content = loading;
|
||||
} else {
|
||||
content = (
|
||||
<table>
|
||||
@@ -167,7 +230,12 @@ export default class Analytics extends React.Component {
|
||||
recentActiveUser = (
|
||||
<div className='col-sm-6'>
|
||||
<div className='total-count recent-active-users'>
|
||||
<div className='title'>{'Recent Active Users'}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.recentActive'
|
||||
defaultMessage='Recent Active Users'
|
||||
/>
|
||||
</div>
|
||||
<div className='content'>
|
||||
{content}
|
||||
</div>
|
||||
@@ -180,7 +248,7 @@ export default class Analytics extends React.Component {
|
||||
if (this.props.newlyCreatedUsers != null) {
|
||||
let content;
|
||||
if (this.props.newlyCreatedUsers.length === 0) {
|
||||
content = 'Loading...';
|
||||
content = loading;
|
||||
} else {
|
||||
content = (
|
||||
<table>
|
||||
@@ -218,7 +286,12 @@ export default class Analytics extends React.Component {
|
||||
newUsers = (
|
||||
<div className='col-sm-6'>
|
||||
<div className='total-count recent-active-users'>
|
||||
<div className='title'>{'Newly Created Users'}</div>
|
||||
<div className='title'>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.newlyCreated'
|
||||
defaultMessage='Newly Created Users'
|
||||
/>
|
||||
</div>
|
||||
<div className='content'>
|
||||
{content}
|
||||
</div>
|
||||
@@ -229,7 +302,15 @@ export default class Analytics extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed team_statistics'>
|
||||
<h3>{'Statistics for ' + this.props.title}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.analytics.title'
|
||||
defaultMessage='Statistics for {title}'
|
||||
values={{
|
||||
title: this.props.title
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
{serverError}
|
||||
<div className='row'>
|
||||
{totalCount}
|
||||
|
||||
@@ -5,7 +5,68 @@ import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
import crypto from 'crypto';
|
||||
|
||||
export default class EmailSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
notificationDisplayExample: {
|
||||
id: 'admin.email.notificationDisplayExample',
|
||||
defaultMessage: 'Ex: "Mattermost Notification", "System", "No-Reply"'
|
||||
},
|
||||
notificationEmailExample: {
|
||||
id: 'admin.email.notificationEmailExample',
|
||||
defaultMessage: 'Ex: "mattermost@yourcompany.com", "admin@yourcompany.com"'
|
||||
},
|
||||
smtpUsernameExample: {
|
||||
id: 'admin.email.smtpUsernameExample',
|
||||
defaultMessage: 'Ex: "admin@yourcompany.com", "AKIADTOVBGERKLCBV"'
|
||||
},
|
||||
smtpPasswordExample: {
|
||||
id: 'admin.email.smtpPasswordExample',
|
||||
defaultMessage: 'Ex: "yourpassword", "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
},
|
||||
smtpServerExample: {
|
||||
id: 'admin.email.smtpServerExample',
|
||||
defaultMessage: 'Ex: "smtp.yourcompany.com", "email-smtp.us-east-1.amazonaws.com"'
|
||||
},
|
||||
smtpPortExample: {
|
||||
id: 'admin.email.smtpPortExample',
|
||||
defaultMessage: 'Ex: "25", "465"'
|
||||
},
|
||||
connectionSecurityNone: {
|
||||
id: 'admin.email.connectionSecurityNone',
|
||||
defaultMessage: 'None'
|
||||
},
|
||||
connectionSecurityTls: {
|
||||
id: 'admin.email.connectionSecurityTls',
|
||||
defaultMessage: 'TLS (Recommended)'
|
||||
},
|
||||
connectionSecurityStart: {
|
||||
id: 'admin.email.connectionSecurityStart',
|
||||
defaultMessage: 'STARTTLS'
|
||||
},
|
||||
inviteSaltExample: {
|
||||
id: 'admin.email.inviteSaltExample',
|
||||
defaultMessage: 'Ex "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo"'
|
||||
},
|
||||
passwordSaltExample: {
|
||||
id: 'admin.email.passwordSaltExample',
|
||||
defaultMessage: 'Ex "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo"'
|
||||
},
|
||||
pushServerEx: {
|
||||
id: 'admin.email.pushServerEx',
|
||||
defaultMessage: 'E.g.: "https://push-test.mattermost.com"'
|
||||
},
|
||||
testing: {
|
||||
id: 'admin.email.testing',
|
||||
defaultMessage: 'Testing...'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.email.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class EmailSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -156,6 +217,7 @@ export default class EmailSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -170,7 +232,11 @@ export default class EmailSettings extends React.Component {
|
||||
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.'}
|
||||
<i className='fa fa-check'></i>
|
||||
<FormattedMessage
|
||||
id='admin.email.emailSuccess'
|
||||
defaultMessage='No errors were reported while sending an email. Please check your inbox to make sure.'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -179,14 +245,26 @@ export default class EmailSettings extends React.Component {
|
||||
if (this.state.emailFail) {
|
||||
emailSuccess = (
|
||||
<div className='alert alert-warning'>
|
||||
<i className='fa fa-warning'></i>{'Connection unsuccessful: ' + this.state.emailFail}
|
||||
<i className='fa fa-warning'></i>
|
||||
<FormattedMessage
|
||||
id='admin.email.emailFail'
|
||||
defaultMessage='Connection unsuccessful: {error}'
|
||||
values={{
|
||||
error: this.state.emailFail
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'Email Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.email.emailSettings'
|
||||
defaultMessage='Email Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -197,7 +275,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='allowSignUpWithEmail'
|
||||
>
|
||||
{'Allow Sign Up With Email: '}
|
||||
<FormattedMessage
|
||||
id='admin.email.allowSignupTitle'
|
||||
defaultMessage='Allow Sign Up With Email: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -209,7 +290,10 @@ export default class EmailSettings extends React.Component {
|
||||
defaultChecked={this.props.config.EmailSettings.EnableSignUpWithEmail}
|
||||
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_true')}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.email.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -219,9 +303,17 @@ export default class EmailSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.EmailSettings.EnableSignUpWithEmail}
|
||||
onChange={this.handleChange.bind(this, 'allowSignUpWithEmail_false')}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.email.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, Mattermost allows team creation and account signup using email and password. This value should be false only when you want to limit signup to a single-sign-on service like OAuth or LDAP.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.allowSignupDescription'
|
||||
defaultMessage='When true, Mattermost allows team creation and account signup using email and password. This value should be false only when you want to limit signup to a single-sign-on service like OAuth or LDAP.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -230,7 +322,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='sendEmailNotifications'
|
||||
>
|
||||
{'Send Email Notifications: '}
|
||||
<FormattedMessage
|
||||
id='admin.email.notificationsTitle'
|
||||
defaultMessage='Send Email Notifications: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -242,7 +337,10 @@ export default class EmailSettings extends React.Component {
|
||||
defaultChecked={this.props.config.EmailSettings.SendEmailNotifications}
|
||||
onChange={this.handleChange.bind(this, 'sendEmailNotifications_true')}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.email.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -252,9 +350,17 @@ export default class EmailSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.EmailSettings.SendEmailNotifications}
|
||||
onChange={this.handleChange.bind(this, 'sendEmailNotifications_false')}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.email.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.\nSetting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedHTMLMessage
|
||||
id='admin.email.notificationsDescription'
|
||||
defaultMessage='Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.<br />Setting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -263,7 +369,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='requireEmailVerification'
|
||||
>
|
||||
{'Require Email Verification: '}
|
||||
<FormattedMessage
|
||||
id='admin.email.requireVerificationTitle'
|
||||
defaultMessage='Require Email Verification: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -276,7 +385,10 @@ export default class EmailSettings extends React.Component {
|
||||
onChange={this.handleChange.bind(this, 'requireEmailVerification_true')}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.email.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -287,9 +399,17 @@ export default class EmailSettings extends React.Component {
|
||||
onChange={this.handleChange.bind(this, 'requireEmailVerification_false')}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.email.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'Typically set to true in production. When true, Mattermost requires email verification after account creation prior to allowing login. Developers may set this field to false so skip sending verification emails for faster development.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.requireVerificationDescription'
|
||||
defaultMessage='Typically set to true in production. When true, Mattermost requires email verification after account creation prior to allowing login. Developers may set this field to false so skip sending verification emails for faster development.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -298,7 +418,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackName'
|
||||
>
|
||||
{'Notification Display Name:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.notificationDisplayTitle'
|
||||
defaultMessage='Notification Display Name:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -306,12 +429,17 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='feedbackName'
|
||||
ref='feedbackName'
|
||||
placeholder='E.g.: "Mattermost Notification", "System", "No-Reply"'
|
||||
placeholder={formatMessage(holders.notificationDisplayExample)}
|
||||
defaultValue={this.props.config.EmailSettings.FeedbackName}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
<p className='help-text'>{'Display name on email account used when sending notification emails from Mattermost.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.notificationDisplayDescription'
|
||||
defaultMessage='Display name on email account used when sending notification emails from Mattermost.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -320,7 +448,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackEmail'
|
||||
>
|
||||
{'Notification Email Address:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.notificationEmailTitle'
|
||||
defaultMessage='Notification Email Address:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -328,12 +459,17 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='feedbackEmail'
|
||||
ref='feedbackEmail'
|
||||
placeholder='E.g.: "mattermost@yourcompany.com", "admin@yourcompany.com"'
|
||||
placeholder={formatMessage(holders.notificationEmailExample)}
|
||||
defaultValue={this.props.config.EmailSettings.FeedbackEmail}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
<p className='help-text'>{'Email address displayed on email account used when sending notification emails from Mattermost.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.notificationEmailDescription'
|
||||
defaultMessage='Email address displayed on email account used when sending notification emails from Mattermost.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -342,7 +478,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SMTPUsername'
|
||||
>
|
||||
{'SMTP Username:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpUsernameTitle'
|
||||
defaultMessage='SMTP Username:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -350,12 +489,17 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SMTPUsername'
|
||||
ref='SMTPUsername'
|
||||
placeholder='E.g.: "admin@yourcompany.com", "AKIADTOVBGERKLCBV"'
|
||||
placeholder={formatMessage(holders.smtpUsernameExample)}
|
||||
defaultValue={this.props.config.EmailSettings.SMTPUsername}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
<p className='help-text'>{' Obtain this credential from administrator setting up your email server.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpUsernameDescription'
|
||||
defaultMessage=' Obtain this credential from administrator setting up your email server.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -364,7 +508,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SMTPPassword'
|
||||
>
|
||||
{'SMTP Password:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpPasswordTitle'
|
||||
defaultMessage='SMTP Password:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -372,12 +519,17 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SMTPPassword'
|
||||
ref='SMTPPassword'
|
||||
placeholder='E.g.: "yourpassword", "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
placeholder={formatMessage(holders.smtpPasswordExample)}
|
||||
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>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpPasswordDescription'
|
||||
defaultMessage=' Obtain this credential from administrator setting up your email server.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -386,7 +538,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SMTPServer'
|
||||
>
|
||||
{'SMTP Server:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpServerTitle'
|
||||
defaultMessage='SMTP Server:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -394,12 +549,17 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SMTPServer'
|
||||
ref='SMTPServer'
|
||||
placeholder='E.g.: "smtp.yourcompany.com", "email-smtp.us-east-1.amazonaws.com"'
|
||||
placeholder={formatMessage(holders.smtpServerExample)}
|
||||
defaultValue={this.props.config.EmailSettings.SMTPServer}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
<p className='help-text'>{'Location of SMTP email server.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpServerDescription'
|
||||
defaultMessage='Location of SMTP email server.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -408,7 +568,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SMTPPort'
|
||||
>
|
||||
{'SMTP Port:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpPortTitle'
|
||||
defaultMessage='SMTP Port:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -416,12 +579,17 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SMTPPort'
|
||||
ref='SMTPPort'
|
||||
placeholder='E.g.: "25", "465"'
|
||||
placeholder={formatMessage(holders.smtpPortExample)}
|
||||
defaultValue={this.props.config.EmailSettings.SMTPPort}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
<p className='help-text'>{'Port of SMTP email server.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.smtpPortDescription'
|
||||
defaultMessage='Port of SMTP email server.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -430,7 +598,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ConnectionSecurity'
|
||||
>
|
||||
{'Connection Security:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.connectionSecurityTitle'
|
||||
defaultMessage='Connection Security:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<select
|
||||
@@ -441,9 +612,9 @@ export default class EmailSettings extends React.Component {
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
>
|
||||
<option value=''>{'None'}</option>
|
||||
<option value='TLS'>{'TLS (Recommended)'}</option>
|
||||
<option value='STARTTLS'>{'STARTTLS'}</option>
|
||||
<option value=''>{formatMessage(holders.connectionSecurityNone)}</option>
|
||||
<option value='TLS'>{formatMessage(holders.connectionSecurityTls)}</option>
|
||||
<option value='STARTTLS'>{formatMessage(holders.connectionSecurityStart)}</option>
|
||||
</select>
|
||||
<div className='help-text'>
|
||||
<table
|
||||
@@ -451,9 +622,29 @@ export default class EmailSettings extends React.Component {
|
||||
cellPadding='5'
|
||||
>
|
||||
<tbody>
|
||||
<tr><td className='help-text'>{'None'}</td><td className='help-text'>{'Mattermost will send email over an unsecure connection.'}</td></tr>
|
||||
<tr><td className='help-text'>{'TLS'}</td><td className='help-text'>{'Encrypts the communication between Mattermost and your email server.'}</td></tr>
|
||||
<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>
|
||||
<tr><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.connectionSecurityNone'
|
||||
defaultMessage='None'
|
||||
/>
|
||||
</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.connectionSecurityNoneDescription'
|
||||
defaultMessage='Mattermost will send email over an unsecure connection.'
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td className='help-text'>{'TLS'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.connectionSecurityTlsDescription'
|
||||
defaultMessage='Encrypts the communication between Mattermost and your email server.'
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td className='help-text'>{'STARTTLS'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.connectionSecurityStartDescription'
|
||||
defaultMessage='Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.'
|
||||
/>
|
||||
</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -463,9 +654,12 @@ export default class EmailSettings extends React.Component {
|
||||
onClick={this.handleTestConnection}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
id='connection-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Testing...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.testing)}
|
||||
>
|
||||
{'Test Connection'}
|
||||
<FormattedMessage
|
||||
id='admin.email.connectionSecurityTest'
|
||||
defaultMessage='Test Connection'
|
||||
/>
|
||||
</button>
|
||||
{emailSuccess}
|
||||
{emailFail}
|
||||
@@ -478,7 +672,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='InviteSalt'
|
||||
>
|
||||
{'Invite Salt:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.inviteSaltTitle'
|
||||
defaultMessage='Invite Salt:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -486,19 +683,27 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='InviteSalt'
|
||||
ref='InviteSalt'
|
||||
placeholder='E.g.: "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo"'
|
||||
placeholder={formatMessage(holders.inviteSaltExample)}
|
||||
defaultValue={this.props.config.EmailSettings.InviteSalt}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
<p className='help-text'>{'32-character salt added to signing of email invites. Randomly generated on install. Click "Re-Generate" to create new salt.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.inviteSaltDescription'
|
||||
defaultMessage='32-character salt added to signing of email invites. Randomly generated on install. Click "Re-Generate" to create new salt.'
|
||||
/>
|
||||
</p>
|
||||
<div className='help-text'>
|
||||
<button
|
||||
className='btn btn-default'
|
||||
onClick={this.handleGenerateInvite}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
>
|
||||
{'Re-Generate'}
|
||||
<FormattedMessage
|
||||
id='admin.email.regenerate'
|
||||
defaultMessage='Re-Generate'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -509,7 +714,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='PasswordResetSalt'
|
||||
>
|
||||
{'Password Reset Salt:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.passwordSaltTitle'
|
||||
defaultMessage='Password Reset Salt:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -517,19 +725,27 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='PasswordResetSalt'
|
||||
ref='PasswordResetSalt'
|
||||
placeholder='E.g.: "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo"'
|
||||
placeholder={formatMessage(holders.passwordSaltExample)}
|
||||
defaultValue={this.props.config.EmailSettings.PasswordResetSalt}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
/>
|
||||
<p className='help-text'>{'32-character salt added to signing of password reset emails. Randomly generated on install. Click "Re-Generate" to create new salt.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.passwordSaltDescription'
|
||||
defaultMessage='32-character salt added to signing of password reset emails. Randomly generated on install. Click "Re-Generate" to create new salt.'
|
||||
/>
|
||||
</p>
|
||||
<div className='help-text'>
|
||||
<button
|
||||
className='btn btn-default'
|
||||
onClick={this.handleGenerateReset}
|
||||
disabled={!this.state.sendEmailNotifications}
|
||||
>
|
||||
{'Re-Generate'}
|
||||
<FormattedMessage
|
||||
id='admin.email.regenerate'
|
||||
defaultMessage='Re-Generate'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -540,7 +756,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='sendPushNotifications'
|
||||
>
|
||||
{'Send Push Notifications: '}
|
||||
<FormattedMessage
|
||||
id='admin.email.pushTitle'
|
||||
defaultMessage='Send Push Notifications: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -552,7 +771,10 @@ export default class EmailSettings extends React.Component {
|
||||
defaultChecked={this.props.config.EmailSettings.SendPushNotifications}
|
||||
onChange={this.handleChange.bind(this, 'sendPushNotifications_true')}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.email.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -562,9 +784,17 @@ export default class EmailSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.EmailSettings.SendPushNotifications}
|
||||
onChange={this.handleChange.bind(this, 'sendPushNotifications_false')}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.email.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'Typically set to true in production. When true, Mattermost attempts to send iOS and Android push notifications through the push notification server.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.pushDesc'
|
||||
defaultMessage='Typically set to true in production. When true, Mattermost attempts to send iOS and Android push notifications through the push notification server.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -573,7 +803,10 @@ export default class EmailSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='PushNotificationServer'
|
||||
>
|
||||
{'Push Notification Server:'}
|
||||
<FormattedMessage
|
||||
id='admin.email.pushServerTitle'
|
||||
defaultMessage='Push Notification Server:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -581,12 +814,17 @@ export default class EmailSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='PushNotificationServer'
|
||||
ref='PushNotificationServer'
|
||||
placeholder='E.g.: "https://push-test.mattermost.com"'
|
||||
placeholder={formatMessage(holders.pushServerEx)}
|
||||
defaultValue={this.props.config.EmailSettings.PushNotificationServer}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.sendPushNotifications}
|
||||
/>
|
||||
<p className='help-text'>{'Location of Mattermost push notification service you can set up behind your firewall using https://github.com/mattermost/push-proxy. For testing you can use https://push-test.mattermost.com, which connects to the sample Mattermost iOS app in the public Apple AppStore. Please do not use test service for production deployments.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.email.pushServerDesc'
|
||||
defaultMessage='Location of Mattermost push notification service you can set up behind your firewall using https://github.com/mattermost/push-proxy. For testing you can use https://push-test.mattermost.com, which connects to the sample Mattermost iOS app in the public Apple AppStore. Please do not use test service for production deployments.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -599,9 +837,12 @@ export default class EmailSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.email.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -613,5 +854,8 @@ export default class EmailSettings extends React.Component {
|
||||
}
|
||||
|
||||
EmailSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(EmailSettings);
|
||||
@@ -4,7 +4,36 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
export default class GitLabSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
clientIdExample: {
|
||||
id: 'admin.gitlab.clientIdExample',
|
||||
defaultMessage: 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
},
|
||||
clientSecretExample: {
|
||||
id: 'admin.gitlab.clientSecretExample',
|
||||
defaultMessage: 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
},
|
||||
authExample: {
|
||||
id: 'admin.gitlab.authExample',
|
||||
defaultMessage: 'Ex ""'
|
||||
},
|
||||
tokenExample: {
|
||||
id: 'admin.gitlab.tokenExample',
|
||||
defaultMessage: 'Ex ""'
|
||||
},
|
||||
userExample: {
|
||||
id: 'admin.gitlab.userExample',
|
||||
defaultMessage: 'Ex ""'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.gitlab.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class GitLabSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -65,6 +94,7 @@ export default class GitLabSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -78,7 +108,12 @@ export default class GitLabSettings extends React.Component {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
|
||||
<h3>{'GitLab Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.settingsTitle'
|
||||
defaultMessage='GitLab Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -89,7 +124,10 @@ export default class GitLabSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='Enable'
|
||||
>
|
||||
{'Enable Sign Up With GitLab: '}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.enableTitle'
|
||||
defaultMessage='Enable Sign Up With GitLab: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -101,7 +139,10 @@ export default class GitLabSettings extends React.Component {
|
||||
defaultChecked={this.props.config.GitLabSettings.Enable}
|
||||
onChange={this.handleChange.bind(this, 'EnableTrue')}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -111,18 +152,23 @@ export default class GitLabSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.GitLabSettings.Enable}
|
||||
onChange={this.handleChange.bind(this, 'EnableFalse')}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>
|
||||
{'When true, Mattermost allows team creation and account signup using GitLab OAuth.'} <br/>
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.enableDescription'
|
||||
defaultMessage='When true, Mattermost allows team creation and account signup using GitLab OAuth.'
|
||||
/>
|
||||
<br/>
|
||||
</p>
|
||||
<div className='help-text'>
|
||||
<ol>
|
||||
<li>{'Log in to your GitLab account and go to Applications -> Profile Settings.'}</li>
|
||||
<li>{'Enter Redirect URIs "<your-mattermost-url>/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "<your-mattermost-url>/signup/gitlab/complete". '}</li>
|
||||
<li>{'Then use "Secret" and "Id" fields from GitLab to complete the options below.'}</li>
|
||||
<li>{'Complete the Endpoint URLs below. '}</li>
|
||||
</ol>
|
||||
<FormattedHTMLMessage
|
||||
id='admin.gitlab.EnableHtmlDesc'
|
||||
defaultMessage='<ol><li>Log in to your GitLab account and go to Applications -> Profile Settings.</li><li>Enter Redirect URIs "<your-mattermost-url>/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "<your-mattermost-url>/signup/gitlab/complete". </li><li>Then use "Secret" and "Id" fields from GitLab to complete the options below.</li><li>Complete the Endpoint URLs below. </li></ol>'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,7 +178,10 @@ export default class GitLabSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='Id'
|
||||
>
|
||||
{'Id:'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.clientIdTitle'
|
||||
defaultMessage='Id:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -140,12 +189,17 @@ export default class GitLabSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='Id'
|
||||
ref='Id'
|
||||
placeholder='Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
placeholder={formatMessage(holders.clientIdExample)}
|
||||
defaultValue={this.props.config.GitLabSettings.Id}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.Enable}
|
||||
/>
|
||||
<p className='help-text'>{'Obtain this value via the instructions above for logging into GitLab'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.clientIdDescription'
|
||||
defaultMessage='Obtain this value via the instructions above for logging into GitLab'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -154,7 +208,10 @@ export default class GitLabSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='Secret'
|
||||
>
|
||||
{'Secret:'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.clientSecretTitle'
|
||||
defaultMessage='Secret:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -162,12 +219,17 @@ export default class GitLabSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='Secret'
|
||||
ref='Secret'
|
||||
placeholder='Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
placeholder={formatMessage(holders.clientSecretExample)}
|
||||
defaultValue={this.props.config.GitLabSettings.Secret}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.Enable}
|
||||
/>
|
||||
<p className='help-text'>{'Obtain this value via the instructions above for logging into GitLab.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.gitab.clientSecretDescription'
|
||||
defaultMessage='Obtain this value via the instructions above for logging into GitLab.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -176,7 +238,10 @@ export default class GitLabSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AuthEndpoint'
|
||||
>
|
||||
{'Auth Endpoint:'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.authTitle'
|
||||
defaultMessage='Auth Endpoint:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -184,12 +249,17 @@ export default class GitLabSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='AuthEndpoint'
|
||||
ref='AuthEndpoint'
|
||||
placeholder='Ex ""'
|
||||
placeholder={formatMessage(holders.authExample)}
|
||||
defaultValue={this.props.config.GitLabSettings.AuthEndpoint}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.Enable}
|
||||
/>
|
||||
<p className='help-text'>{'Enter https://<your-gitlab-url>/oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.authDescription'
|
||||
defaultMessage='Enter https://<your-gitlab-url>/oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -198,7 +268,10 @@ export default class GitLabSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='TokenEndpoint'
|
||||
>
|
||||
{'Token Endpoint:'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.tokenTitle'
|
||||
defaultMessage='Token Endpoint:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -206,12 +279,17 @@ export default class GitLabSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='TokenEndpoint'
|
||||
ref='TokenEndpoint'
|
||||
placeholder='Ex ""'
|
||||
placeholder={formatMessage(holders.tokenExample)}
|
||||
defaultValue={this.props.config.GitLabSettings.TokenEndpoint}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.Enable}
|
||||
/>
|
||||
<p className='help-text'>{'Enter https://<your-gitlab-url>/oauth/token. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.tokenDescription'
|
||||
defaultMessage='Enter https://<your-gitlab-url>/oauth/token. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -220,7 +298,10 @@ export default class GitLabSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='UserApiEndpoint'
|
||||
>
|
||||
{'User API Endpoint:'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.userTitle'
|
||||
defaultMessage='User API Endpoint:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -228,12 +309,17 @@ export default class GitLabSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='UserApiEndpoint'
|
||||
ref='UserApiEndpoint'
|
||||
placeholder='Ex ""'
|
||||
placeholder={formatMessage(holders.userExample)}
|
||||
defaultValue={this.props.config.GitLabSettings.UserApiEndpoint}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.Enable}
|
||||
/>
|
||||
<p className='help-text'>{'Enter https://<your-gitlab-url>/api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.userDescription'
|
||||
defaultMessage='Enter https://<your-gitlab-url>/api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -246,9 +332,12 @@ export default class GitLabSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.gitlab.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -283,5 +372,8 @@ export default class GitLabSettings extends React.Component {
|
||||
// </div>
|
||||
|
||||
GitLabSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(GitLabSettings);
|
||||
@@ -5,7 +5,76 @@ import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
import crypto from 'crypto';
|
||||
|
||||
export default class FileSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
storeDisabled: {
|
||||
id: 'admin.image.storeDisabled',
|
||||
defaultMessage: 'Disable File Storage'
|
||||
},
|
||||
storeLocal: {
|
||||
id: 'admin.image.storeLocal',
|
||||
defaultMessage: 'Local File System'
|
||||
},
|
||||
storeAmazonS3: {
|
||||
id: 'admin.image.storeAmazonS3',
|
||||
defaultMessage: 'Amazon S3'
|
||||
},
|
||||
localExample: {
|
||||
id: 'admin.image.localExample',
|
||||
defaultMessage: 'Ex "./data/"'
|
||||
},
|
||||
amazonS3IdExample: {
|
||||
id: 'admin.image.amazonS3IdExample',
|
||||
defaultMessage: 'Ex "AKIADTOVBGERKLCBV"'
|
||||
},
|
||||
amazonS3SecretExample: {
|
||||
id: 'admin.image.amazonS3SecretExample',
|
||||
defaultMessage: 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
},
|
||||
amazonS3BucketExample: {
|
||||
id: 'admin.image.amazonS3BucketExample',
|
||||
defaultMessage: 'Ex "mattermost-media"'
|
||||
},
|
||||
amazonS3RegionExample: {
|
||||
id: 'admin.image.amazonS3RegionExample',
|
||||
defaultMessage: 'Ex "us-east-1"'
|
||||
},
|
||||
thumbWidthExample: {
|
||||
id: 'admin.image.thumbWidthExample',
|
||||
defaultMessage: 'Ex "120"'
|
||||
},
|
||||
thumbHeightExample: {
|
||||
id: 'admin.image.thumbHeightExample',
|
||||
defaultMessage: 'Ex "100"'
|
||||
},
|
||||
previewWidthExample: {
|
||||
id: 'admin.image.previewWidthExample',
|
||||
defaultMessage: 'Ex "1024"'
|
||||
},
|
||||
previewHeightExample: {
|
||||
id: 'admin.image.previewHeightExample',
|
||||
defaultMessage: 'Ex "0"'
|
||||
},
|
||||
profileWidthExample: {
|
||||
id: 'admin.image.profileWidthExample',
|
||||
defaultMessage: 'Ex "1024"'
|
||||
},
|
||||
profileHeightExample: {
|
||||
id: 'admin.image.profileHeightExample',
|
||||
defaultMessage: 'Ex "0"'
|
||||
},
|
||||
publicLinkExample: {
|
||||
id: 'admin.image.publicLinkExample',
|
||||
defaultMessage: 'Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.image.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class FileSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -120,6 +189,7 @@ export default class FileSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -143,7 +213,12 @@ export default class FileSettings extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'File Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.image.fileSettings'
|
||||
defaultMessage='File Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -154,7 +229,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='DriverName'
|
||||
>
|
||||
{'Store Files In:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.storeTitle'
|
||||
defaultMessage='Store Files In:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<select
|
||||
@@ -164,9 +242,9 @@ export default class FileSettings extends React.Component {
|
||||
defaultValue={this.props.config.FileSettings.DriverName}
|
||||
onChange={this.handleChange.bind(this, 'DriverName')}
|
||||
>
|
||||
<option value=''>{'Disable File Storage'}</option>
|
||||
<option value='local'>{'Local File System'}</option>
|
||||
<option value='amazons3'>{'Amazon S3'}</option>
|
||||
<option value=''>{formatMessage(holders.storeDisabled)}</option>
|
||||
<option value='local'>{formatMessage(holders.storeLocal)}</option>
|
||||
<option value='amazons3'>{formatMessage(holders.storeAmazonS3)}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -176,7 +254,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='Directory'
|
||||
>
|
||||
{'Local Directory Location:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.localTitle'
|
||||
defaultMessage='Local Directory Location:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -184,12 +265,17 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='Directory'
|
||||
ref='Directory'
|
||||
placeholder='Ex "./data/"'
|
||||
placeholder={formatMessage(holders.localExample)}
|
||||
defaultValue={this.props.config.FileSettings.Directory}
|
||||
onChange={this.handleChange}
|
||||
disabled={!enableFile}
|
||||
/>
|
||||
<p className='help-text'>{'Directory to which image files are written. If blank, will be set to ./data/.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.localDescription'
|
||||
defaultMessage='Directory to which image files are written. If blank, will be set to ./data/.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -198,7 +284,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AmazonS3AccessKeyId'
|
||||
>
|
||||
{'Amazon S3 Access Key Id:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3IdTitle'
|
||||
defaultMessage='Amazon S3 Access Key Id:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -206,12 +295,17 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='AmazonS3AccessKeyId'
|
||||
ref='AmazonS3AccessKeyId'
|
||||
placeholder='Ex "AKIADTOVBGERKLCBV"'
|
||||
placeholder={formatMessage(holders.amazonS3IdExample)}
|
||||
defaultValue={this.props.config.FileSettings.AmazonS3AccessKeyId}
|
||||
onChange={this.handleChange}
|
||||
disabled={!enableS3}
|
||||
/>
|
||||
<p className='help-text'>{'Obtain this credential from your Amazon EC2 administrator.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3IdDescription'
|
||||
defaultMessage='Obtain this credential from your Amazon EC2 administrator.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -220,7 +314,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AmazonS3SecretAccessKey'
|
||||
>
|
||||
{'Amazon S3 Secret Access Key:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3SecretTitle'
|
||||
defaultMessage='Amazon S3 Secret Access Key:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -228,12 +325,17 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='AmazonS3SecretAccessKey'
|
||||
ref='AmazonS3SecretAccessKey'
|
||||
placeholder='Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"'
|
||||
placeholder={formatMessage(holders.amazonS3SecretExample)}
|
||||
defaultValue={this.props.config.FileSettings.AmazonS3SecretAccessKey}
|
||||
onChange={this.handleChange}
|
||||
disabled={!enableS3}
|
||||
/>
|
||||
<p className='help-text'>{'Obtain this credential from your Amazon EC2 administrator.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3SecretDescription'
|
||||
defaultMessage='Obtain this credential from your Amazon EC2 administrator.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -242,7 +344,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AmazonS3Bucket'
|
||||
>
|
||||
{'Amazon S3 Bucket:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3BucketTitle'
|
||||
defaultMessage='Amazon S3 Bucket:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -250,12 +355,17 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='AmazonS3Bucket'
|
||||
ref='AmazonS3Bucket'
|
||||
placeholder='Ex "mattermost-media"'
|
||||
placeholder={formatMessage(holders.amazonS3BucketExample)}
|
||||
defaultValue={this.props.config.FileSettings.AmazonS3Bucket}
|
||||
onChange={this.handleChange}
|
||||
disabled={!enableS3}
|
||||
/>
|
||||
<p className='help-text'>{'Name you selected for your S3 bucket in AWS.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3BucketDescription'
|
||||
defaultMessage='Name you selected for your S3 bucket in AWS.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -264,7 +374,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AmazonS3Region'
|
||||
>
|
||||
{'Amazon S3 Region:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3RegionTitle'
|
||||
defaultMessage='Amazon S3 Region:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -272,12 +385,17 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='AmazonS3Region'
|
||||
ref='AmazonS3Region'
|
||||
placeholder='Ex "us-east-1"'
|
||||
placeholder={formatMessage(holders.amazonS3RegionExample)}
|
||||
defaultValue={this.props.config.FileSettings.AmazonS3Region}
|
||||
onChange={this.handleChange}
|
||||
disabled={!enableS3}
|
||||
/>
|
||||
<p className='help-text'>{'AWS region you selected for creating your S3 bucket.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.amazonS3RegionDescription'
|
||||
defaultMessage='AWS region you selected for creating your S3 bucket.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -286,7 +404,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ThumbnailWidth'
|
||||
>
|
||||
{'Thumbnail Width:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.thumbWidthTitle'
|
||||
defaultMessage='Thumbnail Width:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -294,11 +415,16 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='ThumbnailWidth'
|
||||
ref='ThumbnailWidth'
|
||||
placeholder='Ex "120"'
|
||||
placeholder={formatMessage(holders.thumbWidthExample)}
|
||||
defaultValue={this.props.config.FileSettings.ThumbnailWidth}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Width of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.thumbWidthDescription'
|
||||
defaultMessage='Width of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -307,7 +433,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ThumbnailHeight'
|
||||
>
|
||||
{'Thumbnail Height:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.thumbHeightTitle'
|
||||
defaultMessage='Thumbnail Height:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -315,11 +444,16 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='ThumbnailHeight'
|
||||
ref='ThumbnailHeight'
|
||||
placeholder='Ex "100"'
|
||||
placeholder={formatMessage(holders.thumbHeightExample)}
|
||||
defaultValue={this.props.config.FileSettings.ThumbnailHeight}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Height of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.thumbHeightDescription'
|
||||
defaultMessage='Height of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -328,7 +462,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='PreviewWidth'
|
||||
>
|
||||
{'Preview Width:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.previewWidthTitle'
|
||||
defaultMessage='Preview Width:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -336,11 +473,16 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='PreviewWidth'
|
||||
ref='PreviewWidth'
|
||||
placeholder='Ex "1024"'
|
||||
placeholder={formatMessage(holders.previewWidthExample)}
|
||||
defaultValue={this.props.config.FileSettings.PreviewWidth}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Maximum width of preview image. Updating this value changes how preview images render in future, but does not change images created in the past.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.previewWidthDescription'
|
||||
defaultMessage='Maximum width of preview image. Updating this value changes how preview images render in future, but does not change images created in the past.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -349,7 +491,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='PreviewHeight'
|
||||
>
|
||||
{'Preview Height:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.previewHeightTitle'
|
||||
defaultMessage='Preview Height:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -357,11 +502,16 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='PreviewHeight'
|
||||
ref='PreviewHeight'
|
||||
placeholder='Ex "0"'
|
||||
placeholder={formatMessage(holders.previewHeightExample)}
|
||||
defaultValue={this.props.config.FileSettings.PreviewHeight}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Maximum height of preview image ("0": Sets to auto-size). Updating this value changes how preview images render in future, but does not change images created in the past.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.previewHeightDescription'
|
||||
defaultMessage='Maximum height of preview image ("0": Sets to auto-size). Updating this value changes how preview images render in future, but does not change images created in the past.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -370,7 +520,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ProfileWidth'
|
||||
>
|
||||
{'Profile Width:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.profileWidthTitle'
|
||||
defaultMessage='Profile Width:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -378,11 +531,16 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='ProfileWidth'
|
||||
ref='ProfileWidth'
|
||||
placeholder='Ex "1024"'
|
||||
placeholder={formatMessage(holders.profileWidthExample)}
|
||||
defaultValue={this.props.config.FileSettings.ProfileWidth}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Width of profile picture.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.profileWidthDescription'
|
||||
defaultMessage='Width of profile picture.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -391,7 +549,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ProfileHeight'
|
||||
>
|
||||
{'Profile Height:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.profileHeightTitle'
|
||||
defaultMessage='Profile Height:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -399,11 +560,16 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='ProfileHeight'
|
||||
ref='ProfileHeight'
|
||||
placeholder='Ex "0"'
|
||||
placeholder={formatMessage(holders.profileHeightExample)}
|
||||
defaultValue={this.props.config.FileSettings.ProfileHeight}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Height of profile picture.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.profileHeightDescription'
|
||||
defaultMessage='Height of profile picture.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -412,7 +578,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnablePublicLink'
|
||||
>
|
||||
{'Share Public File Link: '}
|
||||
<FormattedMessage
|
||||
id='admin.image.shareTitle'
|
||||
defaultMessage='Share Public File Link: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -424,7 +593,10 @@ export default class FileSettings extends React.Component {
|
||||
defaultChecked={this.props.config.FileSettings.EnablePublicLink}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.image.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -434,9 +606,17 @@ export default class FileSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.FileSettings.EnablePublicLink}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.image.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'Allow users to share public links to files and images.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.shareDescription'
|
||||
defaultMessage='Allow users to share public links to files and images.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -445,7 +625,10 @@ export default class FileSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='PublicLinkSalt'
|
||||
>
|
||||
{'Public Link Salt:'}
|
||||
<FormattedMessage
|
||||
id='admin.image.publicLinkTitle'
|
||||
defaultMessage='Public Link Salt:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -453,17 +636,25 @@ export default class FileSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='PublicLinkSalt'
|
||||
ref='PublicLinkSalt'
|
||||
placeholder='Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"'
|
||||
placeholder={formatMessage(holders.publicLinkExample)}
|
||||
defaultValue={this.props.config.FileSettings.PublicLinkSalt}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'32-character salt added to signing of public image links. Randomly generated on install. Click "Re-Generate" to create new salt.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.image.publicLinkDescription'
|
||||
defaultMessage='32-character salt added to signing of public image links. Randomly generated on install. Click "Re-Generate" to create new salt.'
|
||||
/>
|
||||
</p>
|
||||
<div className='help-text'>
|
||||
<button
|
||||
className='btn btn-default'
|
||||
onClick={this.handleGenerate}
|
||||
>
|
||||
{'Re-Generate'}
|
||||
<FormattedMessage
|
||||
id='admin.image.regenerate'
|
||||
defaultMessage='Re-Generate'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -478,9 +669,12 @@ export default class FileSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.image.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -492,5 +686,8 @@ export default class FileSettings extends React.Component {
|
||||
}
|
||||
|
||||
FileSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(FileSettings);
|
||||
@@ -4,10 +4,55 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
const DEFAULT_LDAP_PORT = 389;
|
||||
const DEFAULT_QUERY_TIMEOUT = 60;
|
||||
|
||||
export default class LdapSettings extends React.Component {
|
||||
var holders = defineMessages({
|
||||
serverEx: {
|
||||
id: 'admin.ldap.serverEx',
|
||||
defaultMessage: 'Ex "10.0.0.23"'
|
||||
},
|
||||
portEx: {
|
||||
id: 'admin.ldap.portEx',
|
||||
defaultMessage: 'Ex "389"'
|
||||
},
|
||||
baseEx: {
|
||||
id: 'admin.ldap.baseEx',
|
||||
defaultMessage: 'Ex "dc=mydomain,dc=com"'
|
||||
},
|
||||
firstnameAttrEx: {
|
||||
id: 'admin.ldap.firstnameAttrEx',
|
||||
defaultMessage: 'Ex "givenName"'
|
||||
},
|
||||
lastnameAttrEx: {
|
||||
id: 'admin.ldap.lastnameAttrEx',
|
||||
defaultMessage: 'Ex "sn"'
|
||||
},
|
||||
emailAttrEx: {
|
||||
id: 'admin.ldap.emailAttrEx',
|
||||
defaultMessage: 'Ex "mail"'
|
||||
},
|
||||
usernameAttrEx: {
|
||||
id: 'admin.ldap.usernameAttrEx',
|
||||
defaultMessage: 'Ex "sAMAccountName"'
|
||||
},
|
||||
idAttrEx: {
|
||||
id: 'admin.ldap.idAttrEx',
|
||||
defaultMessage: 'Ex "sAMAccountName"'
|
||||
},
|
||||
queryEx: {
|
||||
id: 'admin.ldap.queryEx',
|
||||
defaultMessage: 'Ex "60"'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.ldap.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class LdapSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -80,6 +125,7 @@ export default class LdapSettings extends React.Component {
|
||||
);
|
||||
}
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
let serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -97,8 +143,18 @@ export default class LdapSettings extends React.Component {
|
||||
bannerContent = (
|
||||
<div className='banner'>
|
||||
<div className='banner__content'>
|
||||
<h4 className='banner__heading'>{'Note:'}</h4>
|
||||
<p>{'If a user attribute changes on the LDAP server it will be updated the next time the user enters their credentials to log in to Mattermost. This includes if a user is made inactive or removed from an LDAP server. Synchronization with LDAP servers is planned in a future release.'}</p>
|
||||
<h4 className='banner__heading'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.bannerHeading'
|
||||
defaultMessage='Note:'
|
||||
/>
|
||||
</h4>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.bannerDesc'
|
||||
defaultMessage='If a user attribute changes on the LDAP server it will be updated the next time the user enters their credentials to log in to Mattermost. This includes if a user is made inactive or removed from an LDAP server. Synchronization with LDAP servers is planned in a future release.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -106,17 +162,10 @@ export default class LdapSettings extends React.Component {
|
||||
bannerContent = (
|
||||
<div className='banner warning'>
|
||||
<div className='banner__content'>
|
||||
<h4 className='banner__heading'>{'Note:'}</h4>
|
||||
<p>
|
||||
{'LDAP is an enterprise feature. Your current license does not support LDAP. Click '}
|
||||
<a
|
||||
href='http://mattermost.com'
|
||||
target='_blank'
|
||||
>
|
||||
{'here'}
|
||||
</a>
|
||||
{' for information and pricing on enterprise licenses.'}
|
||||
</p>
|
||||
<FormattedHTMLMessage
|
||||
id='admin.ldap.noLicense'
|
||||
defaultMessage='<h4 className="banner__heading">Note:</h4><p>LDAP is an enterprise feature. Your current license does not support LDAP. Click <a href="http://mattermost.com"target="_blank">here</a> for information and pricing on enterprise licenses.</p>'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -125,7 +174,12 @@ export default class LdapSettings extends React.Component {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
{bannerContent}
|
||||
<h3>{'LDAP Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.title'
|
||||
defaultMessage='LDAP Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -135,7 +189,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='Enable'
|
||||
>
|
||||
{'Enable Login With LDAP:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.enableTitle'
|
||||
defaultMessage='Enable Login With LDAP:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -148,7 +205,10 @@ export default class LdapSettings extends React.Component {
|
||||
onChange={this.handleEnable}
|
||||
disabled={!licenseEnabled}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -158,9 +218,17 @@ export default class LdapSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.LdapSettings.Enable}
|
||||
onChange={this.handleDisable}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, Mattermost allows login using LDAP'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.enableDesc'
|
||||
defaultMessage='When true, Mattermost allows login using LDAP'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -168,7 +236,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='LdapServer'
|
||||
>
|
||||
{'LDAP Server:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.serverTitle'
|
||||
defaultMessage='LDAP Server:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -176,12 +247,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='LdapServer'
|
||||
ref='LdapServer'
|
||||
placeholder='Ex "10.0.0.23"'
|
||||
placeholder={formatMessage(holders.serverEx)}
|
||||
defaultValue={this.props.config.LdapSettings.LdapServer}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The domain or IP address of LDAP server.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.serverDesc'
|
||||
defaultMessage='The domain or IP address of LDAP server.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -189,7 +265,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='LdapPort'
|
||||
>
|
||||
{'LDAP Port:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.portTitle'
|
||||
defaultMessage='LDAP Port:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -197,12 +276,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='LdapPort'
|
||||
ref='LdapPort'
|
||||
placeholder='Ex "389"'
|
||||
placeholder={formatMessage(holders.portEx)}
|
||||
defaultValue={this.props.config.LdapSettings.LdapPort}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The port Mattermost will use to connect to the LDAP server. Default is 389.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.portDesc'
|
||||
defaultMessage='The port Mattermost will use to connect to the LDAP server. Default is 389.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -210,7 +294,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='BaseDN'
|
||||
>
|
||||
{'BaseDN:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.baseTitle'
|
||||
defaultMessage='BaseDN:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -218,12 +305,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='BaseDN'
|
||||
ref='BaseDN'
|
||||
placeholder='Ex "dc=mydomain,dc=com"'
|
||||
placeholder={formatMessage(holders.baseEx)}
|
||||
defaultValue={this.props.config.LdapSettings.BaseDN}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The Base DN is the Distinguished Name of the location where Mattermost should start its search for users in the LDAP tree.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.baseDesc'
|
||||
defaultMessage='The Base DN is the Distinguished Name of the location where Mattermost should start its search for users in the LDAP tree.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -231,7 +323,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='BindUsername'
|
||||
>
|
||||
{'Bind Username:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.bindUserTitle'
|
||||
defaultMessage='Bind Username:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -244,7 +339,12 @@ export default class LdapSettings extends React.Component {
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The username used to perform the LDAP search. This should typically be an account created specifically for use with Mattermost. It should have access limited to read the portion of the LDAP tree specified in the BaseDN field.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.bindUserDesc'
|
||||
defaultMessage='The username used to perform the LDAP search. This should typically be an account created specifically for use with Mattermost. It should have access limited to read the portion of the LDAP tree specified in the BaseDN field.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -252,7 +352,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='BindPassword'
|
||||
>
|
||||
{'Bind Password:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.bindPwdTitle'
|
||||
defaultMessage='Bind Password:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -265,7 +368,12 @@ export default class LdapSettings extends React.Component {
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'Password of the user given in "Bind Username".'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.bindPwdDesc'
|
||||
defaultMessage='Password of the user given in "Bind Username".'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -273,7 +381,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='FirstNameAttribute'
|
||||
>
|
||||
{'First Name Attrubute'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.firstnameAttrTitle'
|
||||
defaultMessage='First Name Attrubute'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -281,12 +392,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='FirstNameAttribute'
|
||||
ref='FirstNameAttribute'
|
||||
placeholder='Ex "givenName"'
|
||||
placeholder={formatMessage(holders.firstnameAttrEx)}
|
||||
defaultValue={this.props.config.LdapSettings.FirstNameAttribute}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The attribute in the LDAP server that will be used to populate the first name of users in Mattermost.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.firstnameAttrDesc'
|
||||
defaultMessage='The attribute in the LDAP server that will be used to populate the first name of users in Mattermost.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -294,7 +410,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='LastNameAttribute'
|
||||
>
|
||||
{'Last Name Attribute:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.lastnameAttrTitle'
|
||||
defaultMessage='Last Name Attribute:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -302,12 +421,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='LastNameAttribute'
|
||||
ref='LastNameAttribute'
|
||||
placeholder='Ex "sn"'
|
||||
placeholder={formatMessage(holders.lastnameAttrEx)}
|
||||
defaultValue={this.props.config.LdapSettings.LastNameAttribute}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The attribute in the LDAP server that will be used to populate the last name of users in Mattermost.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.lastnameAttrDesc'
|
||||
defaultMessage='The attribute in the LDAP server that will be used to populate the last name of users in Mattermost.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -315,7 +439,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EmailAttribute'
|
||||
>
|
||||
{'Email Attribute:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.emailAttrTitle'
|
||||
defaultMessage='Email Attribute:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -323,12 +450,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='EmailAttribute'
|
||||
ref='EmailAttribute'
|
||||
placeholder='Ex "mail"'
|
||||
placeholder={formatMessage(holders.emailAttrEx)}
|
||||
defaultValue={this.props.config.LdapSettings.EmailAttribute}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The attribute in the LDAP server that will be used to populate the email addresses of users in Mattermost.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.emailAttrDesc'
|
||||
defaultMessage='The attribute in the LDAP server that will be used to populate the email addresses of users in Mattermost.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -336,7 +468,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='UsernameAttribute'
|
||||
>
|
||||
{'Username Attribute:'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.usernameAttrTitle'
|
||||
defaultMessage='Username Attribute:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -344,12 +479,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='UsernameAttribute'
|
||||
ref='UsernameAttribute'
|
||||
placeholder='Ex "sAMAccountName"'
|
||||
placeholder={formatMessage(holders.usernameAttrEx)}
|
||||
defaultValue={this.props.config.LdapSettings.UsernameAttribute}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The attribute in the LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.uernameAttrDesc'
|
||||
defaultMessage='The attribute in the LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -357,7 +497,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='IdAttribute'
|
||||
>
|
||||
{'Id Attribute: '}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.idAttrTitle'
|
||||
defaultMessage='Id Attribute: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -365,12 +508,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='IdAttribute'
|
||||
ref='IdAttribute'
|
||||
placeholder='Ex "sAMAccountName"'
|
||||
placeholder={formatMessage(holders.idAttrEx)}
|
||||
defaultValue={this.props.config.LdapSettings.IdAttribute}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The attribute in the LDAP server that will be used as a unique identifier in Mattermost. It should be an LDAP attribute with a value that does not change, such as username or uid. If a user’s Id Attribute changes, it will create a new Mattermost account unassociated with their old one. This is the value used to log in to Mattermost in the "LDAP Username" field on the sign in page. Normally this attribute is the same as the “Username Attribute” field above. If your team typically uses domain\\username to sign in to other services with LDAP, you may choose to put domain\\username in this field to maintain consistency between sites.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.idAttrDesc'
|
||||
defaultMessage='The attribute in the LDAP server that will be used as a unique identifier in Mattermost. It should be an LDAP attribute with a value that does not change, such as username or uid. If a user’s Id Attribute changes, it will create a new Mattermost account unassociated with their old one. This is the value used to log in to Mattermost in the "LDAP Username" field on the sign in page. Normally this attribute is the same as the “Username Attribute” field above. If your team typically uses domain\\username to sign in to other services with LDAP, you may choose to put domain\\username in this field to maintain consistency between sites.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -378,7 +526,10 @@ export default class LdapSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='QueryTimeout'
|
||||
>
|
||||
{'Query Timeout (seconds):'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.queryTitle'
|
||||
defaultMessage='Query Timeout (seconds):'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -386,12 +537,17 @@ export default class LdapSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='QueryTimeout'
|
||||
ref='QueryTimeout'
|
||||
placeholder='Ex "60"'
|
||||
placeholder={formatMessage(holders.queryEx)}
|
||||
defaultValue={this.props.config.LdapSettings.QueryTimeout}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enable}
|
||||
/>
|
||||
<p className='help-text'>{'The timeout value for queries to the LDAP server. Increase if you are getting timeout errors caused by a slow LDAP server.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.ldap.queryDesc'
|
||||
defaultMessage='The timeout value for queries to the LDAP server. Increase if you are getting timeout errors caused by a slow LDAP server.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
@@ -403,9 +559,12 @@ export default class LdapSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.ldap.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -418,5 +577,8 @@ LdapSettings.defaultProps = {
|
||||
};
|
||||
|
||||
LdapSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(LdapSettings);
|
||||
@@ -4,7 +4,16 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
export default class LegalAndSupportSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
saving: {
|
||||
id: 'admin.support.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class LegalAndSupportSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -69,7 +78,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
|
||||
<h3>{'Legal and Support Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.support.title'
|
||||
defaultMessage='Legal and Support Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -80,7 +94,10 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='TermsOfServiceLink'
|
||||
>
|
||||
{'Terms of Service link:'}
|
||||
<FormattedMessage
|
||||
id='admin.support.termsTitle'
|
||||
defaultMessage='Terms of Service link:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -91,7 +108,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
defaultValue={this.props.config.SupportSettings.TermsOfServiceLink}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Link to Terms of Service available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.support.termsDesc'
|
||||
defaultMessage='Link to Terms of Service available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -100,7 +122,10 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='PrivacyPolicyLink'
|
||||
>
|
||||
{'Privacy Policy link:'}
|
||||
<FormattedMessage
|
||||
id='admin.support.privacyTitle'
|
||||
defaultMessage='Privacy Policy link:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -111,7 +136,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
defaultValue={this.props.config.SupportSettings.PrivacyPolicyLink}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Link to Privacy Policy available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.support.privacyDesc'
|
||||
defaultMessage='Link to Privacy Policy available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -120,7 +150,10 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AboutLink'
|
||||
>
|
||||
{'About link:'}
|
||||
<FormattedMessage
|
||||
id='admin.support.aboutTitle'
|
||||
defaultMessage='About link:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -131,7 +164,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
defaultValue={this.props.config.SupportSettings.AboutLink}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Link to About page for more information on your Mattermost deployment, for example its purpose and audience within your organization. Defaults to Mattermost information page.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.support.aboutDesc'
|
||||
defaultMessage='Link to About page for more information on your Mattermost deployment, for example its purpose and audience within your organization. Defaults to Mattermost information page.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -140,7 +178,10 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='HelpLink'
|
||||
>
|
||||
{'Help link:'}
|
||||
<FormattedMessage
|
||||
id='admin.support.helpTitle'
|
||||
defaultMessage='Help link:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -151,7 +192,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
defaultValue={this.props.config.SupportSettings.HelpLink}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Link to help documentation from team site main menu. Typically not changed unless your organization chooses to create custom documentation.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.support.helpDesc'
|
||||
defaultMessage='Link to help documentation from team site main menu. Typically not changed unless your organization chooses to create custom documentation.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -160,7 +206,10 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ReportAProblemLink'
|
||||
>
|
||||
{'Report a Problem link:'}
|
||||
<FormattedMessage
|
||||
id='admin.support.problemTitle'
|
||||
defaultMessage='Report a Problem link:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -171,7 +220,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
defaultValue={this.props.config.SupportSettings.ReportAProblemLink}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Link to help documentation from team site main menu. By default this points to the peer-to-peer troubleshooting forum where users can search for, find and request help with technical issues.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.support.problemDesc'
|
||||
defaultMessage='Link to help documentation from team site main menu. By default this points to the peer-to-peer troubleshooting forum where users can search for, find and request help with technical issues.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -180,7 +234,10 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SupportEmail'
|
||||
>
|
||||
{'Support email:'}
|
||||
<FormattedMessage
|
||||
id='admin.support.emailTitle'
|
||||
defaultMessage='Support email:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -191,7 +248,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
defaultValue={this.props.config.SupportSettings.SupportEmail}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Email shown during tutorial for end users to ask support questions.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.support.emailHelp'
|
||||
defaultMessage='Email shown during tutorial for end users to ask support questions.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -204,9 +266,12 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + this.props.intl.formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.support.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -218,5 +283,8 @@ export default class LegalAndSupportSettings extends React.Component {
|
||||
}
|
||||
|
||||
LegalAndSupportSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(LegalAndSupportSettings);
|
||||
@@ -4,7 +4,20 @@
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
|
||||
export default class LicenseSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
removing: {
|
||||
id: 'admin.license.removing',
|
||||
defaultMessage: 'Removing License...'
|
||||
},
|
||||
uploading: {
|
||||
id: 'admin.license.uploading',
|
||||
defaultMessage: 'Uploading License...'
|
||||
}
|
||||
});
|
||||
|
||||
class LicenseSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -88,41 +101,26 @@ export default class LicenseSettings extends React.Component {
|
||||
let licenseKey;
|
||||
|
||||
if (global.window.mm_license.IsLicensed === 'true') {
|
||||
edition = 'Mattermost Enterprise Edition. Designed for enterprise-scale communication.';
|
||||
edition = (
|
||||
<FormattedMessage
|
||||
id='admin.license.enterpriseEdition'
|
||||
defaultMessage='Mattermost Enterprise Edition. Designed for enterprise-scale communication.'
|
||||
/>
|
||||
);
|
||||
licenseType = (
|
||||
<div>
|
||||
<p>
|
||||
{'This compiled release of Mattermost platform is provided under a '}
|
||||
<a
|
||||
href='http://mattermost.com'
|
||||
target='_blank'
|
||||
>
|
||||
{'commercial license'}
|
||||
</a>
|
||||
{' from Mattermost, Inc. based on your subscription level and is subject to the '}
|
||||
<a
|
||||
href={global.window.mm_config.TermsOfServiceLink}
|
||||
target='_blank'
|
||||
>
|
||||
{'Terms of Service.'}
|
||||
</a>
|
||||
</p>
|
||||
<p>{'Your subscription details are as follows:'}</p>
|
||||
{'Name: ' + global.window.mm_license.Name}
|
||||
<br/>
|
||||
{'Company or organization name: ' + global.window.mm_license.Company}
|
||||
<br/>
|
||||
{'Number of users: ' + global.window.mm_license.Users}
|
||||
<br/>
|
||||
{`License issued: ${Utils.displayDate(parseInt(global.window.mm_license.IssuedAt, 10))} ${Utils.displayTime(parseInt(global.window.mm_license.IssuedAt, 10), true)}`}
|
||||
<br/>
|
||||
{'Start date of license: ' + Utils.displayDate(parseInt(global.window.mm_license.StartsAt, 10))}
|
||||
<br/>
|
||||
{'Expiry date of license: ' + Utils.displayDate(parseInt(global.window.mm_license.ExpiresAt, 10))}
|
||||
<br/>
|
||||
{'LDAP: ' + global.window.mm_license.LDAP}
|
||||
<br/>
|
||||
</div>
|
||||
<FormattedHTMLMessage
|
||||
id='admin.license.entrepriseType'
|
||||
defaultMessage='<div><p>This compiled release of Mattermost platform is provided under a <a href="http://mattermost.com" target="_blank">commercial license</a>
|
||||
from Mattermost, Inc. based on your subscription level and is subject to the <a href="{terms}" target="_blank">Terms of Service.</a></p>
|
||||
<p>Your subscription details are as follows:</p>
|
||||
Name: {name}<br />
|
||||
Company or organization name: {company}<br/>
|
||||
Number of users: {users}<br/>
|
||||
License issued: {issued}<br/>
|
||||
Start date of license: {start}<br/>
|
||||
Expiry date of license: {expires}<br/>
|
||||
LDAP: {ldap}<br/></div>'
|
||||
/>
|
||||
);
|
||||
|
||||
licenseKey = (
|
||||
@@ -131,32 +129,39 @@ export default class LicenseSettings extends React.Component {
|
||||
className='btn btn-danger'
|
||||
onClick={this.handleRemove}
|
||||
id='remove-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Removing License...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + this.props.intl.formatMessage(holders.removing)}
|
||||
>
|
||||
{'Remove Enterprise License and Downgrade Server'}
|
||||
<FormattedMessage
|
||||
id='admin.license.keyRemove'
|
||||
defaultMessage='Remove Enterprise License and Downgrade Server'
|
||||
/>
|
||||
</button>
|
||||
<br/>
|
||||
<br/>
|
||||
<p className='help-text'>
|
||||
{'If you’re migrating servers you may need to remove your license key from this server in order to install it on a new server. To start, '}
|
||||
<a
|
||||
href='http://mattermost.com'
|
||||
target='_blank'
|
||||
>
|
||||
{'disable all Enterprise Edition features on this server'}
|
||||
</a>
|
||||
{'. This will enable the ability to remove the license key and downgrade this server from Enterprise Edition to Team Edition.'}
|
||||
<FormattedHTMLMessage
|
||||
id='admin.licence.keyMigration'
|
||||
defaultMessage='If you’re migrating servers you may need to remove your license key from this server in order to install it on a new server. To start,
|
||||
<a href="http://mattermost.com" target="_blank">disable all Enterprise Edition features on this server</a>.
|
||||
This will enable the ability to remove the license key and downgrade this server from Enterprise Edition to Team Edition.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
edition = 'Mattermost Team Edition. Designed for teams from 5 to 50 users.';
|
||||
edition = (
|
||||
<FormattedMessage
|
||||
id='admin.license.teamEdition'
|
||||
defaultMessage='Mattermost Team Edition. Designed for teams from 5 to 50 users.'
|
||||
/>
|
||||
);
|
||||
|
||||
licenseType = (
|
||||
<span>
|
||||
<p>{'This compiled release of Mattermost platform is offered under an MIT license.'}</p>
|
||||
<p>{'See MIT-COMPILED-LICENSE.txt in your root install directory for details. See NOTICES.txt for information about open source software used in this system.'}</p>
|
||||
</span>
|
||||
<FormattedHTMLMessage
|
||||
id='admin.license.teamType'
|
||||
defaultMessage='<span><p>This compiled release of Mattermost platform is offered under an MIT license.</p>
|
||||
<p>See MIT-COMPILED-LICENSE.txt in your root install directory for details. See NOTICES.txt for information about open source software used in this system.</p></span>'
|
||||
/>
|
||||
);
|
||||
|
||||
licenseKey = (
|
||||
@@ -173,23 +178,23 @@ export default class LicenseSettings extends React.Component {
|
||||
disabled={!this.state.fileSelected}
|
||||
onClick={this.handleSubmit}
|
||||
id='upload-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Uploading License...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + this.props.intl.formatMessage(holders.uploading)}
|
||||
>
|
||||
{'Upload'}
|
||||
<FormattedMessage
|
||||
id='admin.license.upload'
|
||||
defaultMessage='Upload'
|
||||
/>
|
||||
</button>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
{serverError}
|
||||
<p className='help-text'>
|
||||
{'Upload a license key for Mattermost Enterprise Edition to upgrade this server. '}
|
||||
<a
|
||||
href='http://mattermost.com'
|
||||
target='_blank'
|
||||
>
|
||||
{'Visit us online'}
|
||||
</a>
|
||||
{' to learn more about the benefits of Enterprise Edition or to purchase a key.'}
|
||||
<FormattedHTMLMessage
|
||||
id='admin.license.uploadDesc'
|
||||
defaultMessage='Upload a license key for Mattermost Enterprise Edition to upgrade this server. <a href="http://mattermost.com" target="_blank">Visit us online</a>
|
||||
to learn more about the benefits of Enterprise Edition or to purchase a key.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -197,7 +202,12 @@ export default class LicenseSettings extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'Edition and License'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.license.title'
|
||||
defaultMessage='Edition and License'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -206,7 +216,10 @@ export default class LicenseSettings extends React.Component {
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
>
|
||||
{'Edition: '}
|
||||
<FormattedMessage
|
||||
id='admin.license.edition'
|
||||
defaultMessage='Edition: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
{edition}
|
||||
@@ -216,7 +229,10 @@ export default class LicenseSettings extends React.Component {
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
>
|
||||
{'License: '}
|
||||
<FormattedMessage
|
||||
id='admin.license.type'
|
||||
defaultMessage='License: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
{licenseType}
|
||||
@@ -226,7 +242,10 @@ export default class LicenseSettings extends React.Component {
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
>
|
||||
{'License Key: '}
|
||||
<FormattedMessage
|
||||
id='admin.license.key'
|
||||
defaultMessage='License Key: '
|
||||
/>
|
||||
</label>
|
||||
{licenseKey}
|
||||
</div>
|
||||
@@ -235,3 +254,9 @@ export default class LicenseSettings extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LicenseSettings.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(LicenseSettings);
|
||||
@@ -4,7 +4,24 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
export default class LogSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
locationPlaceholder: {
|
||||
id: 'admin.log.locationPlaceholder',
|
||||
defaultMessage: 'Enter your file location'
|
||||
},
|
||||
formatPlaceholder: {
|
||||
id: 'admin.log.formatPlaceholder',
|
||||
defaultMessage: 'Enter your file format'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.log.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class LogSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -78,6 +95,7 @@ export default class LogSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -90,7 +108,12 @@ export default class LogSettings extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'Log Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.log.logSettings'
|
||||
defaultMessage='Log Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -101,7 +124,10 @@ export default class LogSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='consoleEnable'
|
||||
>
|
||||
{'Log To The Console: '}
|
||||
<FormattedMessage
|
||||
id='admin.log.consoleTitle'
|
||||
defaultMessage='Log To The Console: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -113,7 +139,10 @@ export default class LogSettings extends React.Component {
|
||||
defaultChecked={this.props.config.LogSettings.EnableConsole}
|
||||
onChange={this.handleChange.bind(this, 'console_true')}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.log.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -123,9 +152,17 @@ export default class LogSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.LogSettings.EnableConsole}
|
||||
onChange={this.handleChange.bind(this, 'console_false')}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.log.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'Typically set to false in production. Developers may set this field to true to output log messages to console based on the console level option. If true, server writes messages to the standard output stream (stdout).'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.consoleDescription'
|
||||
defaultMessage='Typically set to false in production. Developers may set this field to true to output log messages to console based on the console level option. If true, server writes messages to the standard output stream (stdout).'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -134,7 +171,10 @@ export default class LogSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='consoleLevel'
|
||||
>
|
||||
{'Console Log Level:'}
|
||||
<FormattedMessage
|
||||
id='admin.log.levelTitle'
|
||||
defaultMessage='Console Log Level:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<select
|
||||
@@ -149,7 +189,12 @@ export default class LogSettings extends React.Component {
|
||||
<option value='INFO'>{'INFO'}</option>
|
||||
<option value='ERROR'>{'ERROR'}</option>
|
||||
</select>
|
||||
<p className='help-text'>{'This setting determines the level of detail at which log events are written to the console. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.levelDescription'
|
||||
defaultMessage='This setting determines the level of detail at which log events are written to the console. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -157,7 +202,10 @@ export default class LogSettings extends React.Component {
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
>
|
||||
{'Log To File: '}
|
||||
<FormattedMessage
|
||||
id='admin.log.fileTitle'
|
||||
defaultMessage='Log To File: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -169,7 +217,10 @@ export default class LogSettings extends React.Component {
|
||||
defaultChecked={this.props.config.LogSettings.EnableFile}
|
||||
onChange={this.handleChange.bind(this, 'file_true')}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.log.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -179,9 +230,17 @@ export default class LogSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.LogSettings.EnableFile}
|
||||
onChange={this.handleChange.bind(this, 'file_false')}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.log.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'Typically set to true in production. When true, log files are written to the log file specified in file location field below.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.fileDescription'
|
||||
defaultMessage='Typically set to true in production. When true, log files are written to the log file specified in file location field below.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -190,7 +249,10 @@ export default class LogSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='fileLevel'
|
||||
>
|
||||
{'File Log Level:'}
|
||||
<FormattedMessage
|
||||
id='admin.log.fileLevelTitle'
|
||||
defaultMessage='File Log Level:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<select
|
||||
@@ -205,7 +267,12 @@ export default class LogSettings extends React.Component {
|
||||
<option value='INFO'>{'INFO'}</option>
|
||||
<option value='ERROR'>{'ERROR'}</option>
|
||||
</select>
|
||||
<p className='help-text'>{'This setting determines the level of detail at which log events are written to the log file. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.fileLevelDescription'
|
||||
defaultMessage='This setting determines the level of detail at which log events are written to the log file. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -214,7 +281,10 @@ export default class LogSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='fileLocation'
|
||||
>
|
||||
{'File Location:'}
|
||||
<FormattedMessage
|
||||
id='admin.log.locationTitle'
|
||||
defaultMessage='File Location:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -222,12 +292,17 @@ export default class LogSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='fileLocation'
|
||||
ref='fileLocation'
|
||||
placeholder='Enter your file location'
|
||||
placeholder={formatMessage(holders.locationPlaceholder)}
|
||||
defaultValue={this.props.config.LogSettings.FileLocation}
|
||||
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, which writes logs to mattermost.log. Log rotation is enabled and every 10,000 lines of log information is written to new files stored in the same directory, for example mattermost.2015-09-23.001, mattermost.2015-09-23.002, and so forth.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.locationDescription'
|
||||
defaultMessage='File to which log files are written. If blank, will be set to ./logs/mattermost, which writes logs to mattermost.log. Log rotation is enabled and every 10,000 lines of log information is written to new files stored in the same directory, for example mattermost.2015-09-23.001, mattermost.2015-09-23.002, and so forth.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -236,7 +311,10 @@ export default class LogSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='fileFormat'
|
||||
>
|
||||
{'File Format:'}
|
||||
<FormattedMessage
|
||||
id='admin.log.formatTitle'
|
||||
defaultMessage='File Format:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -244,25 +322,58 @@ export default class LogSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='fileFormat'
|
||||
ref='fileFormat'
|
||||
placeholder='Enter your file format'
|
||||
placeholder={formatMessage(holders.formatPlaceholder)}
|
||||
defaultValue={this.props.config.LogSettings.FileFormat}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.fileEnable}
|
||||
/>
|
||||
<div className='help-text'>
|
||||
{'Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'}
|
||||
<FormattedMessage
|
||||
id='admin.log.formatDescription'
|
||||
defaultMessage='Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'
|
||||
/>
|
||||
<div className='help-text'>
|
||||
<table
|
||||
className='table table-bordered'
|
||||
cellPadding='5'
|
||||
>
|
||||
<tbody>
|
||||
<tr><td className='help-text'>{'%T'}</td><td className='help-text'>{'Time (15:04:05 MST)'}</td></tr>
|
||||
<tr><td className='help-text'>{'%D'}</td><td className='help-text'>{'Date (2006/01/02)'}</td></tr>
|
||||
<tr><td className='help-text'>{'%d'}</td><td className='help-text'>{'Date (01/02/06)'}</td></tr>
|
||||
<tr><td className='help-text'>{'%L'}</td><td className='help-text'>{'Level (DEBG, INFO, EROR)'}</td></tr>
|
||||
<tr><td className='help-text'>{'%S'}</td><td className='help-text'>{'Source'}</td></tr>
|
||||
<tr><td className='help-text'>{'%M'}</td><td className='help-text'>{'Message'}</td></tr>
|
||||
<tr><td className='help-text'>{'%T'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.formatTime'
|
||||
defaultMessage='Time (15:04:05 MST)'
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td className='help-text'>{'%D'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.formatDateLong'
|
||||
defaultMessage='Date (2006/01/02)'
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td className='help-text'>{'%d'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.formatDateShort'
|
||||
defaultMessage='Date (01/02/06)'
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td className='help-text'>{'%L'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.formatLevel'
|
||||
defaultMessage='Level (DEBG, INFO, EROR)'
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td className='help-text'>{'%S'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.formatSource'
|
||||
defaultMessage='Source'
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td className='help-text'>{'%M'}</td><td className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.log.formatMessage'
|
||||
defaultMessage='Message'
|
||||
/>
|
||||
</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -279,9 +390,12 @@ export default class LogSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.log.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -293,5 +407,8 @@ export default class LogSettings extends React.Component {
|
||||
}
|
||||
|
||||
LogSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(LogSettings);
|
||||
@@ -5,6 +5,8 @@ import AdminStore from '../../stores/admin_store.jsx';
|
||||
import LoadingScreen from '../loading_screen.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class Logs extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -73,13 +75,21 @@ export default class Logs extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='panel'>
|
||||
<h3>{'Server Logs'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.logs.title'
|
||||
defaultMessage='Server Logs'
|
||||
/>
|
||||
</h3>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
onClick={this.reload}
|
||||
>
|
||||
{'Reload'}
|
||||
<FormattedMessage
|
||||
id='admin.logs.reload'
|
||||
defaultMessage='Reload'
|
||||
/>
|
||||
</button>
|
||||
<div className='log__panel'>
|
||||
{content}
|
||||
|
||||
@@ -4,7 +4,16 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
export default class PrivacySettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
saving: {
|
||||
id: 'admin.privacy.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class PrivacySettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -64,7 +73,12 @@ export default class PrivacySettings extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'Privacy Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.privacy.title'
|
||||
defaultMessage='Privacy Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -75,7 +89,10 @@ export default class PrivacySettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ShowEmailAddress'
|
||||
>
|
||||
{'Show Email Address: '}
|
||||
<FormattedMessage
|
||||
id='admin.privacy.showEmailTitle'
|
||||
defaultMessage='Show Email Address: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -87,7 +104,10 @@ export default class PrivacySettings extends React.Component {
|
||||
defaultChecked={this.props.config.PrivacySettings.ShowEmailAddress}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.privacy.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -97,9 +117,17 @@ export default class PrivacySettings extends React.Component {
|
||||
defaultChecked={!this.props.config.PrivacySettings.ShowEmailAddress}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.privacy.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When false, hides email address of users from other users in the user interface, including team owners and team administrators. Used when system is set up for managing teams where some users choose to keep their contact information private.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.privacy.showEmailDescription'
|
||||
defaultMessage='When false, hides email address of users from other users in the user interface, including team owners and team administrators. Used when system is set up for managing teams where some users choose to keep their contact information private.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -108,7 +136,10 @@ export default class PrivacySettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ShowFullName'
|
||||
>
|
||||
{'Show Full Name: '}
|
||||
<FormattedMessage
|
||||
id='admin.privacy.showFullNameTitle'
|
||||
defaultMessage='Show Full Name: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -120,7 +151,10 @@ export default class PrivacySettings extends React.Component {
|
||||
defaultChecked={this.props.config.PrivacySettings.ShowFullName}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.privacy.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -130,9 +164,17 @@ export default class PrivacySettings extends React.Component {
|
||||
defaultChecked={!this.props.config.PrivacySettings.ShowFullName}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.privacy.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When false, hides full name of users from other users, including team owners and team administrators. Username is shown in place of full name.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.privacy.showFullNameDescription'
|
||||
defaultMessage='When false, hides full name of users from other users, including team owners and team administrators. Username is shown in place of full name.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -145,9 +187,12 @@ export default class PrivacySettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + this.props.intl.formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.privacy.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -159,5 +204,8 @@ export default class PrivacySettings extends React.Component {
|
||||
}
|
||||
|
||||
PrivacySettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(PrivacySettings);
|
||||
@@ -4,7 +4,28 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
export default class RateSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
queriesExample: {
|
||||
id: 'admin.rate.queriesExample',
|
||||
defaultMessage: 'Ex "10"'
|
||||
},
|
||||
memoryExample: {
|
||||
id: 'admin.rate.memoryExample',
|
||||
defaultMessage: 'Ex "10000"'
|
||||
},
|
||||
httpHeaderExample: {
|
||||
id: 'admin.rate.httpHeaderExample',
|
||||
defaultMessage: 'Ex "X-Real-IP", "X-Forwarded-For"'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.rate.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class RateSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -85,6 +106,7 @@ export default class RateSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -100,12 +122,27 @@ export default class RateSettings extends React.Component {
|
||||
|
||||
<div className='banner'>
|
||||
<div className='banner__content'>
|
||||
<h4 className='banner__heading'>{'Note:'}</h4>
|
||||
<p>{'Changing properties in this section will require a server restart before taking effect.'}</p>
|
||||
<h4 className='banner__heading'>
|
||||
<FormattedMessage
|
||||
id='admin.rate.noteTitle'
|
||||
defaultMessage='Note:'
|
||||
/>
|
||||
</h4>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='admin.rate.noteDescription'
|
||||
defaultMessage='Changing properties in this section will require a server restart before taking effect.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>{'Rate Limit Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.rate.title'
|
||||
defaultMessage='Rate Limit Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -116,7 +153,10 @@ export default class RateSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableRateLimiter'
|
||||
>
|
||||
{'Enable Rate Limiter: '}
|
||||
<FormattedMessage
|
||||
id='admin.rate.enableLimiterTitle'
|
||||
defaultMessage='Enable Rate Limiter: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -128,7 +168,10 @@ export default class RateSettings extends React.Component {
|
||||
defaultChecked={this.props.config.RateLimitSettings.EnableRateLimiter}
|
||||
onChange={this.handleChange.bind(this, 'EnableRateLimiterTrue')}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -138,9 +181,17 @@ export default class RateSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.RateLimitSettings.EnableRateLimiter}
|
||||
onChange={this.handleChange.bind(this, 'EnableRateLimiterFalse')}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, APIs are throttled at rates specified below.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.rate.enableLimiterDescription'
|
||||
defaultMessage='When true, APIs are throttled at rates specified below.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -149,7 +200,10 @@ export default class RateSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='PerSec'
|
||||
>
|
||||
{'Number Of Queries Per Second:'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.queriesTitle'
|
||||
defaultMessage='Number Of Queries Per Second:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -157,12 +211,17 @@ export default class RateSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='PerSec'
|
||||
ref='PerSec'
|
||||
placeholder='Ex "10"'
|
||||
placeholder={formatMessage(holders.queriesExample)}
|
||||
defaultValue={this.props.config.RateLimitSettings.PerSec}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.EnableRateLimiter}
|
||||
/>
|
||||
<p className='help-text'>{'Throttles API at this number of requests per second.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.rate.queriesDescription'
|
||||
defaultMessage='Throttles API at this number of requests per second.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -171,7 +230,10 @@ export default class RateSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='MemoryStoreSize'
|
||||
>
|
||||
{'Memory Store Size:'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.memoryTitle'
|
||||
defaultMessage='Memory Store Size:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -179,12 +241,17 @@ export default class RateSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='MemoryStoreSize'
|
||||
ref='MemoryStoreSize'
|
||||
placeholder='Ex "10000"'
|
||||
placeholder={formatMessage(holders.memoryExample)}
|
||||
defaultValue={this.props.config.RateLimitSettings.MemoryStoreSize}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.EnableRateLimiter}
|
||||
/>
|
||||
<p className='help-text'>{'Maximum number of users sessions connected to the system as determined by "Vary By Remote Address" and "Vary By Header" settings below.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.rate.memoryDescription'
|
||||
defaultMessage='Maximum number of users sessions connected to the system as determined by "Vary By Remote Address" and "Vary By Header" settings below.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -193,7 +260,10 @@ export default class RateSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='VaryByRemoteAddr'
|
||||
>
|
||||
{'Vary By Remote Address: '}
|
||||
<FormattedMessage
|
||||
id='admin.rate.remoteTitle'
|
||||
defaultMessage='Vary By Remote Address: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -206,7 +276,10 @@ export default class RateSettings extends React.Component {
|
||||
onChange={this.handleChange.bind(this, 'VaryByRemoteAddrTrue')}
|
||||
disabled={!this.state.EnableRateLimiter}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -217,9 +290,17 @@ export default class RateSettings extends React.Component {
|
||||
onChange={this.handleChange.bind(this, 'VaryByRemoteAddrFalse')}
|
||||
disabled={!this.state.EnableRateLimiter}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, rate limit API access by IP address.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.rate.remoteDescription'
|
||||
defaultMessage='When true, rate limit API access by IP address.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -228,7 +309,10 @@ export default class RateSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='VaryByHeader'
|
||||
>
|
||||
{'Vary By HTTP Header:'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.httpHeaderTitle'
|
||||
defaultMessage='Vary By HTTP Header:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -236,12 +320,17 @@ export default class RateSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='VaryByHeader'
|
||||
ref='VaryByHeader'
|
||||
placeholder='Ex "X-Real-IP", "X-Forwarded-For"'
|
||||
placeholder={formatMessage(holders.httpHeaderExample)}
|
||||
defaultValue={this.props.config.RateLimitSettings.VaryByHeader}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.EnableRateLimiter || this.state.VaryByRemoteAddr}
|
||||
/>
|
||||
<p className='help-text'>{'When filled in, vary rate limiting by HTTP header field specified (e.g. when configuring NGINX set to "X-Real-IP", when configuring AmazonELB set to "X-Forwarded-For").'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.rate.httpHeaderDescription'
|
||||
defaultMessage='When filled in, vary rate limiting by HTTP header field specified (e.g. when configuring NGINX set to "X-Real-IP", when configuring AmazonELB set to "X-Forwarded-For").'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -254,9 +343,12 @@ export default class RateSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.rate.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -268,5 +360,8 @@ export default class RateSettings extends React.Component {
|
||||
}
|
||||
|
||||
RateSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(RateSettings);
|
||||
@@ -5,7 +5,16 @@ import * as Client from '../../utils/client.jsx';
|
||||
import Constants from '../../utils/constants.jsx';
|
||||
var Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class ResetPasswordModal extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
submit: {
|
||||
id: 'admin.reset_password.submit',
|
||||
defaultMessage: 'Please enter at least {chars} characters.'
|
||||
}
|
||||
});
|
||||
|
||||
class ResetPasswordModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -22,7 +31,7 @@ export default class ResetPasswordModal extends React.Component {
|
||||
var password = ReactDOM.findDOMNode(this.refs.password).value;
|
||||
|
||||
if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
this.setState({serverError: 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters.'});
|
||||
this.setState({serverError: this.props.intl.formatMessage(holders.submit, {chars: Constants.MIN_PASSWORD_LENGTH})});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,7 +76,12 @@ export default class ResetPasswordModal extends React.Component {
|
||||
onHide={this.doCancel}
|
||||
>
|
||||
<Modal.Header closeButton={true}>
|
||||
<Modal.Title>{'Reset Password'}</Modal.Title>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id='admin.reset_password.title'
|
||||
defaultMessage='Reset Password'
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<form
|
||||
role='form'
|
||||
@@ -82,7 +96,10 @@ export default class ResetPasswordModal extends React.Component {
|
||||
title='New Password'
|
||||
className='input-group-addon'
|
||||
>
|
||||
{'New Password'}
|
||||
<FormattedMessage
|
||||
id='admin.reset_password.newPassword'
|
||||
defaultMessage='New Password'
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
type='password'
|
||||
@@ -103,7 +120,10 @@ export default class ResetPasswordModal extends React.Component {
|
||||
className='btn btn-default'
|
||||
onClick={this.doCancel}
|
||||
>
|
||||
{'Close'}
|
||||
<FormattedMessage
|
||||
id='admin.reset_password.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
onClick={this.doSubmit}
|
||||
@@ -111,7 +131,10 @@ export default class ResetPasswordModal extends React.Component {
|
||||
className='btn btn-primary'
|
||||
tabIndex='2'
|
||||
>
|
||||
{'Select'}
|
||||
<FormattedMessage
|
||||
id='admin.reset_password.select'
|
||||
defaultMessage='Select'
|
||||
/>
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</form>
|
||||
@@ -125,9 +148,12 @@ ResetPasswordModal.defaultProps = {
|
||||
};
|
||||
|
||||
ResetPasswordModal.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
user: React.PropTypes.object,
|
||||
team: React.PropTypes.object,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
onModalSubmit: React.PropTypes.func,
|
||||
onModalDismissed: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default injectIntl(ResetPasswordModal);
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
var Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class SelectTeamModal extends React.Component {
|
||||
@@ -45,7 +47,12 @@ export default class SelectTeamModal extends React.Component {
|
||||
onHide={this.doCancel}
|
||||
>
|
||||
<Modal.Header closeButton={true}>
|
||||
<Modal.Title>{'Select Team'}</Modal.Title>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id='admin.select_team.selectTeam'
|
||||
defaultMessage='Select Team'
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<form
|
||||
role='form'
|
||||
@@ -70,7 +77,10 @@ export default class SelectTeamModal extends React.Component {
|
||||
className='btn btn-default'
|
||||
onClick={this.doCancel}
|
||||
>
|
||||
{'Close'}
|
||||
<FormattedMessage
|
||||
id='admin.select_team.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
onClick={this.doSubmit}
|
||||
@@ -78,7 +88,10 @@ export default class SelectTeamModal extends React.Component {
|
||||
className='btn btn-primary'
|
||||
tabIndex='2'
|
||||
>
|
||||
{'Select'}
|
||||
<FormattedMessage
|
||||
id='admin.select_team.select'
|
||||
defaultMessage='Select'
|
||||
/>
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</form>
|
||||
@@ -96,4 +109,4 @@ SelectTeamModal.propTypes = {
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
onModalSubmit: React.PropTypes.func,
|
||||
onModalDismissed: React.PropTypes.func
|
||||
};
|
||||
};
|
||||
@@ -4,11 +4,40 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
const DefaultSessionLength = 30;
|
||||
const DefaultMaximumLoginAttempts = 10;
|
||||
const DefaultSessionCacheInMinutes = 10;
|
||||
|
||||
export default class ServiceSettings extends React.Component {
|
||||
var holders = defineMessages({
|
||||
listenExample: {
|
||||
id: 'admin.service.listenExample',
|
||||
defaultMessage: 'Ex ":8065"'
|
||||
},
|
||||
attemptExample: {
|
||||
id: 'admin.service.attemptExample',
|
||||
defaultMessage: 'Ex "10"'
|
||||
},
|
||||
segmentExample: {
|
||||
id: 'admin.service.segmentExample',
|
||||
defaultMessage: 'Ex "g3fgGOXJAQ43QV7rAh6iwQCkV4cA1Gs"'
|
||||
},
|
||||
googleExample: {
|
||||
id: 'admin.service.googleExample',
|
||||
defaultMessage: 'Ex "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"'
|
||||
},
|
||||
sessionDaysEx: {
|
||||
id: 'admin.service.sessionDaysEx',
|
||||
defaultMessage: 'Ex "30"'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.service.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class ServiceSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -120,6 +149,7 @@ export default class ServiceSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -133,7 +163,12 @@ export default class ServiceSettings extends React.Component {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
|
||||
<h3>{'Service Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.service.title'
|
||||
defaultMessage='Service Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -144,7 +179,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='ListenAddress'
|
||||
>
|
||||
{'Listen Address:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.listenAddress'
|
||||
defaultMessage='Listen Address:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -152,11 +190,16 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='ListenAddress'
|
||||
ref='ListenAddress'
|
||||
placeholder='Ex ":8065"'
|
||||
placeholder={formatMessage(holders.listenExample)}
|
||||
defaultValue={this.props.config.ServiceSettings.ListenAddress}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'The address to which to bind and listen. Entering ":8065" will bind to all interfaces or you can choose one like "127.0.0.1:8065". Changing this will require a server restart before taking effect.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.listenDescription'
|
||||
defaultMessage='The address to which to bind and listen. Entering ":8065" will bind to all interfaces or you can choose one like "127.0.0.1:8065". Changing this will require a server restart before taking effect.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -165,7 +208,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='MaximumLoginAttempts'
|
||||
>
|
||||
{'Maximum Login Attempts:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.attemptTitle'
|
||||
defaultMessage='Maximum Login Attempts:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -173,11 +219,16 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='MaximumLoginAttempts'
|
||||
ref='MaximumLoginAttempts'
|
||||
placeholder='Ex "10"'
|
||||
placeholder={formatMessage(holders.attemptExample)}
|
||||
defaultValue={this.props.config.ServiceSettings.MaximumLoginAttempts}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Login attempts allowed before user is locked out and required to reset password via email.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.attemptDescription'
|
||||
defaultMessage='Login attempts allowed before user is locked out and required to reset password via email.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -186,7 +237,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SegmentDeveloperKey'
|
||||
>
|
||||
{'Segment Developer Key:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.segmentTitle'
|
||||
defaultMessage='Segment Developer Key:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -194,11 +248,16 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SegmentDeveloperKey'
|
||||
ref='SegmentDeveloperKey'
|
||||
placeholder='Ex "g3fgGOXJAQ43QV7rAh6iwQCkV4cA1Gs"'
|
||||
placeholder={formatMessage(holders.segmentExample)}
|
||||
defaultValue={this.props.config.ServiceSettings.SegmentDeveloperKey}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'For users running a SaaS services, sign up for a key at Segment.com to track metrics.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.segmentDescription'
|
||||
defaultMessage='For users running a SaaS services, sign up for a key at Segment.com to track metrics.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -207,7 +266,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='GoogleDeveloperKey'
|
||||
>
|
||||
{'Google Developer Key:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.googleTitle'
|
||||
defaultMessage='Google Developer Key:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -215,19 +277,17 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='GoogleDeveloperKey'
|
||||
ref='GoogleDeveloperKey'
|
||||
placeholder='Ex "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"'
|
||||
placeholder={formatMessage(holders.googleExample)}
|
||||
defaultValue={this.props.config.ServiceSettings.GoogleDeveloperKey}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>
|
||||
{'Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at '}
|
||||
<a
|
||||
href='https://www.youtube.com/watch?v=Im69kzhpR3I'
|
||||
target='_blank'
|
||||
>
|
||||
{'https://www.youtube.com/watch?v=Im69kzhpR3I'}
|
||||
</a>
|
||||
{'. Leaving the field blank disables the automatic generation of YouTube video previews from links.'}
|
||||
<FormattedHTMLMessage
|
||||
id='admin.service.googleDescription'
|
||||
defaultMessage='Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at
|
||||
<a href="https://www.youtube.com/watch?v=Im69kzhpR3I" target="_blank">https://www.youtube.com/watch?v=Im69kzhpR3I</a>.
|
||||
Leaving the field blank disables the automatic generation of YouTube video previews from links.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -237,7 +297,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableIncomingWebhooks'
|
||||
>
|
||||
{'Enable Incoming Webhooks: '}
|
||||
<FormattedMessage
|
||||
id='admin.service.webhooksTitle'
|
||||
defaultMessage='Enable Incoming Webhooks: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -249,7 +312,10 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={this.props.config.ServiceSettings.EnableIncomingWebhooks}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -259,9 +325,17 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnableIncomingWebhooks}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, incoming webhooks will be allowed. To help combat phishing attacks, all posts from webhooks will be labelled by a BOT tag.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.webhooksDescription'
|
||||
defaultMessage='When true, incoming webhooks will be allowed. To help combat phishing attacks, all posts from webhooks will be labelled by a BOT tag.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -270,7 +344,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableOutgoingWebhooks'
|
||||
>
|
||||
{'Enable Outgoing Webhooks: '}
|
||||
<FormattedMessage
|
||||
id='admin.service.outWebhooksTitle'
|
||||
defaultMessage='Enable Outgoing Webhooks: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -282,7 +359,10 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={this.props.config.ServiceSettings.EnableOutgoingWebhooks}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -292,9 +372,17 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnableOutgoingWebhooks}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, outgoing webhooks will be allowed.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.outWebhooksDesc'
|
||||
defaultMessage='When true, outgoing webhooks will be allowed.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -303,7 +391,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnablePostUsernameOverride'
|
||||
>
|
||||
{'Enable Overriding Usernames from Webhooks: '}
|
||||
<FormattedMessage
|
||||
id='admin.service.overrideTitle'
|
||||
defaultMessage='Enable Overriding Usernames from Webhooks: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -315,7 +406,10 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={this.props.config.ServiceSettings.EnablePostUsernameOverride}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -325,9 +419,17 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnablePostUsernameOverride}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, webhooks will be allowed to change the username they are posting as. Note, combined with allowing icon overriding, this could open users up to phishing attacks.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.overrideDescription'
|
||||
defaultMessage='When true, webhooks will be allowed to change the username they are posting as. Note, combined with allowing icon overriding, this could open users up to phishing attacks.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -336,7 +438,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnablePostIconOverride'
|
||||
>
|
||||
{'Enable Overriding Icon from Webhooks: '}
|
||||
<FormattedMessage
|
||||
id='admin.service.iconTitle'
|
||||
defaultMessage='Enable Overriding Icon from Webhooks: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -348,7 +453,10 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={this.props.config.ServiceSettings.EnablePostIconOverride}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -358,9 +466,17 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnablePostIconOverride}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, webhooks will be allowed to change the icon they post with. Note, combined with allowing username overriding, this could open users up to phishing attacks.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.iconDescription'
|
||||
defaultMessage='When true, webhooks will be allowed to change the icon they post with. Note, combined with allowing username overriding, this could open users up to phishing attacks.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -369,7 +485,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableTesting'
|
||||
>
|
||||
{'Enable Testing: '}
|
||||
<FormattedMessage
|
||||
id='admin.service.testingTitle'
|
||||
defaultMessage='Enable Testing: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -381,7 +500,10 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={this.props.config.ServiceSettings.EnableTesting}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -391,9 +513,17 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnableTesting}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'(Developer Option) When true, /loadtest slash command is enabled to load test accounts and test data. Changing this will require a server restart before taking effect.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.testingDescription'
|
||||
defaultMessage='(Developer Option) When true, /loadtest slash command is enabled to load test accounts and test data. Changing this will require a server restart before taking effect.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -402,7 +532,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableDeveloper'
|
||||
>
|
||||
{'Enable Developer Mode: '}
|
||||
<FormattedMessage
|
||||
id='admin.service.developerTitle'
|
||||
defaultMessage='Enable Developer Mode: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -414,7 +547,10 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={this.props.config.ServiceSettings.EnableDeveloper}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -424,9 +560,17 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnableDeveloper}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'(Developer Option) When true, extra information around errors will be displayed in the UI.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.developerDesc'
|
||||
defaultMessage='(Developer Option) When true, extra information around errors will be displayed in the UI.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -435,7 +579,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableSecurityFixAlert'
|
||||
>
|
||||
{'Enable Security Alerts: '}
|
||||
<FormattedMessage
|
||||
id='admin.service.securityTitle'
|
||||
defaultMessage='Enable Security Alerts: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -447,7 +594,10 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={this.props.config.ServiceSettings.EnableSecurityFixAlert}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.service.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -457,9 +607,17 @@ export default class ServiceSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.ServiceSettings.EnableSecurityFixAlert}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.service.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.securityDesc'
|
||||
defaultMessage='When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -468,7 +626,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SessionLengthWebInDays'
|
||||
>
|
||||
{'Session Length for Web in Days:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.webSessionDays'
|
||||
defaultMessage='Session Length for Web in Days:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -476,11 +637,16 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SessionLengthWebInDays'
|
||||
ref='SessionLengthWebInDays'
|
||||
placeholder='Ex "30"'
|
||||
placeholder={formatMessage(holders.sessionDaysEx)}
|
||||
defaultValue={this.props.config.ServiceSettings.SessionLengthWebInDays}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'The web session will expire after the number of days specified and will require a user to login again.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.webSessionDaysDesc'
|
||||
defaultMessage='The web session will expire after the number of days specified and will require a user to login again.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -489,7 +655,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SessionLengthMobileInDays'
|
||||
>
|
||||
{'Session Length for Mobile Device in Days:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.mobileSessionDays'
|
||||
defaultMessage='Session Length for Mobile Device in Days:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -497,11 +666,16 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SessionLengthMobileInDays'
|
||||
ref='SessionLengthMobileInDays'
|
||||
placeholder='Ex "30"'
|
||||
placeholder={formatMessage(holders.sessionDaysEx)}
|
||||
defaultValue={this.props.config.ServiceSettings.SessionLengthMobileInDays}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'The native mobile session will expire after the number of days specified and will require a user to login again.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.mobileSessionDaysDesc'
|
||||
defaultMessage='The native mobile session will expire after the number of days specified and will require a user to login again.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -510,7 +684,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SessionLengthSSOInDays'
|
||||
>
|
||||
{'Session Length for SSO in Days:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.ssoSessionDays'
|
||||
defaultMessage='Session Length for SSO in Days:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -518,11 +695,16 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SessionLengthSSOInDays'
|
||||
ref='SessionLengthSSOInDays'
|
||||
placeholder='Ex "30"'
|
||||
placeholder={formatMessage(holders.sessionDaysEx)}
|
||||
defaultValue={this.props.config.ServiceSettings.SessionLengthSSOInDays}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'The SSO session will expire after the number of days specified and will require a user to login again.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.ssoSessionDaysDesc'
|
||||
defaultMessage='The SSO session will expire after the number of days specified and will require a user to login again.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -531,7 +713,10 @@ export default class ServiceSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SessionCacheInMinutes'
|
||||
>
|
||||
{'Session Cache in Minutes:'}
|
||||
<FormattedMessage
|
||||
id='admin.service.sessionCache'
|
||||
defaultMessage='Session Cache in Minutes:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -539,11 +724,16 @@ export default class ServiceSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SessionCacheInMinutes'
|
||||
ref='SessionCacheInMinutes'
|
||||
placeholder='Ex "30"'
|
||||
placeholder={formatMessage(holders.sessionDaysEx)}
|
||||
defaultValue={this.props.config.ServiceSettings.SessionCacheInMinutes}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'The number of minutes to cache a session in memory.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.sessionCacheDesc'
|
||||
defaultMessage='The number of minutes to cache a session in memory.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -556,9 +746,12 @@ export default class ServiceSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.service.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -603,5 +796,8 @@ export default class ServiceSettings extends React.Component {
|
||||
// </div>
|
||||
|
||||
ServiceSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(ServiceSettings);
|
||||
@@ -5,7 +5,32 @@ import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
import crypto from 'crypto';
|
||||
|
||||
export default class SqlSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
warning: {
|
||||
id: 'admin.sql.warning',
|
||||
defaultMessage: 'Warning: re-generating this salt may cause some columns in the database to return empty results.'
|
||||
},
|
||||
maxConnectionsExample: {
|
||||
id: 'admin.sql.maxConnectionsExample',
|
||||
defaultMessage: 'Ex "10"'
|
||||
},
|
||||
maxOpenExample: {
|
||||
id: 'admin.sql.maxOpenExample',
|
||||
defaultMessage: 'Ex "10"'
|
||||
},
|
||||
keyExample: {
|
||||
id: 'admin.sql.keyExample',
|
||||
defaultMessage: 'Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.sql.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class SqlSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -74,7 +99,7 @@ export default class SqlSettings extends React.Component {
|
||||
handleGenerate(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var cfm = global.window.confirm('Warning: re-generating this salt may cause some columns in the database to return empty results.');
|
||||
var cfm = global.window.confirm(this.props.intl.formatMessage(holders.warning));
|
||||
if (cfm === false) {
|
||||
return;
|
||||
}
|
||||
@@ -85,6 +110,7 @@ export default class SqlSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -111,12 +137,27 @@ export default class SqlSettings extends React.Component {
|
||||
|
||||
<div className='banner'>
|
||||
<div className='banner__content'>
|
||||
<h4 className='banner__heading'>{'Note:'}</h4>
|
||||
<p>{'Changing properties in this section will require a server restart before taking effect.'}</p>
|
||||
<h4 className='banner__heading'>
|
||||
<FormattedMessage
|
||||
id='admin.sql.noteTitle'
|
||||
defaultMessage='Note:'
|
||||
/>
|
||||
</h4>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='admin.sql.noteDescription'
|
||||
defaultMessage='Changing properties in this section will require a server restart before taking effect.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>{'SQL Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.sql.title'
|
||||
defaultMessage='SQL Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -127,7 +168,10 @@ export default class SqlSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='DriverName'
|
||||
>
|
||||
{'Driver Name:'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.driverName'
|
||||
defaultMessage='Driver Name:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<p className='help-text'>{this.props.config.SqlSettings.DriverName}</p>
|
||||
@@ -139,7 +183,10 @@ export default class SqlSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='DataSource'
|
||||
>
|
||||
{'Data Source:'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.dataSource'
|
||||
defaultMessage='Data Source:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<p className='help-text'>{dataSource}</p>
|
||||
@@ -151,7 +198,10 @@ export default class SqlSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='DataSourceReplicas'
|
||||
>
|
||||
{'Data Source Replicas:'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.replicas'
|
||||
defaultMessage='Data Source Replicas:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<p className='help-text'>{dataSourceReplicas}</p>
|
||||
@@ -163,7 +213,10 @@ export default class SqlSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='MaxIdleConns'
|
||||
>
|
||||
{'Maximum Idle Connections:'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.maxConnectionsTitle'
|
||||
defaultMessage='Maximum Idle Connections:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -171,11 +224,16 @@ export default class SqlSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='MaxIdleConns'
|
||||
ref='MaxIdleConns'
|
||||
placeholder='Ex "10"'
|
||||
placeholder={formatMessage(holders.maxConnectionsExample)}
|
||||
defaultValue={this.props.config.SqlSettings.MaxIdleConns}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Maximum number of idle connections held open to the database.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.sql.maxConnectionsDescription'
|
||||
defaultMessage='Maximum number of idle connections held open to the database.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -184,7 +242,10 @@ export default class SqlSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='MaxOpenConns'
|
||||
>
|
||||
{'Maximum Open Connections:'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.maxOpenTitle'
|
||||
defaultMessage='Maximum Open Connections:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -192,11 +253,16 @@ export default class SqlSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='MaxOpenConns'
|
||||
ref='MaxOpenConns'
|
||||
placeholder='Ex "10"'
|
||||
placeholder={formatMessage(holders.maxOpenExample)}
|
||||
defaultValue={this.props.config.SqlSettings.MaxOpenConns}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Maximum number of open connections held open to the database.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.sql.maxOpenDescription'
|
||||
defaultMessage='Maximum number of open connections held open to the database.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -205,7 +271,10 @@ export default class SqlSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AtRestEncryptKey'
|
||||
>
|
||||
{'At Rest Encrypt Key:'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.keyTitle'
|
||||
defaultMessage='At Rest Encrypt Key:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -213,17 +282,25 @@ export default class SqlSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='AtRestEncryptKey'
|
||||
ref='AtRestEncryptKey'
|
||||
placeholder='Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"'
|
||||
placeholder={formatMessage(holders.keyExample)}
|
||||
defaultValue={this.props.config.SqlSettings.AtRestEncryptKey}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'32-character salt available to encrypt and decrypt sensitive fields in database.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.sql.keyDescription'
|
||||
defaultMessage='32-character salt available to encrypt and decrypt sensitive fields in database.'
|
||||
/>
|
||||
</p>
|
||||
<div className='help-text'>
|
||||
<button
|
||||
className='btn btn-default'
|
||||
onClick={this.handleGenerate}
|
||||
>
|
||||
{'Re-Generate'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.regenerate'
|
||||
defaultMessage='Re-Generate'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -234,7 +311,10 @@ export default class SqlSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='Trace'
|
||||
>
|
||||
{'Trace: '}
|
||||
<FormattedMessage
|
||||
id='admin.sql.traceTitle'
|
||||
defaultMessage='Trace: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -246,7 +326,10 @@ export default class SqlSettings extends React.Component {
|
||||
defaultChecked={this.props.config.SqlSettings.Trace}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -256,9 +339,17 @@ export default class SqlSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.SqlSettings.Trace}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'(Development Mode) When true, executing SQL statements are written to the log.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.sql.traceDescription'
|
||||
defaultMessage='(Development Mode) When true, executing SQL statements are written to the log.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -271,9 +362,12 @@ export default class SqlSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.sql.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -285,5 +379,8 @@ export default class SqlSettings extends React.Component {
|
||||
}
|
||||
|
||||
SqlSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(SqlSettings);
|
||||
@@ -4,7 +4,24 @@
|
||||
import Analytics from './analytics.jsx';
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
|
||||
export default class SystemAnalytics extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages} from 'mm-intl';
|
||||
|
||||
const labels = defineMessages({
|
||||
totalPosts: {
|
||||
id: 'admin.system_analytics.totalPosts',
|
||||
defaultMessage: 'Total Posts'
|
||||
},
|
||||
activeUsers: {
|
||||
id: 'admin.system_analytics.activeUsers',
|
||||
defaultMessage: 'Active Users With Posts'
|
||||
},
|
||||
title: {
|
||||
id: 'admin.system_analytics.title',
|
||||
defaultMessage: 'the System'
|
||||
}
|
||||
});
|
||||
|
||||
class SystemAnalytics extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -29,6 +46,7 @@ export default class SystemAnalytics extends React.Component {
|
||||
}
|
||||
|
||||
getData() { // should be moved to an action creator eventually
|
||||
const {formatMessage} = this.props.intl;
|
||||
Client.getSystemAnalytics(
|
||||
'standard',
|
||||
(data) => {
|
||||
@@ -63,7 +81,7 @@ export default class SystemAnalytics extends React.Component {
|
||||
var chartData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Total Posts',
|
||||
label: formatMessage(labels.totalPosts),
|
||||
fillColor: 'rgba(151,187,205,0.2)',
|
||||
strokeColor: 'rgba(151,187,205,1)',
|
||||
pointColor: 'rgba(151,187,205,1)',
|
||||
@@ -97,7 +115,7 @@ export default class SystemAnalytics extends React.Component {
|
||||
var chartData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Active Users With Posts',
|
||||
label: formatMessage(labels.activeUsers),
|
||||
fillColor: 'rgba(151,187,205,0.2)',
|
||||
strokeColor: 'rgba(151,187,205,1)',
|
||||
pointColor: 'rgba(151,187,205,1)',
|
||||
@@ -142,7 +160,7 @@ export default class SystemAnalytics extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
<Analytics
|
||||
title={'the System'}
|
||||
title={this.props.intl.formatMessage(labels.title)}
|
||||
channelOpenCount={this.state.channel_open_count}
|
||||
channelPrivateCount={this.state.channel_private_count}
|
||||
postCount={this.state.post_count}
|
||||
@@ -157,5 +175,8 @@ export default class SystemAnalytics extends React.Component {
|
||||
}
|
||||
|
||||
SystemAnalytics.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
team: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(SystemAnalytics);
|
||||
@@ -4,7 +4,20 @@
|
||||
import Analytics from './analytics.jsx';
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
|
||||
export default class TeamAnalytics extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages} from 'mm-intl';
|
||||
|
||||
const labels = defineMessages({
|
||||
totalPosts: {
|
||||
id: 'admin.team_analytics.totalPosts',
|
||||
defaultMessage: 'Total Posts'
|
||||
},
|
||||
activeUsers: {
|
||||
id: 'admin.team_analytics.activeUsers',
|
||||
defaultMessage: 'Active Users With Posts'
|
||||
}
|
||||
});
|
||||
|
||||
class TeamAnalytics extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -29,6 +42,7 @@ export default class TeamAnalytics extends React.Component {
|
||||
}
|
||||
|
||||
getData(teamId) { // should be moved to an action creator eventually
|
||||
const {formatMessage} = this.props.intl;
|
||||
Client.getTeamAnalytics(
|
||||
teamId,
|
||||
'standard',
|
||||
@@ -65,7 +79,7 @@ export default class TeamAnalytics extends React.Component {
|
||||
var chartData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Total Posts',
|
||||
label: formatMessage(labels.totalPosts),
|
||||
fillColor: 'rgba(151,187,205,0.2)',
|
||||
strokeColor: 'rgba(151,187,205,1)',
|
||||
pointColor: 'rgba(151,187,205,1)',
|
||||
@@ -100,7 +114,7 @@ export default class TeamAnalytics extends React.Component {
|
||||
var chartData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Active Users With Posts',
|
||||
label: formatMessage(labels.activeUsers),
|
||||
fillColor: 'rgba(151,187,205,0.2)',
|
||||
strokeColor: 'rgba(151,187,205,1)',
|
||||
pointColor: 'rgba(151,187,205,1)',
|
||||
@@ -231,5 +245,8 @@ export default class TeamAnalytics extends React.Component {
|
||||
}
|
||||
|
||||
TeamAnalytics.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
team: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(TeamAnalytics);
|
||||
@@ -4,7 +4,28 @@
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
|
||||
export default class TeamSettings extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
siteNameExample: {
|
||||
id: 'admin.team.siteNameExample',
|
||||
defaultMessage: 'Ex "Mattermost"'
|
||||
},
|
||||
maxUsersExample: {
|
||||
id: 'admin.team.maxUsersExample',
|
||||
defaultMessage: 'Ex "25"'
|
||||
},
|
||||
restrictExample: {
|
||||
id: 'admin.team.restrictExample',
|
||||
defaultMessage: 'Ex "corp.mattermost.com, mattermost.org"'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.team.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
}
|
||||
});
|
||||
|
||||
class TeamSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -62,6 +83,7 @@ export default class TeamSettings extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var serverError = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
||||
@@ -75,7 +97,12 @@ export default class TeamSettings extends React.Component {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
|
||||
<h3>{'Team Settings'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.team.title'
|
||||
defaultMessage='Team Settings'
|
||||
/>
|
||||
</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
@@ -86,7 +113,10 @@ export default class TeamSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='SiteName'
|
||||
>
|
||||
{'Site Name:'}
|
||||
<FormattedMessage
|
||||
id='admin.team.siteNameTitle'
|
||||
defaultMessage='Site Name:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -94,11 +124,16 @@ export default class TeamSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='SiteName'
|
||||
ref='SiteName'
|
||||
placeholder='Ex "Mattermost"'
|
||||
placeholder={formatMessage(holders.siteNameExample)}
|
||||
defaultValue={this.props.config.TeamSettings.SiteName}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Name of service shown in login screens and UI.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.team.siteNameDescription'
|
||||
defaultMessage='Name of service shown in login screens and UI.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -107,7 +142,10 @@ export default class TeamSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='MaxUsersPerTeam'
|
||||
>
|
||||
{'Max Users Per Team:'}
|
||||
<FormattedMessage
|
||||
id='admin.team.maxUsersTitle'
|
||||
defaultMessage='Max Users Per Team:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -115,11 +153,16 @@ export default class TeamSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='MaxUsersPerTeam'
|
||||
ref='MaxUsersPerTeam'
|
||||
placeholder='Ex "25"'
|
||||
placeholder={formatMessage(holders.maxUsersExample)}
|
||||
defaultValue={this.props.config.TeamSettings.MaxUsersPerTeam}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Maximum total number of users per team, including both active and inactive users.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.team.maxUsersDescription'
|
||||
defaultMessage='Maximum total number of users per team, including both active and inactive users.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -128,7 +171,10 @@ export default class TeamSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableTeamCreation'
|
||||
>
|
||||
{'Enable Team Creation: '}
|
||||
<FormattedMessage
|
||||
id='admin.team.teamCreationTitle'
|
||||
defaultMessage='Enable Team Creation: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -140,7 +186,10 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={this.props.config.TeamSettings.EnableTeamCreation}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.team.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -150,9 +199,17 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.TeamSettings.EnableTeamCreation}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.team.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When false, the ability to create teams is disabled. The create team button displays error when pressed.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.team.teamCreationDescription'
|
||||
defaultMessage='When false, the ability to create teams is disabled. The create team button displays error when pressed.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -161,7 +218,10 @@ export default class TeamSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableUserCreation'
|
||||
>
|
||||
{'Enable User Creation: '}
|
||||
<FormattedMessage
|
||||
id='admin.team.userCreationTitle'
|
||||
defaultMessage='Enable User Creation: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -173,7 +233,10 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={this.props.config.TeamSettings.EnableUserCreation}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.team.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -183,9 +246,17 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.TeamSettings.EnableUserCreation}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.team.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When false, the ability to create accounts is disabled. The create account button displays error when pressed.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.team.userCreationDescription'
|
||||
defaultMessage='When false, the ability to create accounts is disabled. The create account button displays error when pressed.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -194,7 +265,10 @@ export default class TeamSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='RestrictCreationToDomains'
|
||||
>
|
||||
{'Restrict Creation To Domains:'}
|
||||
<FormattedMessage
|
||||
id='admin.team.restrictTitle'
|
||||
defaultMessage='Restrict Creation To Domains:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
@@ -202,11 +276,16 @@ export default class TeamSettings extends React.Component {
|
||||
className='form-control'
|
||||
id='RestrictCreationToDomains'
|
||||
ref='RestrictCreationToDomains'
|
||||
placeholder='Ex "corp.mattermost.com, mattermost.org"'
|
||||
placeholder={formatMessage(holders.restrictExample)}
|
||||
defaultValue={this.props.config.TeamSettings.RestrictCreationToDomains}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>{'Teams and user accounts can only be created from a specific domain (e.g. "mattermost.org") or list of comma-separated domains (e.g. "corp.mattermost.com, mattermost.org").'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.team.restrictDescription'
|
||||
defaultMessage='Teams and user accounts can only be created from a specific domain (e.g. "mattermost.org") or list of comma-separated domains (e.g. "corp.mattermost.com, mattermost.org").'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -215,7 +294,10 @@ export default class TeamSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='RestrictTeamNames'
|
||||
>
|
||||
{'Restrict Team Names: '}
|
||||
<FormattedMessage
|
||||
id='admin.team.restrictNameTitle'
|
||||
defaultMessage='Restrict Team Names: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -227,7 +309,10 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={this.props.config.TeamSettings.RestrictTeamNames}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.team.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -237,9 +322,17 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.TeamSettings.RestrictTeamNames}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.team.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, You cannot create a team name with reserved words like www, admin, support, test, channel, etc'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.team.restrictNameDesc'
|
||||
defaultMessage='When true, You cannot create a team name with reserved words like www, admin, support, test, channel, etc'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -248,7 +341,10 @@ export default class TeamSettings extends React.Component {
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='EnableTeamListing'
|
||||
>
|
||||
{'Enable Team Directory: '}
|
||||
<FormattedMessage
|
||||
id='admin.team.dirTitle'
|
||||
defaultMessage='Enable Team Directory: '
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
@@ -260,7 +356,10 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={this.props.config.TeamSettings.EnableTeamListing}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'true'}
|
||||
<FormattedMessage
|
||||
id='admin.team.true'
|
||||
defaultMessage='true'
|
||||
/>
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
@@ -270,9 +369,17 @@ export default class TeamSettings extends React.Component {
|
||||
defaultChecked={!this.props.config.TeamSettings.EnableTeamListing}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
{'false'}
|
||||
<FormattedMessage
|
||||
id='admin.team.false'
|
||||
defaultMessage='false'
|
||||
/>
|
||||
</label>
|
||||
<p className='help-text'>{'When true, teams that are configured to show in team directory will show on main page inplace of creating a new team.'}</p>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.team.dirDesc'
|
||||
defaultMessage='When true, teams that are configured to show in team directory will show on main page inplace of creating a new team.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -285,9 +392,12 @@ export default class TeamSettings extends React.Component {
|
||||
className={saveClass}
|
||||
onClick={this.handleSubmit}
|
||||
id='save-button'
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
|
||||
data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + formatMessage(holders.saving)}
|
||||
>
|
||||
{'Save'}
|
||||
<FormattedMessage
|
||||
id='admin.team.save'
|
||||
defaultMessage='Save'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -299,5 +409,8 @@ export default class TeamSettings extends React.Component {
|
||||
}
|
||||
|
||||
TeamSettings.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(TeamSettings);
|
||||
@@ -6,6 +6,8 @@ import LoadingScreen from '../loading_screen.jsx';
|
||||
import UserItem from './user_item.jsx';
|
||||
import ResetPasswordModal from './reset_password_modal.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class UserList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -122,7 +124,15 @@ export default class UserList extends React.Component {
|
||||
if (this.state.users == null) {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'Users for ' + this.props.team.name}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.userList.title'
|
||||
defaultMessage='Users for {team}'
|
||||
values={{
|
||||
team: this.props.team.name
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
{serverError}
|
||||
<LoadingScreen />
|
||||
</div>
|
||||
@@ -141,7 +151,16 @@ export default class UserList extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'Users for ' + this.props.team.name + ' (' + this.state.users.length + ')'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='admin.userList.title2'
|
||||
defaultMessage='Users for {team} ({count})'
|
||||
values={{
|
||||
team: this.props.team.name,
|
||||
count: this.state.users.length
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
{serverError}
|
||||
<form
|
||||
className='form-horizontal'
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
import UserStore from '../../stores/user_store.jsx';
|
||||
import ConfirmModal from '../confirm_modal.jsx';
|
||||
import TeamStore from '../../stores/team_store.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
confirmDemoteRoleTitle: {
|
||||
id: 'admin.user_item.confirmDemoteRoleTitle',
|
||||
defaultMessage: 'Confirm demotion from System Admin role'
|
||||
},
|
||||
confirmDemotion: {
|
||||
id: 'admin.user_item.confirmDemotion',
|
||||
defaultMessage: 'Confirm Demotion'
|
||||
},
|
||||
confirmDemoteDescription: {
|
||||
id: 'admin.user_item.confirmDemoteDescription',
|
||||
defaultMessage: 'If you demote yourself from the System Admin role and there is not another user with System Admin privileges, you\'ll need to re-assign a System Admin by accessing the Mattermost server through a terminal and running the following command.'
|
||||
},
|
||||
confirmDemotionCmd: {
|
||||
id: 'admin.user_item.confirmDemotionCmd',
|
||||
defaultMessage: 'platform -assign_role -team_name="yourteam" -email="name@yourcompany.com" -role="system_admin"'
|
||||
}
|
||||
});
|
||||
|
||||
export default class UserItem extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -14,25 +38,38 @@ export default class UserItem extends React.Component {
|
||||
this.handleMakeAdmin = this.handleMakeAdmin.bind(this);
|
||||
this.handleMakeSystemAdmin = this.handleMakeSystemAdmin.bind(this);
|
||||
this.handleResetPassword = this.handleResetPassword.bind(this);
|
||||
this.handleDemote = this.handleDemote.bind(this);
|
||||
this.handleDemoteSubmit = this.handleDemoteSubmit.bind(this);
|
||||
this.handleDemoteCancel = this.handleDemoteCancel.bind(this);
|
||||
|
||||
this.state = {};
|
||||
this.state = {
|
||||
serverError: null,
|
||||
showDemoteModal: false,
|
||||
user: null,
|
||||
role: null
|
||||
};
|
||||
}
|
||||
|
||||
handleMakeMember(e) {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
user_id: this.props.user.id,
|
||||
new_roles: ''
|
||||
};
|
||||
const me = UserStore.getCurrentUser();
|
||||
if (this.props.user.id === me.id) {
|
||||
this.handleDemote(this.props.user, '');
|
||||
} else {
|
||||
const data = {
|
||||
user_id: this.props.user.id,
|
||||
new_roles: ''
|
||||
};
|
||||
|
||||
Client.updateRoles(data,
|
||||
() => {
|
||||
this.props.refreshProfiles();
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
);
|
||||
Client.updateRoles(data,
|
||||
() => {
|
||||
this.props.refreshProfiles();
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleMakeActive(e) {
|
||||
@@ -61,19 +98,24 @@ export default class UserItem extends React.Component {
|
||||
|
||||
handleMakeAdmin(e) {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
user_id: this.props.user.id,
|
||||
new_roles: 'admin'
|
||||
};
|
||||
const me = UserStore.getCurrentUser();
|
||||
if (this.props.user.id === me.id) {
|
||||
this.handleDemote(this.props.user, 'admin');
|
||||
} else {
|
||||
const data = {
|
||||
user_id: this.props.user.id,
|
||||
new_roles: 'admin'
|
||||
};
|
||||
|
||||
Client.updateRoles(data,
|
||||
() => {
|
||||
this.props.refreshProfiles();
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
);
|
||||
Client.updateRoles(data,
|
||||
() => {
|
||||
this.props.refreshProfiles();
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleMakeSystemAdmin(e) {
|
||||
@@ -98,6 +140,54 @@ export default class UserItem extends React.Component {
|
||||
this.props.doPasswordReset(this.props.user);
|
||||
}
|
||||
|
||||
handleDemote(user, role) {
|
||||
this.setState({
|
||||
serverError: this.state.serverError,
|
||||
showDemoteModal: true,
|
||||
user,
|
||||
role
|
||||
});
|
||||
}
|
||||
|
||||
handleDemoteCancel() {
|
||||
this.setState({
|
||||
serverError: null,
|
||||
showDemoteModal: false,
|
||||
user: null,
|
||||
role: null
|
||||
});
|
||||
}
|
||||
|
||||
handleDemoteSubmit() {
|
||||
const data = {
|
||||
user_id: this.props.user.id,
|
||||
new_roles: this.state.role
|
||||
};
|
||||
|
||||
Client.updateRoles(data,
|
||||
() => {
|
||||
this.setState({
|
||||
serverError: null,
|
||||
showDemoteModal: false,
|
||||
user: null,
|
||||
role: null
|
||||
});
|
||||
|
||||
const teamUrl = TeamStore.getCurrentTeamUrl();
|
||||
if (teamUrl) {
|
||||
window.location.href = teamUrl;
|
||||
} else {
|
||||
window.location.href = '/';
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
this.setState({
|
||||
serverError: err.message
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let serverError = null;
|
||||
if (this.state.serverError) {
|
||||
@@ -109,12 +199,27 @@ export default class UserItem extends React.Component {
|
||||
}
|
||||
|
||||
const user = this.props.user;
|
||||
let currentRoles = 'Member';
|
||||
let currentRoles = (
|
||||
<FormattedMessage
|
||||
id='admin.user_item.member'
|
||||
defaultMessage='Member'
|
||||
/>
|
||||
);
|
||||
if (user.roles.length > 0) {
|
||||
if (Utils.isSystemAdmin(user.roles)) {
|
||||
currentRoles = 'System Admin';
|
||||
currentRoles = (
|
||||
<FormattedMessage
|
||||
id='admin.user_item.sysAdmin'
|
||||
defaultMessage='System Admin'
|
||||
/>
|
||||
);
|
||||
} else if (Utils.isAdmin(user.roles)) {
|
||||
currentRoles = 'Team Admin';
|
||||
currentRoles = (
|
||||
<FormattedMessage
|
||||
id='admin.user_item.teamAdmin'
|
||||
defaultMessage='Team Admin'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1);
|
||||
}
|
||||
@@ -128,7 +233,12 @@ export default class UserItem extends React.Component {
|
||||
let showMakeNotActive = user.roles !== 'system_admin';
|
||||
|
||||
if (user.delete_at > 0) {
|
||||
currentRoles = 'Inactive';
|
||||
currentRoles = (
|
||||
<FormattedMessage
|
||||
id='admin.user_item.inactive'
|
||||
defaultMessage='Inactive'
|
||||
/>
|
||||
);
|
||||
showMakeMember = false;
|
||||
showMakeAdmin = false;
|
||||
showMakeSystemAdmin = false;
|
||||
@@ -145,7 +255,10 @@ export default class UserItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeSystemAdmin}
|
||||
>
|
||||
{'Make System Admin'}
|
||||
<FormattedMessage
|
||||
id='admin.user_item.makeSysAdmin'
|
||||
defaultMessage='Make System Admin'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -160,7 +273,10 @@ export default class UserItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeAdmin}
|
||||
>
|
||||
{'Make Team Admin'}
|
||||
<FormattedMessage
|
||||
id='admin.user_item.makeTeamAdmin'
|
||||
defaultMessage='Make Team Admin'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -175,7 +291,10 @@ export default class UserItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeMember}
|
||||
>
|
||||
{'Make Member'}
|
||||
<FormattedMessage
|
||||
id='admin.user_item.makeMember'
|
||||
defaultMessage='Make Member'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -190,7 +309,10 @@ export default class UserItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeActive}
|
||||
>
|
||||
{'Make Active'}
|
||||
<FormattedMessage
|
||||
id='admin.user_item.makeActive'
|
||||
defaultMessage='Make Active'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -205,11 +327,29 @@ export default class UserItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeNotActive}
|
||||
>
|
||||
{'Make Inactive'}
|
||||
<FormattedMessage
|
||||
id='admin.user_item.makeInactive'
|
||||
defaultMessage='Make Inactive'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
const me = UserStore.getCurrentUser();
|
||||
const {formatMessage} = this.props.intl;
|
||||
let makeDemoteModal = null;
|
||||
if (this.props.user.id === me.id) {
|
||||
makeDemoteModal = (
|
||||
<ConfirmModal
|
||||
show={this.state.showDemoteModal}
|
||||
title={formatMessage(holders.confirmDemoteRoleTitle)}
|
||||
message={[formatMessage(holders.confirmDemoteDescription), React.createElement('br'), React.createElement('br'), formatMessage(holders.confirmDemotionCmd), serverError]}
|
||||
confirm_button={formatMessage(holders.confirmDemotion)}
|
||||
onConfirm={this.handleDemoteSubmit}
|
||||
onCancel={this.handleDemoteCancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<tr>
|
||||
@@ -248,11 +388,15 @@ export default class UserItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleResetPassword}
|
||||
>
|
||||
{'Reset Password'}
|
||||
<FormattedMessage
|
||||
id='admin.user_item.resetPwd'
|
||||
defaultMessage='Reset Password'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{makeDemoteModal}
|
||||
{serverError}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -261,7 +405,10 @@ export default class UserItem extends React.Component {
|
||||
}
|
||||
|
||||
UserItem.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
user: React.PropTypes.object.isRequired,
|
||||
refreshProfiles: React.PropTypes.func.isRequired,
|
||||
doPasswordReset: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(UserItem);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
export default class Authorize extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -33,28 +35,67 @@ export default class Authorize extends React.Component {
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className='authorize-box'>
|
||||
<div className='authorize-inner'>
|
||||
<h3>{'An application would like to connect to your '}{this.props.teamName}{' account'}</h3>
|
||||
<label>{'The app '}{this.props.appName}{' would like the ability to access and modify your basic information.'}</label>
|
||||
<br/>
|
||||
<br/>
|
||||
<label>{'Allow '}{this.props.appName}{' access?'}</label>
|
||||
<br/>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn authorize-btn'
|
||||
onClick={this.handleDeny}
|
||||
>
|
||||
{'Deny'}
|
||||
</button>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary authorize-btn'
|
||||
onClick={this.handleAllow}
|
||||
>
|
||||
{'Allow'}
|
||||
</button>
|
||||
<div className='container-fluid'>
|
||||
<div className='oauth-prompt'>
|
||||
<div className='prompt__heading'>
|
||||
<div className='prompt__app-icon'>
|
||||
<img
|
||||
src='/static/images/icon50x50.png'
|
||||
width='50'
|
||||
height='50'
|
||||
alt=''
|
||||
/>
|
||||
</div>
|
||||
<div className='text'>
|
||||
<FormattedMessage
|
||||
id='authorize.title'
|
||||
defaultMessage='An application would like to connect to your {teamName} account'
|
||||
values={{
|
||||
teamName: this.props.teamName
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<FormattedHTMLMessage
|
||||
id='authorize.app'
|
||||
defaultMessage='The app <strong>{appName}</strong> would like the ability to access and modify your basic information.'
|
||||
values={{
|
||||
appName: this.props.appName
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<h2 className='prompt__allow'>
|
||||
<FormattedHTMLMessage
|
||||
id='authorize.access'
|
||||
defaultMessage='Allow <strong>{appName}</strong> access?'
|
||||
values={{
|
||||
appName: this.props.appName
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
<div className='prompt__buttons'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn authorize-btn'
|
||||
onClick={this.handleDeny}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='authorize.deny'
|
||||
defaultMessage='Deny'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary authorize-btn'
|
||||
onClick={this.handleAllow}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='authorize.allow'
|
||||
defaultMessage='Allow'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -66,11 +66,9 @@ export default class CenterPanel extends React.Component {
|
||||
createPost = (
|
||||
<div
|
||||
id='archive-link-home'
|
||||
onClick={handleClick}
|
||||
>
|
||||
<a
|
||||
href=''
|
||||
onClick={handleClick}
|
||||
>
|
||||
<a href=''>
|
||||
{'You are viewing the Archives. Click here to jump to recent messages. '}
|
||||
{<i className='fa fa-arrow-down'></i>}
|
||||
</a>
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
var Modal = ReactBootstrap.Modal;
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class ChangeUrlModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -39,21 +41,58 @@ export default class ChangeUrlModal extends React.Component {
|
||||
getURLError(url) {
|
||||
let error = []; //eslint-disable-line prefer-const
|
||||
if (url.length < 2) {
|
||||
error.push(<span key='error1'>{'Must be longer than two characters'}<br/></span>);
|
||||
error.push(
|
||||
<span key='error1'>
|
||||
<FormattedMessage
|
||||
id='change_url.longer'
|
||||
defaultMessage='Must be longer than two characters'
|
||||
/>
|
||||
<br/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (url.charAt(0) === '-' || url.charAt(0) === '_') {
|
||||
error.push(<span key='error2'>{'Must start with a letter or number'}<br/></span>);
|
||||
error.push(
|
||||
<span key='error2'>
|
||||
<FormattedMessage
|
||||
id='change_url.startWithLetter'
|
||||
defaultMessage='Must start with a letter or number'
|
||||
/>
|
||||
<br/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (url.length > 1 && (url.charAt(url.length - 1) === '-' || url.charAt(url.length - 1) === '_')) {
|
||||
error.push(<span key='error3'>{'Must end with a letter or number'}<br/></span>);
|
||||
error.push(
|
||||
<span key='error3'>
|
||||
<FormattedMessage
|
||||
id='change_url.endWithLetter'
|
||||
defaultMessage='Must end with a letter or number'
|
||||
/>
|
||||
<br/>
|
||||
</span>);
|
||||
}
|
||||
if (url.indexOf('__') > -1) {
|
||||
error.push(<span key='error4'>{'Can not contain two underscores in a row.'}<br/></span>);
|
||||
error.push(
|
||||
<span key='error4'>
|
||||
<FormattedMessage
|
||||
id='change_url.noUnderscore'
|
||||
defaultMessage='Can not contain two underscores in a row.'
|
||||
/>
|
||||
<br/>
|
||||
</span>);
|
||||
}
|
||||
|
||||
// In case of error we don't detect
|
||||
if (error.length === 0) {
|
||||
error.push(<span key='errorlast'>{'Invalid URL'}<br/></span>);
|
||||
error.push(
|
||||
<span key='errorlast'>
|
||||
<FormattedMessage
|
||||
id='change_url.invalidUrl'
|
||||
defaultMessage='Invalid URL'
|
||||
/>
|
||||
<br/>
|
||||
</span>);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@@ -137,7 +176,10 @@ export default class ChangeUrlModal extends React.Component {
|
||||
className='btn btn-default'
|
||||
onClick={this.doCancel}
|
||||
>
|
||||
{'Close'}
|
||||
<FormattedMessage
|
||||
id='change_url.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
onClick={this.doSubmit}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
import EmailToSSO from './email_to_sso.jsx';
|
||||
import SSOToEmail from './sso_to_email.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class ClaimAccount extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -13,7 +15,14 @@ export default class ClaimAccount extends React.Component {
|
||||
render() {
|
||||
let content;
|
||||
if (this.props.email === '') {
|
||||
content = <p>{'No email specified.'}</p>;
|
||||
content = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='claim.account.noEmail'
|
||||
defaultMessage='No email specified'
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
} else if (this.props.currentType === '' && this.props.newType !== '') {
|
||||
content = (
|
||||
<EmailToSSO
|
||||
|
||||
@@ -4,7 +4,20 @@
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
|
||||
export default class EmailToSSO extends React.Component {
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
pwdError: {
|
||||
id: 'claim.email_to_sso.pwdError',
|
||||
defaultMessage: 'Please enter your password.'
|
||||
},
|
||||
pwd: {
|
||||
id: 'claim.email_to_sso.pwd',
|
||||
defaultMessage: 'Password'
|
||||
}
|
||||
});
|
||||
|
||||
class EmailToSSO extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -18,7 +31,7 @@ export default class EmailToSSO extends React.Component {
|
||||
|
||||
var password = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
if (!password) {
|
||||
state.error = 'Please enter your password.';
|
||||
state.error = this.props.intl.formatMessage(holders.pwdError);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -59,17 +72,42 @@ export default class EmailToSSO extends React.Component {
|
||||
return (
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>{'Switch Email/Password Account to ' + uiType}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='claim.email_to_sso.title'
|
||||
defaultMessage='Switch Email/Password Account to {uiType}'
|
||||
values={{
|
||||
uiType: uiType
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
<form onSubmit={this.submit}>
|
||||
<p>{'Upon claiming your account, you will only be able to login with ' + Utils.toTitleCase(this.props.type) + ' SSO.'}</p>
|
||||
<p>{'Enter the password for your ' + this.props.teamDisplayName + ' ' + global.window.mm_config.SiteName + ' account.'}</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='claim.email_to_sso.ssoType'
|
||||
defaultMessage='Upon claiming your account, you will only be able to login with {type} SSO'
|
||||
values={{
|
||||
type: Utils.toTitleCase(this.props.type)
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='claim.email_to_sso.enterPwd'
|
||||
defaultMessage='Enter the password for your {team} {site} account'
|
||||
values={{
|
||||
team: this.props.teamDisplayName,
|
||||
site: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<div className={formClass}>
|
||||
<input
|
||||
type='password'
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder='Password'
|
||||
placeholder={this.props.intl.formatMessage(holders.pwd)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -78,7 +116,13 @@ export default class EmailToSSO extends React.Component {
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
{'Switch account to ' + uiType}
|
||||
<FormattedMessage
|
||||
id='claim.email_to_sso.switchTo'
|
||||
defaultMessage='Switch account to {uiType}'
|
||||
values={{
|
||||
uiType: uiType
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -90,8 +134,11 @@ export default class EmailToSSO extends React.Component {
|
||||
EmailToSSO.defaultProps = {
|
||||
};
|
||||
EmailToSSO.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
type: React.PropTypes.string.isRequired,
|
||||
email: React.PropTypes.string.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired,
|
||||
teamDisplayName: React.PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(EmailToSSO);
|
||||
@@ -4,7 +4,28 @@
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
|
||||
export default class SSOToEmail extends React.Component {
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
enterPwd: {
|
||||
id: 'claim.sso_to_email.enterPwd',
|
||||
defaultMessage: 'Please enter a password.'
|
||||
},
|
||||
pwdNotMatch: {
|
||||
id: 'claim.sso_to_email.pwdNotMatch',
|
||||
defaultMessage: 'Password do not match.'
|
||||
},
|
||||
newPwd: {
|
||||
id: 'claim.sso_to_email.newPwd',
|
||||
defaultMessage: 'New Password'
|
||||
},
|
||||
confirm: {
|
||||
id: 'claim.sso_to_email.confirm',
|
||||
defaultMessage: 'Confirm Password'
|
||||
}
|
||||
});
|
||||
|
||||
class SSOToEmail extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -13,19 +34,20 @@ export default class SSOToEmail extends React.Component {
|
||||
this.state = {};
|
||||
}
|
||||
submit(e) {
|
||||
const {formatMessage} = this.props.intl;
|
||||
e.preventDefault();
|
||||
const state = {};
|
||||
|
||||
const password = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
if (!password) {
|
||||
state.error = 'Please enter a password.';
|
||||
state.error = formatMessage(holders.enterPwd);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmPassword = ReactDOM.findDOMNode(this.refs.passwordconfirm).value.trim();
|
||||
if (!confirmPassword || password !== confirmPassword) {
|
||||
state.error = 'Passwords do not match.';
|
||||
state.error = formatMessage(holders.pwdNotMatch);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -50,6 +72,7 @@ export default class SSOToEmail extends React.Component {
|
||||
);
|
||||
}
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var error = null;
|
||||
if (this.state.error) {
|
||||
error = <div className='form-group has-error'><label className='control-label'>{this.state.error}</label></div>;
|
||||
@@ -65,17 +88,39 @@ export default class SSOToEmail extends React.Component {
|
||||
return (
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>{'Switch ' + uiType + ' Account to Email'}</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='claim.sso_to_email.title'
|
||||
defaultMessage='Switch {type} Account to Email'
|
||||
values={{
|
||||
type: uiType
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
<form onSubmit={this.submit}>
|
||||
<p>{'Upon changing your account type, you will only be able to login with your email and password.'}</p>
|
||||
<p>{'Enter a new password for your ' + this.props.teamDisplayName + ' ' + global.window.mm_config.SiteName + ' account.'}</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='claim.sso_to_email.description'
|
||||
defaultMessage='Upon changing your account type, you will only be able to login with your email and password.'
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='claim.sso_to_email_newPwd'
|
||||
defaultMessage='Enter a new password for your {team} {site} account'
|
||||
values={{
|
||||
team: this.props.teamDisplayName,
|
||||
site: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<div className={formClass}>
|
||||
<input
|
||||
type='password'
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder='New Password'
|
||||
placeholder={formatMessage(holders.newPwd)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -85,7 +130,7 @@ export default class SSOToEmail extends React.Component {
|
||||
className='form-control'
|
||||
name='passwordconfirm'
|
||||
ref='passwordconfirm'
|
||||
placeholder='Confirm Password'
|
||||
placeholder={formatMessage(holders.confirm)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -94,7 +139,13 @@ export default class SSOToEmail extends React.Component {
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
{'Switch ' + uiType + ' account to email and password'}
|
||||
<FormattedMessage
|
||||
id='claim.sso_to_email.switchTo'
|
||||
defaultMessage='Switch {type} to email and password'
|
||||
values={{
|
||||
type: uiType
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -106,8 +157,11 @@ export default class SSOToEmail extends React.Component {
|
||||
SSOToEmail.defaultProps = {
|
||||
};
|
||||
SSOToEmail.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
currentType: React.PropTypes.string.isRequired,
|
||||
email: React.PropTypes.string.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired,
|
||||
teamDisplayName: React.PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(SSOToEmail);
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
const Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class ConfirmModal extends React.Component {
|
||||
@@ -33,7 +34,10 @@ export default class ConfirmModal extends React.Component {
|
||||
className='btn btn-default'
|
||||
onClick={this.props.onCancel}
|
||||
>
|
||||
{'Cancel'}
|
||||
<FormattedMessage
|
||||
id='confirm_modal.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
type='button'
|
||||
|
||||
@@ -16,10 +16,32 @@ import FilePreview from './file_preview.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
const KeyCodes = Constants.KeyCodes;
|
||||
|
||||
export default class CreateComment extends React.Component {
|
||||
const holders = defineMessages({
|
||||
commentLength: {
|
||||
id: 'create_comment.commentLength',
|
||||
defaultMessage: 'Comment length must be less than {max} characters.'
|
||||
},
|
||||
comment: {
|
||||
id: 'create_comment.comment',
|
||||
defaultMessage: 'Add Comment'
|
||||
},
|
||||
addComment: {
|
||||
id: 'create_comment.addComment',
|
||||
defaultMessage: 'Add a comment...'
|
||||
},
|
||||
commentTitle: {
|
||||
id: 'create_comment.commentTitle',
|
||||
defaultMessage: 'Comment'
|
||||
}
|
||||
});
|
||||
|
||||
class CreateComment extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -93,7 +115,7 @@ export default class CreateComment extends React.Component {
|
||||
}
|
||||
|
||||
if (post.message.length > Constants.CHARACTER_LIMIT) {
|
||||
this.setState({postError: `Comment length must be less than ${Constants.CHARACTER_LIMIT} characters.`});
|
||||
this.setState({postError: this.props.intl.formatMessage(holders.commentLength, {max: Constants.CHARACTER_LIMIT})});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -189,7 +211,7 @@ export default class CreateComment extends React.Component {
|
||||
AppDispatcher.handleViewAction({
|
||||
type: ActionTypes.RECIEVED_EDIT_POST,
|
||||
refocusId: '#reply_textbox',
|
||||
title: 'Comment',
|
||||
title: this.props.intl.formatMessage(holders.commentTitle),
|
||||
message: lastPost.message,
|
||||
postId: lastPost.id,
|
||||
channelId: lastPost.channel_id,
|
||||
@@ -305,14 +327,23 @@ export default class CreateComment extends React.Component {
|
||||
let uploadsInProgressText = null;
|
||||
if (this.state.uploadsInProgress.length > 0) {
|
||||
uploadsInProgressText = (
|
||||
<span
|
||||
className='pull-right post-right-comments-upload-in-progress'
|
||||
>
|
||||
{this.state.uploadsInProgress.length === 1 ? 'File uploading' : 'Files uploading'}
|
||||
<span className='pull-right post-right-comments-upload-in-progress'>
|
||||
{this.state.uploadsInProgress.length === 1 ? (
|
||||
<FormattedMessage
|
||||
id='create_comment.file'
|
||||
defaultMessage='File uploading'
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='create_comment.files'
|
||||
defaultMessage='Files uploading'
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='post-create'>
|
||||
@@ -326,7 +357,7 @@ export default class CreateComment extends React.Component {
|
||||
onKeyPress={this.commentMsgKeyPress}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
messageText={this.state.messageText}
|
||||
createMessage='Add a comment...'
|
||||
createMessage={formatMessage(holders.addComment)}
|
||||
initialText=''
|
||||
supportsCommands={false}
|
||||
id='reply_textbox'
|
||||
@@ -351,7 +382,7 @@ export default class CreateComment extends React.Component {
|
||||
<input
|
||||
type='button'
|
||||
className='btn btn-primary comment-btn pull-right'
|
||||
value='Add Comment'
|
||||
value={formatMessage(holders.comment)}
|
||||
onClick={this.handleSubmit}
|
||||
/>
|
||||
{uploadsInProgressText}
|
||||
@@ -366,6 +397,9 @@ export default class CreateComment extends React.Component {
|
||||
}
|
||||
|
||||
CreateComment.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
channelId: React.PropTypes.string.isRequired,
|
||||
rootId: React.PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(CreateComment);
|
||||
@@ -13,7 +13,7 @@ export default class Docs extends React.Component {
|
||||
const errorState = {text: '## 404'};
|
||||
|
||||
if (props.site) {
|
||||
$.get('/static/help/' + props.site + '.md').then((response) => {
|
||||
$.get(`/static/help/${props.site}_${global.window.mm_locale}.md`).then((response) => {
|
||||
this.setState({text: response});
|
||||
}, () => {
|
||||
this.setState(errorState);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
export default class EmailVerify extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -19,21 +21,61 @@ export default class EmailVerify extends React.Component {
|
||||
var resend = '';
|
||||
var resendConfirm = '';
|
||||
if (this.props.isVerified === 'true') {
|
||||
title = global.window.mm_config.SiteName + ' Email Verified';
|
||||
body = <p>Your email has been verified! Click <a href={this.props.teamURL + '?email=' + this.props.userEmail}>here</a> to log in.</p>;
|
||||
title = (
|
||||
<FormattedMessage
|
||||
id='email_verify.verified'
|
||||
defaultMessage='{siteName} Email Verified'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
);
|
||||
body = (
|
||||
<FormattedHTMLMessage
|
||||
id='email_verify.verifiedBody'
|
||||
defaultMessage='<p>Your email has been verified! Click <a href={url}>here</a> to log in.</p>'
|
||||
values={{
|
||||
url: this.props.teamURL + '?email=' + this.props.userEmail
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
title = global.window.mm_config.SiteName + ': You are almost done';
|
||||
body = <p>Please verify your email address. Check your inbox for an email.</p>;
|
||||
title = (
|
||||
<FormattedMessage
|
||||
id='email_verify.almost'
|
||||
defaultMessage='{siteName}: You are almost done'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
);
|
||||
body = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='email_verify.notVerifiedBody'
|
||||
defaultMessage='Please verify your email address. Check your inbox for an email.'
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
resend = (
|
||||
<button
|
||||
onClick={this.handleResend}
|
||||
className='btn btn-primary'
|
||||
>
|
||||
Resend Email
|
||||
<FormattedMessage
|
||||
id='email_verify.resend'
|
||||
defaultMessage='Resend Email'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
if (this.props.resendSuccess) {
|
||||
resendConfirm = <div><br /><p className='alert alert-success'><i className='fa fa-check'></i>{' Verification email sent.'}</p></div>;
|
||||
resendConfirm = (
|
||||
<div><br /><p className='alert alert-success'><i className='fa fa-check'></i>
|
||||
<FormattedMessage
|
||||
id='email_verify.sent'
|
||||
defaultMessage=' Verification email sent.'
|
||||
/>
|
||||
</p></div>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
|
||||
import ErrorStore from '../stores/error_store.jsx';
|
||||
|
||||
// import mm-intl is required for the tool to be able to extract the messages
|
||||
import {defineMessages} from 'mm-intl';
|
||||
|
||||
var messages = defineMessages({
|
||||
preview: {
|
||||
id: 'error_bar.preview_mode',
|
||||
defaultMessage: 'Preview Mode: Email notifications have not been configured'
|
||||
}
|
||||
});
|
||||
|
||||
export default class ErrorBar extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
@@ -13,6 +23,12 @@ export default class ErrorBar extends React.Component {
|
||||
this.state = ErrorStore.getLastError();
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
intl: ReactIntl.intlShape.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
isValidError(s) {
|
||||
if (!s) {
|
||||
return false;
|
||||
@@ -41,6 +57,13 @@ export default class ErrorBar extends React.Component {
|
||||
return false;
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
if (global.window.mm_config.SendEmailNotifications === 'false') {
|
||||
ErrorStore.storeLastError({message: this.props.intl.formatMessage(messages.preview)});
|
||||
this.onErrorChange();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
ErrorStore.addChangeListener(this.onErrorChange);
|
||||
}
|
||||
@@ -64,6 +87,7 @@ export default class ErrorBar extends React.Component {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
ErrorStore.clearLastError();
|
||||
this.setState({message: null});
|
||||
}
|
||||
|
||||
@@ -86,3 +110,5 @@ export default class ErrorBar extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ReactIntl.injectIntl(ErrorBar);
|
||||
|
||||
@@ -6,7 +6,28 @@ import Constants from '../utils/constants.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
export default class FileUpload extends React.Component {
|
||||
import {intlShape, injectIntl, defineMessages} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
limited: {
|
||||
id: 'file_upload.limited',
|
||||
defaultMessage: 'Uploads limited to {count} files maximum. Please use additional posts for more files.'
|
||||
},
|
||||
filesAbove: {
|
||||
id: 'file_upload.filesAbove',
|
||||
defaultMessage: 'Files above {max}MB could not be uploaded: {filenames}'
|
||||
},
|
||||
fileAbove: {
|
||||
id: 'file_upload.fileAbove',
|
||||
defaultMessage: 'File above {max}MB could not be uploaded: {filename}'
|
||||
},
|
||||
pasted: {
|
||||
id: 'file_upload.pasted',
|
||||
defaultMessage: 'Image Pasted at '
|
||||
}
|
||||
});
|
||||
|
||||
class FileUpload extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -74,14 +95,15 @@ export default class FileUpload extends React.Component {
|
||||
numUploads += 1;
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
if (files.length > uploadsRemaining) {
|
||||
this.props.onUploadError(`Uploads limited to ${Constants.MAX_UPLOAD_FILES} files maximum. Please use additional posts for more files.`);
|
||||
this.props.onUploadError(formatMessage(holders.limited, {count: Constants.MAX_UPLOAD_FILES}));
|
||||
} else if (tooLargeFiles.length > 1) {
|
||||
var tooLargeFilenames = tooLargeFiles.map((file) => file.name).join(', ');
|
||||
|
||||
this.props.onUploadError(`Files above ${Constants.MAX_FILE_SIZE / 1000000}MB could not be uploaded: ${tooLargeFilenames}`);
|
||||
this.props.onUploadError(formatMessage(holders.filesAbove, {max: (Constants.MAX_FILE_SIZE / 1000000), files: tooLargeFilenames}));
|
||||
} else if (tooLargeFiles.length > 0) {
|
||||
this.props.onUploadError(`File above ${Constants.MAX_FILE_SIZE / 1000000}MB could not be uploaded: ${tooLargeFiles[0].name}`);
|
||||
this.props.onUploadError(formatMessage(holders.fileAbove, {max: (Constants.MAX_FILE_SIZE / 1000000), file: tooLargeFiles[0].name}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +128,7 @@ export default class FileUpload extends React.Component {
|
||||
componentDidMount() {
|
||||
var inputDiv = ReactDOM.findDOMNode(this.refs.input);
|
||||
var self = this;
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
if (this.props.postType === 'post') {
|
||||
$('.row.main').dragster({
|
||||
@@ -184,7 +207,7 @@ export default class FileUpload extends React.Component {
|
||||
var numToUpload = Math.min(Constants.MAX_UPLOAD_FILES - self.props.getFileCount(ChannelStore.getCurrentId()), numItems);
|
||||
|
||||
if (numItems > numToUpload) {
|
||||
self.props.onUploadError('Uploads limited to ' + Constants.MAX_UPLOAD_FILES + ' files maximum. Please use additional posts for more files.');
|
||||
self.props.onUploadError(formatMessage(holders.limited, {count: Constants.MAX_UPLOAD_FILES}));
|
||||
}
|
||||
|
||||
for (var i = 0; i < items.length && i < numToUpload; i++) {
|
||||
@@ -218,7 +241,7 @@ export default class FileUpload extends React.Component {
|
||||
min = String(d.getMinutes());
|
||||
}
|
||||
|
||||
var name = 'Image Pasted at ' + d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate() + ' ' + hour + '-' + min + '.' + ext;
|
||||
var name = formatMessage(holders.pasted) + d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate() + ' ' + hour + '-' + min + '.' + ext;
|
||||
formData.append('files', file, name);
|
||||
formData.append('client_ids', clientId);
|
||||
|
||||
@@ -296,6 +319,7 @@ export default class FileUpload extends React.Component {
|
||||
}
|
||||
|
||||
FileUpload.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
onUploadError: React.PropTypes.func,
|
||||
getFileCount: React.PropTypes.func,
|
||||
onFileUpload: React.PropTypes.func,
|
||||
@@ -304,3 +328,5 @@ FileUpload.propTypes = {
|
||||
channelId: React.PropTypes.string,
|
||||
postType: React.PropTypes.string
|
||||
};
|
||||
|
||||
export default injectIntl(FileUpload);
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class FileUploadOverlay extends React.Component {
|
||||
render() {
|
||||
var overlayClass = 'file-overlay hidden';
|
||||
@@ -19,7 +21,12 @@ export default class FileUploadOverlay extends React.Component {
|
||||
src='/static/images/filesOverlay.png'
|
||||
alt='Files'
|
||||
/>
|
||||
<span><i className='fa fa-upload'></i>{'Drop a file to upload it.'}</span>
|
||||
<span><i className='fa fa-upload'></i>
|
||||
<FormattedMessage
|
||||
id='upload_overlay.info'
|
||||
defaultMessage='Drop a file to upload it.'
|
||||
/>
|
||||
</span>
|
||||
<img
|
||||
className='overlay__logo'
|
||||
src='/static/images/logoWhite.png'
|
||||
|
||||
@@ -4,7 +4,20 @@
|
||||
import * as utils from '../utils/utils.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
|
||||
export default class FindTeam extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
submitError: {
|
||||
id: 'find_team.submitError',
|
||||
defaultMessage: 'Please enter a valid email address'
|
||||
},
|
||||
placeholder: {
|
||||
id: 'find_team.placeholder',
|
||||
defaultMessage: 'you@domain.com'
|
||||
}
|
||||
});
|
||||
|
||||
class FindTeam extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
@@ -19,7 +32,7 @@ export default class FindTeam extends React.Component {
|
||||
|
||||
var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
|
||||
if (!email || !utils.isEmail(email)) {
|
||||
state.email_error = 'Please enter a valid email address';
|
||||
state.email_error = this.props.intl.formatMessage(holders.submitError);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -50,25 +63,50 @@ export default class FindTeam extends React.Component {
|
||||
if (this.state.sent) {
|
||||
return (
|
||||
<div>
|
||||
<h4>{'Find Your teams'}</h4>
|
||||
<p>{'An email was sent with links to any teams to which you are a member.'}</p>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id='find_team.findTitle'
|
||||
defaultMessage='Find Your Team'
|
||||
/>
|
||||
</h4>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='find_team.findDescription'
|
||||
defaultMessage='An email was sent with links to any teams to which you are a member.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h4>Find Your Team</h4>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id='find_team.findTitle'
|
||||
defaultMessage='Find Your Team'
|
||||
/>
|
||||
</h4>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<p>{'Get an email with links to any teams to which you are a member.'}</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='find_team.getLinks'
|
||||
defaultMessage='Get an email with links to any teams to which you are a member.'
|
||||
/>
|
||||
</p>
|
||||
<div className='form-group'>
|
||||
<label className='control-label'>Email</label>
|
||||
<label className='control-label'>
|
||||
<FormattedMessage
|
||||
id='find_team.email'
|
||||
defaultMessage='Email'
|
||||
/>
|
||||
</label>
|
||||
<div className={emailErrorClass}>
|
||||
<input
|
||||
type='text'
|
||||
ref='email'
|
||||
className='form-control'
|
||||
placeholder='you@domain.com'
|
||||
placeholder={this.props.intl.formatMessage(holders.placeholder)}
|
||||
maxLength='128'
|
||||
spellCheck='false'
|
||||
/>
|
||||
@@ -79,10 +117,19 @@ export default class FindTeam extends React.Component {
|
||||
className='btn btn-md btn-primary'
|
||||
type='submit'
|
||||
>
|
||||
Send
|
||||
<FormattedMessage
|
||||
id='find_team.send'
|
||||
defaultMessage='Send'
|
||||
/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FindTeam.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(FindTeam);
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
const Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class GetLinkModal extends React.Component {
|
||||
@@ -59,14 +61,25 @@ export default class GetLinkModal extends React.Component {
|
||||
className='btn btn-primary pull-left'
|
||||
onClick={this.copyLink}
|
||||
>
|
||||
{'Copy Link'}
|
||||
<FormattedMessage
|
||||
id='get_link.copy'
|
||||
defaultMessage='Copy Link'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
var copyLinkConfirm = null;
|
||||
if (this.state.copiedLink) {
|
||||
copyLinkConfirm = <p className='alert alert-success copy-link-confirm'><i className='fa fa-check'></i>{' Link copied to clipboard.'}</p>;
|
||||
copyLinkConfirm = (
|
||||
<p className='alert alert-success copy-link-confirm'>
|
||||
<i className='fa fa-check'></i>
|
||||
<FormattedMessage
|
||||
id='get_link.clipboard'
|
||||
defaultMessage=' Link copied to clipboard.'
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -92,7 +105,10 @@ export default class GetLinkModal extends React.Component {
|
||||
className='btn btn-default'
|
||||
onClick={this.onHide}
|
||||
>
|
||||
{'Close'}
|
||||
<FormattedMessage
|
||||
id='get_link.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</button>
|
||||
{copyLink}
|
||||
{copyLinkConfirm}
|
||||
|
||||
@@ -6,7 +6,20 @@ import GetLinkModal from './get_link_modal.jsx';
|
||||
import ModalStore from '../stores/modal_store.jsx';
|
||||
import TeamStore from '../stores/team_store.jsx';
|
||||
|
||||
export default class GetTeamInviteLinkModal extends React.Component {
|
||||
import {intlShape, injectIntl, defineMessages} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
title: {
|
||||
id: 'get_team_invite_link_modal.title',
|
||||
defaultMessage: 'Team Invite Link'
|
||||
},
|
||||
help: {
|
||||
id: 'get_team_invite_link_modal.help',
|
||||
defaultMessage: 'Send teammates the link below for them to sign-up to this team site.'
|
||||
}
|
||||
});
|
||||
|
||||
class GetTeamInviteLinkModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -32,14 +45,22 @@ export default class GetTeamInviteLinkModal extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
return (
|
||||
<GetLinkModal
|
||||
show={this.state.show}
|
||||
onHide={() => this.setState({show: false})}
|
||||
title='Team Invite Link'
|
||||
helpText='Send teammates the link below for them to sign-up to this team site.'
|
||||
title={formatMessage(holders.title)}
|
||||
helpText={formatMessage(holders.help)}
|
||||
link={TeamStore.getCurrentInviteLink()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
GetTeamInviteLinkModal.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(GetTeamInviteLinkModal);
|
||||
@@ -12,9 +12,38 @@ import ChannelStore from '../stores/channel_store.jsx';
|
||||
import TeamStore from '../stores/team_store.jsx';
|
||||
import ConfirmModal from './confirm_modal.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
const Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class InviteMemberModal extends React.Component {
|
||||
const holders = defineMessages({
|
||||
emailError: {
|
||||
id: 'invite_member.emailError',
|
||||
defaultMessage: 'Please enter a valid email address'
|
||||
},
|
||||
firstname: {
|
||||
id: 'invite_member.firstname',
|
||||
defaultMessage: 'First name'
|
||||
},
|
||||
lastname: {
|
||||
id: 'invite_member.lastname',
|
||||
defaultMessage: 'Last name'
|
||||
},
|
||||
modalTitle: {
|
||||
id: 'invite_member.modalTitle',
|
||||
defaultMessage: 'Discard Invitations?'
|
||||
},
|
||||
modalMessage: {
|
||||
id: 'invite_member.modalMessage',
|
||||
defaultMessage: 'You have unsent invitations, are you sure you want to discard them?'
|
||||
},
|
||||
modalButton: {
|
||||
id: 'invite_member.modalButton',
|
||||
defaultMessage: 'Yes, Discard'
|
||||
}
|
||||
});
|
||||
|
||||
class InviteMemberModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -72,7 +101,7 @@ export default class InviteMemberModal extends React.Component {
|
||||
var invite = {};
|
||||
invite.email = ReactDOM.findDOMNode(this.refs['email' + index]).value.trim();
|
||||
if (!invite.email || !utils.isEmail(invite.email)) {
|
||||
emailErrors[index] = 'Please enter a valid email address';
|
||||
emailErrors[index] = this.props.intl.formatMessage(holders.emailError);
|
||||
valid = false;
|
||||
} else {
|
||||
emailErrors[index] = '';
|
||||
@@ -103,7 +132,7 @@ export default class InviteMemberModal extends React.Component {
|
||||
this.setState({isSendingEmails: false});
|
||||
},
|
||||
(err) => {
|
||||
if (err.message === 'This person is already on your team') {
|
||||
if (err.id === 'api.team.invite_members.already.app_error') {
|
||||
emailErrors[err.detailed_error] = err.message;
|
||||
this.setState({emailErrors: emailErrors});
|
||||
} else {
|
||||
@@ -199,6 +228,7 @@ export default class InviteMemberModal extends React.Component {
|
||||
|
||||
render() {
|
||||
var currentUser = UserStore.getCurrentUser();
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
if (currentUser != null) {
|
||||
var inviteSections = [];
|
||||
@@ -252,7 +282,7 @@ export default class InviteMemberModal extends React.Component {
|
||||
type='text'
|
||||
className='form-control'
|
||||
ref={'first_name' + index}
|
||||
placeholder='First name'
|
||||
placeholder={formatMessage(holders.firstname)}
|
||||
maxLength='64'
|
||||
disabled={!this.state.emailEnabled || !this.state.userCreationEnabled}
|
||||
spellCheck='false'
|
||||
@@ -266,7 +296,7 @@ export default class InviteMemberModal extends React.Component {
|
||||
type='text'
|
||||
className='form-control'
|
||||
ref={'last_name' + index}
|
||||
placeholder='Last name'
|
||||
placeholder={formatMessage(holders.lastname)}
|
||||
maxLength='64'
|
||||
disabled={!this.state.emailEnabled || !this.state.userCreationEnabled}
|
||||
spellCheck='false'
|
||||
@@ -318,20 +348,48 @@ export default class InviteMemberModal extends React.Component {
|
||||
type='button'
|
||||
className='btn btn-default'
|
||||
onClick={this.addInviteFields}
|
||||
>{'Add another'}</button>
|
||||
>
|
||||
<FormattedMessage
|
||||
id='invite_member.addAnother'
|
||||
defaultMessage='Add another'
|
||||
/>
|
||||
</button>
|
||||
<br/>
|
||||
<br/>
|
||||
<span>{'People invited automatically join the '}<strong>{defaultChannelName}</strong>{' channel.'}</span>
|
||||
<span>
|
||||
<FormattedHTMLMessage
|
||||
id='invite_member.autoJoin'
|
||||
defaultMessage='People invited automatically join the <strong>{channel}</strong> channel.'
|
||||
values={{
|
||||
channel: defaultChannelName
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
var sendButtonLabel = 'Send Invitation';
|
||||
var sendButtonLabel = (
|
||||
<FormattedMessage
|
||||
id='invite_member.send'
|
||||
defaultMessage='Send Invitation'
|
||||
/>
|
||||
);
|
||||
if (this.state.isSendingEmails) {
|
||||
sendButtonLabel = (
|
||||
<span><i className='fa fa-spinner fa-spin' />{' Sending'}</span>
|
||||
<span><i className='fa fa-spinner fa-spin' />
|
||||
<FormattedMessage
|
||||
id='invite_member.sending'
|
||||
defaultMessage=' Sending'
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
} else if (this.state.inviteIds.length > 1) {
|
||||
sendButtonLabel = 'Send Invitations';
|
||||
sendButtonLabel = (
|
||||
<FormattedMessage
|
||||
id='invite_member.send2'
|
||||
defaultMessage='Send Invitations'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
sendButton = (
|
||||
@@ -352,27 +410,46 @@ export default class InviteMemberModal extends React.Component {
|
||||
href='#'
|
||||
onClick={this.showGetTeamInviteLinkModal}
|
||||
>
|
||||
{'Team Invite Link'}
|
||||
<FormattedMessage
|
||||
id='invite_member.inviteLink'
|
||||
defaultMessage='Team Invite Link'
|
||||
/>
|
||||
</a>
|
||||
);
|
||||
|
||||
teamInviteLink = (
|
||||
<p>
|
||||
{'You can also invite people using the '}{link}{'.'}
|
||||
<FormattedMessage
|
||||
id='invite_member.teamInviteLink'
|
||||
defaultMessage='You can also invite people using the {link}.'
|
||||
values={{
|
||||
link: (link)
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
content = (
|
||||
<div>
|
||||
<p>{'Email is currently disabled for your team, and email invitations cannot be sent. Contact your system administrator to enable email and email invitations.'}</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='invite_member.content'
|
||||
defaultMessage='Email is currently disabled for your team, and email invitations cannot be sent. Contact your system administrator to enable email and email invitations.'
|
||||
/>
|
||||
</p>
|
||||
{teamInviteLink}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<div>
|
||||
<p>{'User creation has been disabled for your team. Please ask your team administrator for details.'}</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='invite_member.disabled'
|
||||
defaultMessage='User creation has been disabled for your team. Please ask your team administrator for details.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -387,7 +464,12 @@ export default class InviteMemberModal extends React.Component {
|
||||
backdrop={this.state.isSendingEmails ? 'static' : true}
|
||||
>
|
||||
<Modal.Header closeButton={!this.state.isSendingEmails}>
|
||||
<Modal.Title>{'Invite New Member'}</Modal.Title>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id='invite_member.newMember'
|
||||
defaultMessage='Invite New Member'
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body ref='modalBody'>
|
||||
<form role='form'>
|
||||
@@ -402,15 +484,18 @@ export default class InviteMemberModal extends React.Component {
|
||||
onClick={this.handleHide.bind(this, true)}
|
||||
disabled={this.state.isSendingEmails}
|
||||
>
|
||||
{'Cancel'}
|
||||
<FormattedMessage
|
||||
id='invite_member.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
</button>
|
||||
{sendButton}
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
<ConfirmModal
|
||||
title='Discard Invitations?'
|
||||
message='You have unsent invitations, are you sure you want to discard them?'
|
||||
confirm_button='Yes, Discard'
|
||||
title={formatMessage(holders.modalTitle)}
|
||||
message={formatMessage(holders.modalMessage)}
|
||||
confirm_button={formatMessage(holders.modalButton)}
|
||||
show={this.state.showConfirmModal}
|
||||
onConfirm={this.handleHide.bind(this, false)}
|
||||
onCancel={() => this.setState({showConfirmModal: false})}
|
||||
@@ -424,4 +509,7 @@ export default class InviteMemberModal extends React.Component {
|
||||
}
|
||||
|
||||
InviteMemberModal.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(InviteMemberModal);
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class LoadingScreen extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -13,7 +15,12 @@ export default class LoadingScreen extends React.Component {
|
||||
style={{position: this.props.position}}
|
||||
>
|
||||
<div className='loading__content'>
|
||||
<h3>Loading</h3>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='loading_screen.loading'
|
||||
defaultMessage='Loading'
|
||||
/>
|
||||
</h3>
|
||||
<div className='round round-1'></div>
|
||||
<div className='round round-2'></div>
|
||||
<div className='round round-3'></div>
|
||||
|
||||
@@ -7,7 +7,7 @@ import LoginLdap from './login_ldap.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
var FormattedMessage = ReactIntl.FormattedMessage;
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class Login extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -24,10 +24,16 @@ export default class Login extends React.Component {
|
||||
loginMessage.push(
|
||||
<a
|
||||
className='btn btn-custom-login gitlab'
|
||||
key='gitlab'
|
||||
href={'/' + teamName + '/login/gitlab'}
|
||||
>
|
||||
<span className='icon' />
|
||||
<span>{'with GitLab'}</span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.gitlab'
|
||||
defaultMessage='with GitLab'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -36,10 +42,16 @@ export default class Login extends React.Component {
|
||||
loginMessage.push(
|
||||
<a
|
||||
className='btn btn-custom-login google'
|
||||
key='google'
|
||||
href={'/' + teamName + '/login/google'}
|
||||
>
|
||||
<span className='icon' />
|
||||
<span>{'with Google Apps'}</span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.google'
|
||||
defaultMessage='with Google Apps'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -49,9 +61,19 @@ export default class Login extends React.Component {
|
||||
if (extraParam) {
|
||||
let msg;
|
||||
if (extraParam === Constants.SIGNIN_CHANGE) {
|
||||
msg = ' Sign-in method changed successfully';
|
||||
msg = (
|
||||
<FormattedMessage
|
||||
id='login.changed'
|
||||
defaultMessage=' Sign-in method changed successfully'
|
||||
/>
|
||||
);
|
||||
} else if (extraParam === Constants.SIGNIN_VERIFIED) {
|
||||
msg = ' Email Verified';
|
||||
msg = (
|
||||
<FormattedMessage
|
||||
id='login.verified'
|
||||
defaultMessage=' Email Verified'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
@@ -78,7 +100,12 @@ export default class Login extends React.Component {
|
||||
<div>
|
||||
{loginMessage}
|
||||
<div className='or__container'>
|
||||
<span>{'or'}</span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -90,7 +117,7 @@ export default class Login extends React.Component {
|
||||
<div className='form-group'>
|
||||
<a href={'/' + teamName + '/reset_password'}>
|
||||
<FormattedMessage
|
||||
id='login.forgot_password'
|
||||
id='login.forgot'
|
||||
defaultMessage='I forgot my password'
|
||||
/>
|
||||
</a>
|
||||
@@ -102,12 +129,19 @@ export default class Login extends React.Component {
|
||||
if (this.props.inviteId) {
|
||||
userSignUp = (
|
||||
<div>
|
||||
<span>{`Don't have an account? `}
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.noAccount'
|
||||
defaultMessage="Don't have an account? "
|
||||
/>
|
||||
<a
|
||||
href={'/signup_user_complete/?id=' + this.props.inviteId}
|
||||
className='signup-team-login'
|
||||
>
|
||||
{'Create one now'}
|
||||
<FormattedMessage
|
||||
id='login.create'
|
||||
defaultMessage='Create one now'
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
@@ -115,14 +149,17 @@ export default class Login extends React.Component {
|
||||
}
|
||||
|
||||
let teamSignUp = null;
|
||||
if (global.window.mm_config.EnableTeamCreation === 'true') {
|
||||
if (global.window.mm_config.EnableTeamCreation === 'true' && !Utils.isMobileApp()) {
|
||||
teamSignUp = (
|
||||
<div className='margin--extra'>
|
||||
<a
|
||||
href='/'
|
||||
className='signup-team-login'
|
||||
>
|
||||
{'Create a new team'}
|
||||
<FormattedMessage
|
||||
id='login.createTeam'
|
||||
defaultMessage='Create a new team'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
@@ -137,25 +174,45 @@ export default class Login extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let findTeams = null;
|
||||
if (!Utils.isMobileApp()) {
|
||||
findTeams = (
|
||||
<div className='form-group margin--extra form-group--small'>
|
||||
<span>
|
||||
<a href='/find_team'>
|
||||
<FormattedMessage
|
||||
id='login.find'
|
||||
defaultMessage='Find your other teams'
|
||||
/>
|
||||
</a></span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='signup-team__container'>
|
||||
<h5 className='margin--less'>{'Sign in to:'}</h5>
|
||||
<h5 className='margin--less'>
|
||||
<FormattedMessage
|
||||
id='login.signTo'
|
||||
defaultMessage='Sign in to:'
|
||||
/>
|
||||
</h5>
|
||||
<h2 className='signup-team__name'>{teamDisplayName}</h2>
|
||||
<h2 className='signup-team__subdomain'>{'on '}{global.window.mm_config.SiteName}</h2>
|
||||
<h2 className='signup-team__subdomain'>
|
||||
<FormattedMessage
|
||||
id='login.on'
|
||||
defaultMessage='on {siteName}'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
{extraBox}
|
||||
{loginMessage}
|
||||
{emailSignup}
|
||||
{ldapLogin}
|
||||
{userSignUp}
|
||||
<div className='form-group margin--extra form-group--small'>
|
||||
<span>
|
||||
<a href='/find_team'>
|
||||
<FormattedMessage
|
||||
id='login.find_teams'
|
||||
defaultMessage='Find your other teams'
|
||||
/>
|
||||
</a></span>
|
||||
</div>
|
||||
{findTeams}
|
||||
{forgotPassword}
|
||||
{teamSignUp}
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,32 @@ import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
|
||||
export default class LoginEmail extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
badTeam: {
|
||||
id: 'login_email.badTeam',
|
||||
defaultMessage: 'Bad team name'
|
||||
},
|
||||
emailReq: {
|
||||
id: 'login_email.emailReq',
|
||||
defaultMessage: 'An email is required'
|
||||
},
|
||||
pwdReq: {
|
||||
id: 'login_email.pwdReq',
|
||||
defaultMessage: 'A password is required'
|
||||
},
|
||||
email: {
|
||||
id: 'login_email.email',
|
||||
defaultMessage: 'Email'
|
||||
},
|
||||
pwd: {
|
||||
id: 'login_email.pwd',
|
||||
defaultMessage: 'Password'
|
||||
}
|
||||
});
|
||||
|
||||
class LoginEmail extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -17,25 +42,26 @@ export default class LoginEmail extends React.Component {
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const {formatMessage} = this.props.intl;
|
||||
var state = {};
|
||||
|
||||
const name = this.props.teamName;
|
||||
if (!name) {
|
||||
state.serverError = 'Bad team name';
|
||||
state.serverError = formatMessage(holders.badTeam);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const email = this.refs.email.value.trim();
|
||||
if (!email) {
|
||||
state.serverError = 'An email is required';
|
||||
state.serverError = formatMessage(holders.emailReq);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = 'A password is required';
|
||||
state.serverError = formatMessage(holders.pwdReq);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -55,7 +81,7 @@ export default class LoginEmail extends React.Component {
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (err.message === 'Login failed because email address has not been verified') {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
window.location.href = '/verify_email?teamname=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email);
|
||||
return;
|
||||
}
|
||||
@@ -87,6 +113,7 @@ export default class LoginEmail extends React.Component {
|
||||
priorEmail = decodeURIComponent(emailParam);
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
@@ -101,7 +128,7 @@ export default class LoginEmail extends React.Component {
|
||||
name='email'
|
||||
defaultValue={priorEmail}
|
||||
ref='email'
|
||||
placeholder='Email'
|
||||
placeholder={formatMessage(holders.email)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -112,7 +139,7 @@ export default class LoginEmail extends React.Component {
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder='Password'
|
||||
placeholder={formatMessage(holders.pwd)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -121,7 +148,10 @@ export default class LoginEmail extends React.Component {
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
{'Sign in'}
|
||||
<FormattedMessage
|
||||
id='login_email.signin'
|
||||
defaultMessage='Sign in'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -133,5 +163,8 @@ LoginEmail.defaultProps = {
|
||||
};
|
||||
|
||||
LoginEmail.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(LoginEmail);
|
||||
@@ -4,7 +4,32 @@
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
export default class LoginLdap extends React.Component {
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
badTeam: {
|
||||
id: 'login_ldap.badTeam',
|
||||
defaultMessage: 'Bad team name'
|
||||
},
|
||||
idReq: {
|
||||
id: 'login_ldap.idlReq',
|
||||
defaultMessage: 'An LDAP ID is required'
|
||||
},
|
||||
pwdReq: {
|
||||
id: 'login_ldap.pwdReq',
|
||||
defaultMessage: 'An LDAP password is required'
|
||||
},
|
||||
username: {
|
||||
id: 'login_ldap.username',
|
||||
defaultMessage: 'LDAP Username'
|
||||
},
|
||||
pwd: {
|
||||
id: 'login_ldap.pwd',
|
||||
defaultMessage: 'LDAP Password'
|
||||
}
|
||||
});
|
||||
|
||||
class LoginLdap extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -16,25 +41,26 @@ export default class LoginLdap extends React.Component {
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const {formatMessage} = this.props.intl;
|
||||
var state = {};
|
||||
|
||||
const teamName = this.props.teamName;
|
||||
if (!teamName) {
|
||||
state.serverError = 'Bad team name';
|
||||
state.serverError = formatMessage(holders.badTeam);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const id = this.refs.id.value.trim();
|
||||
if (!id) {
|
||||
state.serverError = 'An LDAP ID is required';
|
||||
state.serverError = formatMessage(holders.idReq);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = 'An LDAP password is required';
|
||||
state.serverError = formatMessage(holders.pwdReq);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -64,7 +90,7 @@ export default class LoginLdap extends React.Component {
|
||||
serverError = <label className='control-label'>{this.state.serverError}</label>;
|
||||
errorClass = ' has-error';
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
@@ -76,7 +102,7 @@ export default class LoginLdap extends React.Component {
|
||||
autoFocus={true}
|
||||
className='form-control'
|
||||
ref='id'
|
||||
placeholder='LDAP Username'
|
||||
placeholder={formatMessage(holders.username)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -85,7 +111,7 @@ export default class LoginLdap extends React.Component {
|
||||
type='password'
|
||||
className='form-control'
|
||||
ref='password'
|
||||
placeholder='LDAP Password'
|
||||
placeholder={formatMessage(holders.pwd)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -94,7 +120,10 @@ export default class LoginLdap extends React.Component {
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
{'Sign in'}
|
||||
<FormattedMessage
|
||||
id='login_ldap.signin'
|
||||
defaultMessage='Sign in'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -106,5 +135,8 @@ LoginLdap.defaultProps = {
|
||||
};
|
||||
|
||||
LoginLdap.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(LoginLdap);
|
||||
@@ -6,6 +6,8 @@ import * as Client from '../utils/client.jsx';
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class MemberListTeamItem extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -78,14 +80,29 @@ export default class MemberListTeamItem extends React.Component {
|
||||
}
|
||||
|
||||
const user = this.props.user;
|
||||
let currentRoles = 'Member';
|
||||
let currentRoles = (
|
||||
<FormattedMessage
|
||||
id='member_team_item.member'
|
||||
defaultMessage='Member'
|
||||
/>
|
||||
);
|
||||
const timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
if (user.roles.length > 0) {
|
||||
if (Utils.isSystemAdmin(user.roles)) {
|
||||
currentRoles = 'System Admin';
|
||||
currentRoles = (
|
||||
<FormattedMessage
|
||||
id='member_team_item.systemAdmin'
|
||||
defaultMessage='System Admin'
|
||||
/>
|
||||
);
|
||||
} else if (Utils.isAdmin(user.roles)) {
|
||||
currentRoles = 'Team Admin';
|
||||
currentRoles = (
|
||||
<FormattedMessage
|
||||
id='member_team_item.teamAdmin'
|
||||
defaultMessage='Team Admin'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1);
|
||||
}
|
||||
@@ -98,7 +115,12 @@ export default class MemberListTeamItem extends React.Component {
|
||||
let showMakeNotActive = user.roles !== 'system_admin';
|
||||
|
||||
if (user.delete_at > 0) {
|
||||
currentRoles = 'Inactive';
|
||||
currentRoles = (
|
||||
<FormattedMessage
|
||||
id='member_team_item.inactive'
|
||||
defaultMessage='Inactive'
|
||||
/>
|
||||
);
|
||||
showMakeMember = false;
|
||||
showMakeAdmin = false;
|
||||
showMakeActive = true;
|
||||
@@ -114,7 +136,10 @@ export default class MemberListTeamItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeAdmin}
|
||||
>
|
||||
{'Make Team Admin'}
|
||||
<FormattedMessage
|
||||
id='member_team_item.makeAdmin'
|
||||
defaultMessage='Make Team Admin'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -129,7 +154,10 @@ export default class MemberListTeamItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeMember}
|
||||
>
|
||||
{'Make Member'}
|
||||
<FormattedMessage
|
||||
id='member_team_item.makeMember'
|
||||
defaultMessage='Make Member'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -144,7 +172,10 @@ export default class MemberListTeamItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeActive}
|
||||
>
|
||||
{'Make Active'}
|
||||
<FormattedMessage
|
||||
id='member_team_item.makeActive'
|
||||
defaultMessage='Make Active'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -159,7 +190,10 @@ export default class MemberListTeamItem extends React.Component {
|
||||
href='#'
|
||||
onClick={this.handleMakeNotActive}
|
||||
>
|
||||
{'Make Inactive'}
|
||||
<FormattedMessage
|
||||
id='member_team_item.makeInactive'
|
||||
defaultMessage='Make Inactive'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@ import ChannelStore from '../stores/channel_store.jsx';
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
import NewChannelFlow from './new_channel_flow.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
function getStateFromStores() {
|
||||
return {
|
||||
channels: ChannelStore.getMoreAll(),
|
||||
@@ -100,7 +102,10 @@ export default class MoreChannels extends React.Component {
|
||||
onClick={self.handleJoin.bind(self, channel, index)}
|
||||
className='btn btn-primary'
|
||||
>
|
||||
Join
|
||||
<FormattedMessage
|
||||
id='more_channels.join'
|
||||
defaultMessage='Join'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -123,8 +128,18 @@ export default class MoreChannels extends React.Component {
|
||||
} else {
|
||||
moreChannels = (
|
||||
<div className='no-channel-message'>
|
||||
<p className='primary-message'>No more channels to join</p>
|
||||
<p className='secondary-message'>Click 'Create New Channel' to make a new one</p>
|
||||
<p className='primary-message'>
|
||||
<FormattedMessage
|
||||
id='more_channels.noMore'
|
||||
defaultMessage='No more channels to join'
|
||||
/>
|
||||
</p>
|
||||
<p className='secondary-message'>
|
||||
<FormattedMessage
|
||||
id='more_channels.createClick'
|
||||
defaultMessage="Click 'Create New Channel' to make a new one"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -148,15 +163,28 @@ export default class MoreChannels extends React.Component {
|
||||
data-dismiss='modal'
|
||||
>
|
||||
<span aria-hidden='true'>{'×'}</span>
|
||||
<span className='sr-only'>{'Close'}</span>
|
||||
<span className='sr-only'>
|
||||
<FormattedMessage
|
||||
id='more_channels.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
<h4 className='modal-title'>{'More Channels'}</h4>
|
||||
<h4 className='modal-title'>
|
||||
<FormattedMessage
|
||||
id='more_channels.title'
|
||||
defaultMessage='More Channels'
|
||||
/>
|
||||
</h4>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-primary channel-create-btn'
|
||||
onClick={this.handleNewChannel}
|
||||
>
|
||||
{'Create New Channel'}
|
||||
<FormattedMessage
|
||||
id='more_channels.create'
|
||||
defaultMessage='Create New Channel'
|
||||
/>
|
||||
</button>
|
||||
<NewChannelFlow
|
||||
show={this.state.showNewChannelModal}
|
||||
@@ -174,7 +202,10 @@ export default class MoreChannels extends React.Component {
|
||||
className='btn btn-default'
|
||||
data-dismiss='modal'
|
||||
>
|
||||
{'Close'}
|
||||
<FormattedMessage
|
||||
id='more_channels.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,20 @@ const Modal = ReactBootstrap.Modal;
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
export default class MoreDirectChannels extends React.Component {
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
member: {
|
||||
id: 'more_direct_channels.member',
|
||||
defaultMessage: 'Member'
|
||||
},
|
||||
search: {
|
||||
id: 'more_direct_channels.search',
|
||||
defaultMessage: 'Search members'
|
||||
}
|
||||
});
|
||||
|
||||
class MoreDirectChannels extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -148,7 +161,10 @@ export default class MoreDirectChannels extends React.Component {
|
||||
className='btn btn-primary btn-message'
|
||||
onClick={this.handleShowDirectChannel.bind(this, user)}
|
||||
>
|
||||
{'Message'}
|
||||
<FormattedMessage
|
||||
id='more_direct_channels.message'
|
||||
defaultMessage='Message'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -180,6 +196,7 @@ export default class MoreDirectChannels extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
if (!this.props.show) {
|
||||
return null;
|
||||
}
|
||||
@@ -199,19 +216,44 @@ export default class MoreDirectChannels extends React.Component {
|
||||
const userEntries = users.map(this.createRowForUser);
|
||||
|
||||
if (userEntries.length === 0) {
|
||||
userEntries.push(<tr key='no-users-found'><td>{'No users found :('}</td></tr>);
|
||||
userEntries.push(
|
||||
<tr key='no-users-found'><td>
|
||||
<FormattedMessage
|
||||
id='more_direct_channels.notFound'
|
||||
defaultMessage='No users found :('
|
||||
/>
|
||||
</td></tr>);
|
||||
}
|
||||
|
||||
let memberString = 'Member';
|
||||
let memberString = formatMessage(holders.member);
|
||||
if (users.length !== 1) {
|
||||
memberString += 's';
|
||||
}
|
||||
|
||||
let count;
|
||||
if (users.length === this.state.users.length) {
|
||||
count = `${users.length} ${memberString}`;
|
||||
count = (
|
||||
<FormattedMessage
|
||||
id='more_direct_channels.count'
|
||||
defaultMessage='{count} {member}'
|
||||
values={{
|
||||
count: users.length,
|
||||
member: memberString
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
count = `${users.length} ${memberString} of ${this.state.users.length} Total`;
|
||||
count = (
|
||||
<FormattedMessage
|
||||
id='more_direct_channels.countTotal'
|
||||
defaultMessage='{count} {member} of {total} Total'
|
||||
values={{
|
||||
count: users.length,
|
||||
member: memberString,
|
||||
total: this.state.users.length
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -221,7 +263,12 @@ export default class MoreDirectChannels extends React.Component {
|
||||
onHide={this.handleHide}
|
||||
>
|
||||
<Modal.Header closeButton={true}>
|
||||
<Modal.Title>{'Direct Messages'}</Modal.Title>
|
||||
<Modal.Title>
|
||||
<FormattedMessage
|
||||
id='more_direct_channels.title'
|
||||
defaultMessage='Direct Messages'
|
||||
/>
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body ref='modalBody'>
|
||||
<div className='filter-row'>
|
||||
@@ -229,7 +276,7 @@ export default class MoreDirectChannels extends React.Component {
|
||||
<input
|
||||
ref='filter'
|
||||
className='form-control filter-textbox'
|
||||
placeholder='Search members'
|
||||
placeholder={formatMessage(holders.search)}
|
||||
onInput={this.handleFilterChange}
|
||||
/>
|
||||
</div>
|
||||
@@ -254,7 +301,10 @@ export default class MoreDirectChannels extends React.Component {
|
||||
className='btn btn-default'
|
||||
onClick={this.handleHide}
|
||||
>
|
||||
{'Close'}
|
||||
<FormattedMessage
|
||||
id='more_direct_channels.close'
|
||||
defaultMessage='Close'
|
||||
/>
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
@@ -263,6 +313,9 @@ export default class MoreDirectChannels extends React.Component {
|
||||
}
|
||||
|
||||
MoreDirectChannels.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
onModalDismissed: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default injectIntl(MoreDirectChannels);
|
||||
@@ -5,9 +5,19 @@ import SocketStore from '../stores/socket_store.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const SocketEvents = Constants.SocketEvents;
|
||||
|
||||
export default class MsgTyping extends React.Component {
|
||||
const holders = defineMessages({
|
||||
someone: {
|
||||
id: 'msg_typing.someone',
|
||||
defaultMessage: 'Someone'
|
||||
}
|
||||
});
|
||||
|
||||
class MsgTyping extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -25,9 +35,17 @@ export default class MsgTyping extends React.Component {
|
||||
SocketStore.addChangeListener(this.onChange);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps) {
|
||||
if (this.props.channelId !== newProps.channelId) {
|
||||
this.updateTypingText();
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.channelId !== nextProps.channelId) {
|
||||
for (const u in this.typingUsers) {
|
||||
if (!this.typingUsers.hasOwnProperty(u)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
clearTimeout(this.typingUsers[u]);
|
||||
}
|
||||
this.typingUsers = {};
|
||||
this.setState({text: ''});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +54,10 @@ export default class MsgTyping extends React.Component {
|
||||
}
|
||||
|
||||
onChange(msg) {
|
||||
let username = 'Someone';
|
||||
let username = this.props.intl.formatMessage(holders.someone);
|
||||
if (msg.action === SocketEvents.TYPING &&
|
||||
this.props.channelId === msg.channel_id &&
|
||||
this.props.parentId === msg.props.parent_id) {
|
||||
this.props.channelId === msg.channel_id &&
|
||||
this.props.parentId === msg.props.parent_id) {
|
||||
if (UserStore.hasProfile(msg.user_id)) {
|
||||
username = UserStore.getProfile(msg.user_id).username;
|
||||
}
|
||||
@@ -72,11 +90,28 @@ export default class MsgTyping extends React.Component {
|
||||
text = '';
|
||||
break;
|
||||
case 1:
|
||||
text = users[0] + ' is typing...';
|
||||
text = (
|
||||
<FormattedMessage
|
||||
id='msg_typing.isTyping'
|
||||
defaultMessage='{user} is typing...'
|
||||
values={{
|
||||
user: users[0]
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default: {
|
||||
const last = users.pop();
|
||||
text = users.join(', ') + ' and ' + last + ' are typing...';
|
||||
text = (
|
||||
<FormattedMessage
|
||||
id='msg_typing.areTyping'
|
||||
defaultMessage='{users} and {last} are typing...'
|
||||
vaues={{
|
||||
users: users.join(', '),
|
||||
last: last
|
||||
}}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -92,6 +127,9 @@ export default class MsgTyping extends React.Component {
|
||||
}
|
||||
|
||||
MsgTyping.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
channelId: React.PropTypes.string,
|
||||
parentId: React.PropTypes.string
|
||||
};
|
||||
|
||||
export default injectIntl(MsgTyping);
|
||||
@@ -392,10 +392,14 @@ export default class Navbar extends React.Component {
|
||||
} else if (channel.type === 'D') {
|
||||
isDirect = true;
|
||||
if (this.state.users.length > 1) {
|
||||
let p;
|
||||
if (this.state.users[0].id === currentId) {
|
||||
channelTitle = UserStore.getProfile(this.state.users[1].id).username;
|
||||
p = UserStore.getProfile(this.state.users[1].id);
|
||||
} else {
|
||||
channelTitle = UserStore.getProfile(this.state.users[0].id).username;
|
||||
p = UserStore.getProfile(this.state.users[0].id);
|
||||
}
|
||||
if (p != null) {
|
||||
channelTitle = p.username;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user