diff options
Diffstat (limited to 'api')
-rw-r--r-- | api/admin.go | 62 | ||||
-rw-r--r-- | api/admin_test.go | 148 | ||||
-rw-r--r-- | api/auto_environment.go (renamed from api/auto_enviroment.go) | 30 | ||||
-rw-r--r-- | api/auto_teams.go | 2 | ||||
-rw-r--r-- | api/channel.go | 65 | ||||
-rw-r--r-- | api/channel_benchmark_test.go | 6 | ||||
-rw-r--r-- | api/channel_test.go | 115 | ||||
-rw-r--r-- | api/command.go | 125 | ||||
-rw-r--r-- | api/context.go | 2 | ||||
-rw-r--r-- | api/file.go | 22 | ||||
-rw-r--r-- | api/post.go | 50 | ||||
-rw-r--r-- | api/post_test.go | 40 | ||||
-rw-r--r-- | api/slackimport.go | 2 | ||||
-rw-r--r-- | api/team.go | 45 | ||||
-rw-r--r-- | api/team_test.go | 32 | ||||
-rw-r--r-- | api/user.go | 19 | ||||
-rw-r--r-- | api/user_test.go | 12 |
17 files changed, 592 insertions, 185 deletions
diff --git a/api/admin.go b/api/admin.go index 7a5616ede..8e0a03e4b 100644 --- a/api/admin.go +++ b/api/admin.go @@ -26,7 +26,7 @@ func InitAdmin(r *mux.Router) { sr.Handle("/test_email", ApiUserRequired(testEmail)).Methods("POST") sr.Handle("/client_props", ApiAppHandler(getClientConfig)).Methods("GET") sr.Handle("/log_client", ApiAppHandler(logClient)).Methods("POST") - + sr.Handle("/analytics/{id:[A-Za-z0-9]+}/{name:[A-Za-z0-9_]+}", ApiAppHandler(getAnalytics)).Methods("GET") } func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { @@ -142,3 +142,63 @@ func testEmail(c *Context, w http.ResponseWriter, r *http.Request) { m["SUCCESS"] = "true" w.Write([]byte(model.MapToJson(m))) } + +func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { + if !c.HasSystemAdminPermissions("getAnalytics") { + return + } + + params := mux.Vars(r) + teamId := params["id"] + name := params["name"] + + if name == "standard" { + var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 3) + rows[0] = &model.AnalyticsRow{"channel_open_count", 0} + rows[1] = &model.AnalyticsRow{"channel_private_count", 0} + rows[2] = &model.AnalyticsRow{"post_count", 0} + openChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_OPEN) + privateChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_PRIVATE) + postChan := Srv.Store.Post().AnalyticsPostCount(teamId) + + if r := <-openChan; r.Err != nil { + c.Err = r.Err + return + } else { + rows[0].Value = float64(r.Data.(int64)) + } + + if r := <-privateChan; r.Err != nil { + c.Err = r.Err + return + } else { + rows[1].Value = float64(r.Data.(int64)) + } + + if r := <-postChan; r.Err != nil { + c.Err = r.Err + return + } else { + rows[2].Value = float64(r.Data.(int64)) + } + + w.Write([]byte(rows.ToJson())) + } else if name == "post_counts_day" { + if r := <-Srv.Store.Post().AnalyticsPostCountsByDay(teamId); r.Err != nil { + c.Err = r.Err + return + } else { + w.Write([]byte(r.Data.(model.AnalyticsRows).ToJson())) + } + } else if name == "user_counts_with_posts_day" { + if r := <-Srv.Store.Post().AnalyticsUserCountsWithPostsByDay(teamId); r.Err != nil { + c.Err = r.Err + return + } else { + w.Write([]byte(r.Data.(model.AnalyticsRows).ToJson())) + } + } else { + c.SetInvalidParam("getAnalytics", "name") + } + +} diff --git a/api/admin_test.go b/api/admin_test.go index 0e51644d8..0db5caa4c 100644 --- a/api/admin_test.go +++ b/api/admin_test.go @@ -150,3 +150,151 @@ func TestEmailTest(t *testing.T) { t.Fatal(err) } } + +func TestGetAnalyticsStandard(t *testing.T) { + Setup() + + team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} + team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team) + + user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} + user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user.Id)) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id} + channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel) + + post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"} + post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post) + + if _, err := Client.GetAnalytics(team.Id, "standard"); err == nil { + t.Fatal("Shouldn't have permissions") + } + + c := &Context{} + c.RequestId = model.NewId() + c.IpAddress = "cmd_line" + UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + if result, err := Client.GetAnalytics(team.Id, "standard"); err != nil { + t.Fatal(err) + } else { + rows := result.Data.(model.AnalyticsRows) + + if rows[0].Name != "channel_open_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[0].Value != 2 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[1].Name != "channel_private_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[1].Value != 1 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[2].Name != "post_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[2].Value != 1 { + t.Log(rows.ToJson()) + t.Fatal() + } + } +} + +func TestGetPostCount(t *testing.T) { + Setup() + + team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} + team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team) + + user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} + user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user.Id)) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id} + channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel) + + post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"} + post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post) + + if _, err := Client.GetAnalytics(team.Id, "post_counts_day"); err == nil { + t.Fatal("Shouldn't have permissions") + } + + c := &Context{} + c.RequestId = model.NewId() + c.IpAddress = "cmd_line" + UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + if result, err := Client.GetAnalytics(team.Id, "post_counts_day"); err != nil { + t.Fatal(err) + } else { + rows := result.Data.(model.AnalyticsRows) + + if rows[0].Value != 1 { + t.Log(rows.ToJson()) + t.Fatal() + } + } +} + +func TestUserCountsWithPostsByDay(t *testing.T) { + Setup() + + team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} + team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team) + + user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} + user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user.Id)) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id} + channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel) + + post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"} + post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post) + + if _, err := Client.GetAnalytics(team.Id, "user_counts_with_posts_day"); err == nil { + t.Fatal("Shouldn't have permissions") + } + + c := &Context{} + c.RequestId = model.NewId() + c.IpAddress = "cmd_line" + UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + if result, err := Client.GetAnalytics(team.Id, "user_counts_with_posts_day"); err != nil { + t.Fatal(err) + } else { + rows := result.Data.(model.AnalyticsRows) + + if rows[0].Value != 1 { + t.Log(rows.ToJson()) + t.Fatal() + } + } +} diff --git a/api/auto_enviroment.go b/api/auto_environment.go index c6453f5da..68186ec6c 100644 --- a/api/auto_enviroment.go +++ b/api/auto_environment.go @@ -10,42 +10,42 @@ import ( "time" ) -type TestEnviroment struct { - Teams []*model.Team - Enviroments []TeamEnviroment +type TestEnvironment struct { + Teams []*model.Team + Environments []TeamEnvironment } -func CreateTestEnviromentWithTeams(client *model.Client, rangeTeams utils.Range, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TestEnviroment, bool) { +func CreateTestEnvironmentWithTeams(client *model.Client, rangeTeams utils.Range, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TestEnvironment, bool) { rand.Seed(time.Now().UTC().UnixNano()) teamCreator := NewAutoTeamCreator(client) teamCreator.Fuzzy = fuzzy teams, err := teamCreator.CreateTestTeams(rangeTeams) if err != true { - return TestEnviroment{}, false + return TestEnvironment{}, false } - enviroment := TestEnviroment{teams, make([]TeamEnviroment, len(teams))} + environment := TestEnvironment{teams, make([]TeamEnvironment, len(teams))} for i, team := range teams { userCreator := NewAutoUserCreator(client, team.Id) userCreator.Fuzzy = fuzzy randomUser, err := userCreator.createRandomUser() if err != true { - return TestEnviroment{}, false + return TestEnvironment{}, false } client.LoginById(randomUser.Id, USER_PASSWORD) - teamEnviroment, err := CreateTestEnviromentInTeam(client, team.Id, rangeChannels, rangeUsers, rangePosts, fuzzy) + teamEnvironment, err := CreateTestEnvironmentInTeam(client, team.Id, rangeChannels, rangeUsers, rangePosts, fuzzy) if err != true { - return TestEnviroment{}, false + return TestEnvironment{}, false } - enviroment.Enviroments[i] = teamEnviroment + environment.Environments[i] = teamEnvironment } - return enviroment, true + return environment, true } -func CreateTestEnviromentInTeam(client *model.Client, teamID string, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnviroment, bool) { +func CreateTestEnvironmentInTeam(client *model.Client, teamID string, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnvironment, bool) { rand.Seed(time.Now().UTC().UnixNano()) // We need to create at least one user @@ -57,7 +57,7 @@ func CreateTestEnviromentInTeam(client *model.Client, teamID string, rangeChanne userCreator.Fuzzy = fuzzy users, err := userCreator.CreateTestUsers(rangeUsers) if err != true { - return TeamEnviroment{}, false + return TeamEnvironment{}, false } usernames := make([]string, len(users)) for i, user := range users { @@ -77,7 +77,7 @@ func CreateTestEnviromentInTeam(client *model.Client, teamID string, rangeChanne } if err != true { - return TeamEnviroment{}, false + return TeamEnvironment{}, false } numPosts := utils.RandIntFromRange(rangePosts) numImages := utils.RandIntFromRange(rangePosts) / 4 @@ -93,5 +93,5 @@ func CreateTestEnviromentInTeam(client *model.Client, teamID string, rangeChanne } } - return TeamEnviroment{users, channels}, true + return TeamEnvironment{users, channels}, true } diff --git a/api/auto_teams.go b/api/auto_teams.go index 6677ac9bf..082415d32 100644 --- a/api/auto_teams.go +++ b/api/auto_teams.go @@ -8,7 +8,7 @@ import ( "github.com/mattermost/platform/utils" ) -type TeamEnviroment struct { +type TeamEnvironment struct { Users []*model.User Channels []*model.Channel } diff --git a/api/channel.go b/api/channel.go index a8c8505e9..44be1cf97 100644 --- a/api/channel.go +++ b/api/channel.go @@ -22,7 +22,8 @@ func InitChannel(r *mux.Router) { sr.Handle("/create", ApiUserRequired(createChannel)).Methods("POST") sr.Handle("/create_direct", ApiUserRequired(createDirectChannel)).Methods("POST") sr.Handle("/update", ApiUserRequired(updateChannel)).Methods("POST") - sr.Handle("/update_desc", ApiUserRequired(updateChannelDesc)).Methods("POST") + sr.Handle("/update_header", ApiUserRequired(updateChannelHeader)).Methods("POST") + sr.Handle("/update_purpose", ApiUserRequired(updateChannelPurpose)).Methods("POST") sr.Handle("/update_notify_props", ApiUserRequired(updateNotifyProps)).Methods("POST") sr.Handle("/{id:[A-Za-z0-9]+}/", ApiUserRequiredActivity(getChannel, false)).Methods("GET") sr.Handle("/{id:[A-Za-z0-9]+}/extra_info", ApiUserRequired(getChannelExtraInfo)).Methods("GET") @@ -124,7 +125,7 @@ func CreateDirectChannel(c *Context, otherUserId string) (*model.Channel, *model channel.Name = model.GetDMNameFromIds(otherUserId, c.Session.UserId) channel.TeamId = c.Session.TeamId - channel.Description = "" + channel.Header = "" channel.Type = model.CHANNEL_DIRECT if uresult := <-uc; uresult.Err != nil { @@ -209,7 +210,8 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } - oldChannel.Description = channel.Description + oldChannel.Header = channel.Header + oldChannel.Purpose = channel.Purpose if len(channel.DisplayName) > 0 { oldChannel.DisplayName = channel.DisplayName @@ -233,18 +235,18 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) { } } -func updateChannelDesc(c *Context, w http.ResponseWriter, r *http.Request) { +func updateChannelHeader(c *Context, w http.ResponseWriter, r *http.Request) { props := model.MapFromJson(r.Body) channelId := props["channel_id"] if len(channelId) != 26 { - c.SetInvalidParam("updateChannelDesc", "channel_id") + c.SetInvalidParam("updateChannelHeader", "channel_id") return } - channelDesc := props["channel_description"] - if len(channelDesc) > 1024 { - c.SetInvalidParam("updateChannelDesc", "channel_description") + channelHeader := props["channel_header"] + if len(channelHeader) > 1024 { + c.SetInvalidParam("updateChannelHeader", "channel_header") return } @@ -261,11 +263,54 @@ func updateChannelDesc(c *Context, w http.ResponseWriter, r *http.Request) { channel := cresult.Data.(*model.Channel) // Don't need to do anything channel member, just wanted to confirm it exists - if !c.HasPermissionsToTeam(channel.TeamId, "updateChannelDesc") { + if !c.HasPermissionsToTeam(channel.TeamId, "updateChannelHeader") { return } - channel.Description = channelDesc + channel.Header = channelHeader + + if ucresult := <-Srv.Store.Channel().Update(channel); ucresult.Err != nil { + c.Err = ucresult.Err + return + } else { + c.LogAudit("name=" + channel.Name) + w.Write([]byte(channel.ToJson())) + } + } +} + +func updateChannelPurpose(c *Context, w http.ResponseWriter, r *http.Request) { + props := model.MapFromJson(r.Body) + channelId := props["channel_id"] + if len(channelId) != 26 { + c.SetInvalidParam("updateChannelPurpose", "channel_id") + return + } + + channelPurpose := props["channel_purpose"] + if len(channelPurpose) > 1024 { + c.SetInvalidParam("updateChannelPurpose", "channel_purpose") + return + } + + sc := Srv.Store.Channel().Get(channelId) + cmc := Srv.Store.Channel().GetMember(channelId, c.Session.UserId) + + if cresult := <-sc; cresult.Err != nil { + c.Err = cresult.Err + return + } else if cmcresult := <-cmc; cmcresult.Err != nil { + c.Err = cmcresult.Err + return + } else { + channel := cresult.Data.(*model.Channel) + // Don't need to do anything channel member, just wanted to confirm it exists + + if !c.HasPermissionsToTeam(channel.TeamId, "updateChannelPurpose") { + return + } + + channel.Purpose = channelPurpose if ucresult := <-Srv.Store.Channel().Update(channel); ucresult.Err != nil { c.Err = ucresult.Err diff --git a/api/channel_benchmark_test.go b/api/channel_benchmark_test.go index 58e3fa18d..fb8dd61bc 100644 --- a/api/channel_benchmark_test.go +++ b/api/channel_benchmark_test.go @@ -61,8 +61,8 @@ func BenchmarkCreateDirectChannel(b *testing.B) { func BenchmarkUpdateChannel(b *testing.B) { var ( - NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS} - CHANNEL_DESCRIPTION_LEN = 50 + NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS} + CHANNEL_HEADER_LEN = 50 ) team, _, _ := SetupBenchmark() @@ -73,7 +73,7 @@ func BenchmarkUpdateChannel(b *testing.B) { } for i := range channels { - channels[i].Description = utils.RandString(CHANNEL_DESCRIPTION_LEN, utils.ALPHANUMERIC) + channels[i].Header = utils.RandString(CHANNEL_HEADER_LEN, utils.ALPHANUMERIC) } // Benchmark Start diff --git a/api/channel_test.go b/api/channel_test.go index 899016065..a41f63b1b 100644 --- a/api/channel_test.go +++ b/api/channel_test.go @@ -8,6 +8,7 @@ import ( "github.com/mattermost/platform/store" "github.com/mattermost/platform/utils" "net/http" + "strings" "testing" "time" ) @@ -173,12 +174,17 @@ func TestUpdateChannel(t *testing.T) { Client.AddChannelMember(channel1.Id, userTeamAdmin.Id) - desc := "a" + model.NewId() + "a" - upChannel1 := &model.Channel{Id: channel1.Id, Description: desc} + header := "a" + model.NewId() + "a" + purpose := "a" + model.NewId() + "a" + upChannel1 := &model.Channel{Id: channel1.Id, Header: header, Purpose: purpose} upChannel1 = Client.Must(Client.UpdateChannel(upChannel1)).Data.(*model.Channel) - if upChannel1.Description != desc { - t.Fatal("Channel admin failed to update desc") + if upChannel1.Header != header { + t.Fatal("Channel admin failed to update header") + } + + if upChannel1.Purpose != purpose { + t.Fatal("Channel admin failed to update purpose") } if upChannel1.DisplayName != channel1.DisplayName { @@ -187,12 +193,17 @@ func TestUpdateChannel(t *testing.T) { Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd") - desc = "b" + model.NewId() + "b" - upChannel1 = &model.Channel{Id: channel1.Id, Description: desc} + header = "b" + model.NewId() + "b" + purpose = "b" + model.NewId() + "b" + upChannel1 = &model.Channel{Id: channel1.Id, Header: header, Purpose: purpose} upChannel1 = Client.Must(Client.UpdateChannel(upChannel1)).Data.(*model.Channel) - if upChannel1.Description != desc { - t.Fatal("Team admin failed to update desc") + if upChannel1.Header != header { + t.Fatal("Team admin failed to update header") + } + + if upChannel1.Purpose != purpose { + t.Fatal("Team admin failed to update purpose") } if upChannel1.DisplayName != channel1.DisplayName { @@ -203,7 +214,7 @@ func TestUpdateChannel(t *testing.T) { data := rget.Data.(*model.ChannelList) for _, c := range data.Channels { if c.Name == model.DEFAULT_CHANNEL { - c.Description = "new desc" + c.Header = "new header" if _, err := Client.UpdateChannel(c); err == nil { t.Fatal("should have errored on updating default channel") } @@ -218,7 +229,7 @@ func TestUpdateChannel(t *testing.T) { } } -func TestUpdateChannelDesc(t *testing.T) { +func TestUpdateChannelHeader(t *testing.T) { Setup() team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} @@ -235,36 +246,92 @@ func TestUpdateChannelDesc(t *testing.T) { data := make(map[string]string) data["channel_id"] = channel1.Id - data["channel_description"] = "new desc" + data["channel_header"] = "new header" var upChannel1 *model.Channel - if result, err := Client.UpdateChannelDesc(data); err != nil { + if result, err := Client.UpdateChannelHeader(data); err != nil { t.Fatal(err) } else { upChannel1 = result.Data.(*model.Channel) } - if upChannel1.Description != data["channel_description"] { - t.Fatal("Failed to update desc") + if upChannel1.Header != data["channel_header"] { + t.Fatal("Failed to update header") } data["channel_id"] = "junk" - if _, err := Client.UpdateChannelDesc(data); err == nil { + if _, err := Client.UpdateChannelHeader(data); err == nil { t.Fatal("should have errored on junk channel id") } data["channel_id"] = "12345678901234567890123456" - if _, err := Client.UpdateChannelDesc(data); err == nil { + if _, err := Client.UpdateChannelHeader(data); err == nil { t.Fatal("should have errored on non-existent channel id") } data["channel_id"] = channel1.Id - data["channel_description"] = "" - for i := 0; i < 1050; i++ { - data["channel_description"] += "a" + data["channel_header"] = strings.Repeat("a", 1050) + if _, err := Client.UpdateChannelHeader(data); err == nil { + t.Fatal("should have errored on bad channel header") + } + + user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.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") + + data["channel_id"] = channel1.Id + data["channel_header"] = "new header" + if _, err := Client.UpdateChannelHeader(data); err == nil { + t.Fatal("should have errored non-channel member trying to update header") } - if _, err := Client.UpdateChannelDesc(data); err == nil { - t.Fatal("should have errored on bad channel desc") +} + +func TestUpdateChannelPurpose(t *testing.T) { + Setup() + + team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} + team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team) + + user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} + user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user.Id)) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + 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) + + data := make(map[string]string) + data["channel_id"] = channel1.Id + data["channel_purpose"] = "new purpose" + + var upChannel1 *model.Channel + if result, err := Client.UpdateChannelPurpose(data); err != nil { + t.Fatal(err) + } else { + upChannel1 = result.Data.(*model.Channel) + } + + if upChannel1.Purpose != data["channel_purpose"] { + t.Fatal("Failed to update purpose") + } + + data["channel_id"] = "junk" + if _, err := Client.UpdateChannelPurpose(data); err == nil { + t.Fatal("should have errored on junk channel id") + } + + data["channel_id"] = "12345678901234567890123456" + if _, err := Client.UpdateChannelPurpose(data); err == nil { + t.Fatal("should have errored on non-existent channel id") + } + + data["channel_id"] = channel1.Id + data["channel_purpose"] = strings.Repeat("a", 150) + if _, err := Client.UpdateChannelPurpose(data); err == nil { + t.Fatal("should have errored on bad channel purpose") } user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} @@ -274,9 +341,9 @@ func TestUpdateChannelDesc(t *testing.T) { Client.LoginByEmail(team.Name, user2.Email, "pwd") data["channel_id"] = channel1.Id - data["channel_description"] = "new desc" - if _, err := Client.UpdateChannelDesc(data); err == nil { - t.Fatal("should have errored non-channel member trying to update desc") + data["channel_purpose"] = "new purpose" + if _, err := Client.UpdateChannelPurpose(data); err == nil { + t.Fatal("should have errored non-channel member trying to update purpose") } } diff --git a/api/command.go b/api/command.go index 54f863c48..50ca41155 100644 --- a/api/command.go +++ b/api/command.go @@ -17,14 +17,25 @@ import ( type commandHandler func(c *Context, command *model.Command) bool -var commands = []commandHandler{ - logoutCommand, - joinCommand, - loadTestCommand, - echoCommand, - shrugCommand, -} - +var ( + cmds = map[string]string{ + "logoutCommand": "/logout", + "joinCommand": "/join", + "loadTestCommand": "/loadtest", + "echoCommand": "/echo", + "shrugCommand": "/shrug", + "meCommand": "/me", + } + commands = []commandHandler{ + logoutCommand, + joinCommand, + loadTestCommand, + echoCommand, + shrugCommand, + meCommand, + } + commandNotImplementedErr = model.NewAppError("checkCommand", "Command not implemented", "") +) var echoSem chan bool func InitCommand(r *mux.Router) { @@ -45,7 +56,14 @@ func command(c *Context, w http.ResponseWriter, r *http.Request) { checkCommand(c, command) if c.Err != nil { - return + if c.Err != commandNotImplementedErr { + return + } else { + c.Err = nil + command.Response = model.RESP_NOT_IMPLEMENTED + w.Write([]byte(command.ToJson())) + return + } } else { w.Write([]byte(command.ToJson())) } @@ -66,6 +84,23 @@ func checkCommand(c *Context, command *model.Command) bool { } } + if !command.Suggest { + implemented := false + for _, cmd := range cmds { + bounds := len(cmd) + if len(command.Command) < bounds { + continue + } + if command.Command[:bounds] == cmd { + implemented = true + } + } + if !implemented { + c.Err = commandNotImplementedErr + return false + } + } + for _, v := range commands { if v(c, command) || c.Err != nil { @@ -78,7 +113,7 @@ func checkCommand(c *Context, command *model.Command) bool { func logoutCommand(c *Context, command *model.Command) bool { - cmd := "/logout" + cmd := cmds["logoutCommand"] if strings.Index(command.Command, cmd) == 0 { command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Logout"}) @@ -97,7 +132,7 @@ func logoutCommand(c *Context, command *model.Command) bool { } func echoCommand(c *Context, command *model.Command) bool { - cmd := "/echo" + cmd := cmds["echoCommand"] maxThreads := 100 if !command.Suggest && strings.Index(command.Command, cmd) == 0 { @@ -161,11 +196,39 @@ func echoCommand(c *Context, command *model.Command) bool { return false } +func meCommand(c *Context, command *model.Command) bool { + cmd := cmds["meCommand"] + + if !command.Suggest && strings.Index(command.Command, cmd) == 0 { + message := "" + + parameters := strings.SplitN(command.Command, " ", 2) + if len(parameters) > 1 { + message += "*" + parameters[1] + "*" + } + + post := &model.Post{} + post.Message = message + post.ChannelId = command.ChannelId + if _, err := CreatePost(c, post, false); err != nil { + l4g.Error("Unable to create /me post post, err=%v", err) + return false + } + command.Response = model.RESP_EXECUTED + return true + + } else if strings.Index(cmd, command.Command) == 0 { + command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Do an action, /me [message]"}) + } + + return false +} + func shrugCommand(c *Context, command *model.Command) bool { - cmd := "/shrug" + cmd := cmds["shrugCommand"] if !command.Suggest && strings.Index(command.Command, cmd) == 0 { - message := "¯\\_(ツ)_/¯" + message := `¯\\\_(ツ)_/¯` parameters := strings.SplitN(command.Command, " ", 2) if len(parameters) > 1 { @@ -192,7 +255,7 @@ func shrugCommand(c *Context, command *model.Command) bool { func joinCommand(c *Context, command *model.Command) bool { // looks for "/join channel-name" - cmd := "/join" + cmd := cmds["joinCommand"] if strings.Index(command.Command, cmd) == 0 { @@ -242,7 +305,7 @@ func joinCommand(c *Context, command *model.Command) bool { } func loadTestCommand(c *Context, command *model.Command) bool { - cmd := "/loadtest" + cmd := cmds["loadTestCommand"] // This command is only available when EnableTesting is true if !utils.Cfg.ServiceSettings.EnableTesting { @@ -304,7 +367,7 @@ func contains(items []string, token string) bool { } func loadTestSetupCommand(c *Context, command *model.Command) bool { - cmd := "/loadtest setup" + cmd := cmds["loadTestCommand"] + " setup" if strings.Index(command.Command, cmd) == 0 && !command.Suggest { tokens := strings.Fields(strings.TrimPrefix(command.Command, cmd)) @@ -348,11 +411,11 @@ func loadTestSetupCommand(c *Context, command *model.Command) bool { if doTeams { if err := CreateBasicUser(client); err != nil { - l4g.Error("Failed to create testing enviroment") + l4g.Error("Failed to create testing environment") return true } client.LoginByEmail(BTEST_TEAM_NAME, BTEST_USER_EMAIL, BTEST_USER_PASSWORD) - enviroment, err := CreateTestEnviromentWithTeams( + environment, err := CreateTestEnvironmentWithTeams( client, utils.Range{numTeams, numTeams}, utils.Range{numChannels, numChannels}, @@ -360,18 +423,18 @@ func loadTestSetupCommand(c *Context, command *model.Command) bool { utils.Range{numPosts, numPosts}, doFuzz) if err != true { - l4g.Error("Failed to create testing enviroment") + l4g.Error("Failed to create testing environment") return true } else { - l4g.Info("Testing enviroment created") - for i := 0; i < len(enviroment.Teams); i++ { - l4g.Info("Team Created: " + enviroment.Teams[i].Name) - l4g.Info("\t User to login: " + enviroment.Enviroments[i].Users[0].Email + ", " + USER_PASSWORD) + l4g.Info("Testing environment created") + for i := 0; i < len(environment.Teams); i++ { + l4g.Info("Team Created: " + environment.Teams[i].Name) + l4g.Info("\t User to login: " + environment.Environments[i].Users[0].Email + ", " + USER_PASSWORD) } } } else { client.MockSession(c.Session.Token) - CreateTestEnviromentInTeam( + CreateTestEnvironmentInTeam( client, c.Session.TeamId, utils.Range{numChannels, numChannels}, @@ -383,15 +446,15 @@ func loadTestSetupCommand(c *Context, command *model.Command) bool { } else if strings.Index(cmd, command.Command) == 0 { command.AddSuggestion(&model.SuggestCommand{ Suggestion: cmd, - Description: "Creates a testing enviroment in current team. [teams] [fuzz] <Num Channels> <Num Users> <NumPosts>"}) + Description: "Creates a testing environment in current team. [teams] [fuzz] <Num Channels> <Num Users> <NumPosts>"}) } return false } func loadTestUsersCommand(c *Context, command *model.Command) bool { - cmd1 := "/loadtest users" - cmd2 := "/loadtest users fuzz" + cmd1 := cmds["loadTestCommand"] + " users" + cmd2 := cmds["loadTestCommand"] + " users fuzz" if strings.Index(command.Command, cmd1) == 0 && !command.Suggest { cmd := cmd1 @@ -420,8 +483,8 @@ func loadTestUsersCommand(c *Context, command *model.Command) bool { } func loadTestChannelsCommand(c *Context, command *model.Command) bool { - cmd1 := "/loadtest channels" - cmd2 := "/loadtest channels fuzz" + cmd1 := cmds["loadTestCommand"] + " channels" + cmd2 := cmds["loadTestCommand"] + " channels fuzz" if strings.Index(command.Command, cmd1) == 0 && !command.Suggest { cmd := cmd1 @@ -451,8 +514,8 @@ func loadTestChannelsCommand(c *Context, command *model.Command) bool { } func loadTestPostsCommand(c *Context, command *model.Command) bool { - cmd1 := "/loadtest posts" - cmd2 := "/loadtest posts fuzz" + cmd1 := cmds["loadTestCommand"] + " posts" + cmd2 := cmds["loadTestCommand"] + " posts fuzz" if strings.Index(command.Command, cmd1) == 0 && !command.Suggest { cmd := cmd1 diff --git a/api/context.go b/api/context.go index 9be3e85cc..a5d4169cb 100644 --- a/api/context.go +++ b/api/context.go @@ -320,7 +320,7 @@ func (c *Context) HasSystemAdminPermissions(where string) bool { return true } - c.Err = model.NewAppError(where, "You do not have the appropriate permissions", "userId="+c.Session.UserId) + c.Err = model.NewAppError(where, "You do not have the appropriate permissions (system)", "userId="+c.Session.UserId) c.Err.StatusCode = http.StatusForbidden return false } diff --git a/api/file.go b/api/file.go index 94eea516a..8afc70692 100644 --- a/api/file.go +++ b/api/file.go @@ -52,6 +52,8 @@ const ( RotatedCCW = 6 RotatedCCWMirrored = 7 RotatedCW = 8 + + MaxImageSize = 4096 * 2160 // 4k resolution ) var fileInfoCache *utils.Cache = utils.NewLru(1000) @@ -125,6 +127,21 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { uid := model.NewId() + if model.IsFileExtImage(filepath.Ext(files[i].Filename)) { + imageNameList = append(imageNameList, uid+"/"+filename) + imageDataList = append(imageDataList, buf.Bytes()) + + // Decode image config first to check dimensions before loading the whole thing into memory later on + config, _, err := image.DecodeConfig(bytes.NewReader(buf.Bytes())) + if err != nil { + c.Err = model.NewAppError("uploadFile", "Unable to upload image file.", err.Error()) + return + } else if config.Width*config.Height > MaxImageSize { + c.Err = model.NewAppError("uploadFile", "Unable to upload image file. File is too large.", "File exceeds max image size.") + return + } + } + path := "teams/" + c.Session.TeamId + "/channels/" + channelId + "/users/" + c.Session.UserId + "/" + uid + "/" + filename if err := writeFile(buf.Bytes(), path); err != nil { @@ -132,11 +149,6 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { return } - if model.IsFileExtImage(filepath.Ext(files[i].Filename)) { - imageNameList = append(imageNameList, uid+"/"+filename) - imageDataList = append(imageDataList, buf.Bytes()) - } - encName := utils.UrlEncode(filename) fileUrl := "/" + channelId + "/" + c.Session.UserId + "/" + uid + "/" + encName diff --git a/api/post.go b/api/post.go index 79f84e04d..c98bf2d71 100644 --- a/api/post.go +++ b/api/post.go @@ -249,7 +249,7 @@ func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team } for _, hook := range relevantHooks { - go func() { + go func(hook *model.OutgoingWebhook) { p := url.Values{} p.Set("token", hook.Token) @@ -270,7 +270,7 @@ func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team client := &http.Client{} for _, url := range hook.CallbackURLs { - go func() { + go func(url string) { req, _ := http.NewRequest("POST", url, strings.NewReader(p.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept", "application/json") @@ -289,10 +289,10 @@ func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team } } } - }() + }(url) } - }() + }(hook) } }() @@ -820,45 +820,23 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) { return } - plainSearchParams, hashtagSearchParams := model.ParseSearchParams(terms) + paramsList := model.ParseSearchParams(terms) + channels := []store.StoreChannel{} - var hchan store.StoreChannel - if hashtagSearchParams != nil { - hchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, hashtagSearchParams) + for _, params := range paramsList { + channels = append(channels, Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, params)) } - var pchan store.StoreChannel - if plainSearchParams != nil { - pchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, plainSearchParams) - } - - mainList := &model.PostList{} - if hchan != nil { - if result := <-hchan; result.Err != nil { + posts := &model.PostList{} + for _, channel := range channels { + if result := <-channel; result.Err != nil { c.Err = result.Err return } else { - mainList = result.Data.(*model.PostList) + data := result.Data.(*model.PostList) + posts.Extend(data) } } - plainList := &model.PostList{} - if pchan != nil { - if result := <-pchan; result.Err != nil { - c.Err = result.Err - return - } else { - plainList = result.Data.(*model.PostList) - } - } - - for _, postId := range plainList.Order { - if _, ok := mainList.Posts[postId]; !ok { - mainList.AddPost(plainList.Posts[postId]) - mainList.AddOrder(postId) - } - - } - - w.Write([]byte(mainList.ToJson())) + w.Write([]byte(posts.ToJson())) } diff --git a/api/post_test.go b/api/post_test.go index ac9d5668b..e54e9ef0c 100644 --- a/api/post_test.go +++ b/api/post_test.go @@ -427,12 +427,18 @@ func TestSearchPostsInChannel(t *testing.T) { channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel) + channel3 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} + channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel) + post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"} post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post) post3 := &model.Post{ChannelId: channel2.Id, Message: "other message with no return"} post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post) + post4 := &model.Post{ChannelId: channel3.Id, Message: "other message with no return"} + post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post) + if result := Client.Must(Client.SearchPosts("channel:")).Data.(*model.PostList); len(result.Order) != 0 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } @@ -476,6 +482,10 @@ func TestSearchPostsInChannel(t *testing.T) { if result := Client.Must(Client.SearchPosts("sgtitlereview channel: " + 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("channel: " + channel2.Name + " channel: " + channel3.Name)).Data.(*model.PostList); len(result.Order) != 3 { + t.Fatalf("wrong number of posts returned :) %v :) %v", result.Posts, result.Order) + } } func TestSearchPostsFromUser(t *testing.T) { @@ -510,11 +520,12 @@ 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)) } - // note that this includes the "User2 has joined the channel" system messages if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 { t.Fatalf("wrong number of posts returned %v", len(result.Order)) } @@ -526,6 +537,33 @@ func TestSearchPostsFromUser(t *testing.T) { 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.com", Nickname: "Corey Hulen", Password: "pwd"} + user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user3.Id)) + + Client.LoginByEmail(team.Name, user3.Email, "pwd") + Client.Must(Client.JoinChannel(channel1.Id)) + Client.Must(Client.JoinChannel(channel2.Id)) + + // 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 { + 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 { + 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 { + 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 { + t.Fatalf("wrong number of posts returned %v", len(result.Order)) + } } func TestGetPostsCache(t *testing.T) { diff --git a/api/slackimport.go b/api/slackimport.go index 06032c068..cab4c6184 100644 --- a/api/slackimport.go +++ b/api/slackimport.go @@ -182,7 +182,7 @@ func SlackAddChannels(teamId string, slackchannels []SlackChannel, posts map[str Type: model.CHANNEL_OPEN, DisplayName: sChannel.Name, Name: SlackConvertChannelName(sChannel.Name), - Description: sChannel.Topic["value"], + Purpose: sChannel.Topic["value"], } mChannel := ImportChannel(&newChannel) if mChannel == nil { diff --git a/api/team.go b/api/team.go index d39d8ed60..7d746d922 100644 --- a/api/team.go +++ b/api/team.go @@ -30,7 +30,7 @@ func InitTeam(r *mux.Router) { sr.Handle("/find_teams", ApiAppHandler(findTeams)).Methods("POST") sr.Handle("/email_teams", ApiAppHandler(emailTeams)).Methods("POST") sr.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST") - sr.Handle("/update_name", ApiUserRequired(updateTeamDisplayName)).Methods("POST") + sr.Handle("/update", ApiUserRequired(updateTeam)).Methods("POST") sr.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET") // These should be moved to the global admain console sr.Handle("/import_team", ApiUserRequired(importTeam)).Methods("POST") @@ -541,40 +541,47 @@ func InviteMembers(c *Context, team *model.Team, user *model.User, invites []str } } -func updateTeamDisplayName(c *Context, w http.ResponseWriter, r *http.Request) { +func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) { - props := model.MapFromJson(r.Body) + team := model.TeamFromJson(r.Body) - new_name := props["new_name"] - if len(new_name) == 0 { - c.SetInvalidParam("updateTeamDisplayName", "new_name") + if team == nil { + c.SetInvalidParam("updateTeam", "team") return } - teamId := props["team_id"] - if len(teamId) > 0 && len(teamId) != 26 { - c.SetInvalidParam("updateTeamDisplayName", "team_id") - return - } else if len(teamId) == 0 { - teamId = c.Session.TeamId - } + team.Id = c.Session.TeamId - if !c.HasPermissionsToTeam(teamId, "updateTeamDisplayName") { + if !c.IsTeamAdmin() { + c.Err = model.NewAppError("updateTeam", "You do not have the appropriate permissions", "userId="+c.Session.UserId) + c.Err.StatusCode = http.StatusForbidden return } - if !c.IsTeamAdmin() { - c.Err = model.NewAppError("updateTeamDisplayName", "You do not have the appropriate permissions", "userId="+c.Session.UserId) - c.Err.StatusCode = http.StatusForbidden + var oldTeam *model.Team + if result := <-Srv.Store.Team().Get(team.Id); result.Err != nil { + c.Err = result.Err return + } else { + oldTeam = result.Data.(*model.Team) } - if result := <-Srv.Store.Team().UpdateDisplayName(new_name, c.Session.TeamId); result.Err != nil { + oldTeam.DisplayName = team.DisplayName + oldTeam.InviteId = team.InviteId + oldTeam.AllowOpenInvite = team.AllowOpenInvite + oldTeam.AllowTeamListing = team.AllowTeamListing + oldTeam.CompanyName = team.CompanyName + oldTeam.AllowedDomains = team.AllowedDomains + //oldTeam.Type = team.Type + + if result := <-Srv.Store.Team().Update(oldTeam); result.Err != nil { c.Err = result.Err return } - w.Write([]byte(model.MapToJson(props))) + oldTeam.Sanitize() + + w.Write([]byte(oldTeam.ToJson())) } func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) { diff --git a/api/team_test.go b/api/team_test.go index 507f4252a..7a3b092ce 100644 --- a/api/team_test.go +++ b/api/team_test.go @@ -281,41 +281,23 @@ func TestUpdateTeamDisplayName(t *testing.T) { Client.LoginByEmail(team.Name, user2.Email, "pwd") - data := make(map[string]string) - data["new_name"] = "NewName" - if _, err := Client.UpdateTeamDisplayName(data); err == nil { + vteam := &model.Team{DisplayName: team.DisplayName, Name: team.Name, Email: team.Email, Type: team.Type} + vteam.DisplayName = "NewName" + if _, err := Client.UpdateTeam(vteam); err == nil { t.Fatal("Should have errored, not admin") } Client.LoginByEmail(team.Name, user.Email, "pwd") - data["new_name"] = "" - if _, err := Client.UpdateTeamDisplayName(data); err == nil { + vteam.DisplayName = "" + if _, err := Client.UpdateTeam(vteam); err == nil { t.Fatal("Should have errored, empty name") } - data["new_name"] = "NewName" - if _, err := Client.UpdateTeamDisplayName(data); err != nil { + vteam.DisplayName = "NewName" + if _, err := Client.UpdateTeam(vteam); err != nil { t.Fatal(err) } - // No GET team web service, so hard to confirm here that team name updated - - data["team_id"] = "junk" - if _, err := Client.UpdateTeamDisplayName(data); err == nil { - t.Fatal("Should have errored, junk team id") - } - - data["team_id"] = "12345678901234567890123456" - if _, err := Client.UpdateTeamDisplayName(data); err == nil { - t.Fatal("Should have errored, bad team id") - } - - data["team_id"] = team.Id - data["new_name"] = "NewNameAgain" - if _, err := Client.UpdateTeamDisplayName(data); err != nil { - t.Fatal(err) - } - // No GET team web service, so hard to confirm here that team name updated } func TestFuzzyTeamCreate(t *testing.T) { diff --git a/api/user.go b/api/user.go index 3071e1b26..732c6b9a8 100644 --- a/api/user.go +++ b/api/user.go @@ -652,6 +652,12 @@ func getProfiles(c *Context, w http.ResponseWriter, r *http.Request) { for k, p := range profiles { options := utils.SanitizeOptions options["passwordupdate"] = false + + if c.IsSystemAdmin() { + options["fullname"] = true + options["email"] = true + } + p.Sanitize(options) profiles[k] = p } @@ -814,6 +820,7 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "max-age=86400, public") // 24 hrs } + w.Header().Set("Content-Type", "image/png") w.Write(img) } } @@ -854,6 +861,18 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { return } + // Decode image config first to check dimensions before loading the whole thing into memory later on + config, _, err := image.DecodeConfig(file) + if err != nil { + c.Err = model.NewAppError("uploadProfileFile", "Could not decode profile image config.", err.Error()) + return + } else if config.Width*config.Height > MaxImageSize { + c.Err = model.NewAppError("uploadProfileFile", "Unable to upload profile image. File is too large.", err.Error()) + return + } + + file.Seek(0, 0) + // Decode image into Image object img, _, err := image.Decode(file) if err != nil { diff --git a/api/user_test.go b/api/user_test.go index b54e030c5..0ad3541bc 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -661,12 +661,6 @@ func TestUserUpdateRoles(t *testing.T) { t.Fatal("Should have errored, not admin") } - name := make(map[string]string) - name["new_name"] = "NewName" - if _, err := Client.UpdateTeamDisplayName(name); err == nil { - t.Fatal("should have errored - user not admin yet") - } - 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) @@ -707,12 +701,6 @@ func TestUserUpdateRoles(t *testing.T) { t.Fatal("Roles did not update properly") } } - - Client.LoginByEmail(team.Name, user2.Email, "pwd") - - if _, err := Client.UpdateTeamDisplayName(name); err != nil { - t.Fatal(err) - } } func TestUserUpdateActive(t *testing.T) { |