summaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/auto_constants.go2
-rw-r--r--api/command.go23
-rw-r--r--api/context.go4
-rw-r--r--api/post.go22
-rw-r--r--api/post_test.go2
-rw-r--r--api/team.go82
-rw-r--r--api/team_test.go103
-rw-r--r--api/user.go103
-rw-r--r--api/user_test.go15
9 files changed, 273 insertions, 83 deletions
diff --git a/api/auto_constants.go b/api/auto_constants.go
index 7af90a5f1..3f8831055 100644
--- a/api/auto_constants.go
+++ b/api/auto_constants.go
@@ -32,5 +32,5 @@ var (
POST_MESSAGE_LEN = utils.Range{100, 400}
POST_HASHTAGS_NUM = utils.Range{5, 10}
POST_MENTIONS_NUM = utils.Range{0, 3}
- TEST_IMAGE_FILENAMES = []string{"test.png", "salamander.jpg", "toothless.gif"}
+ TEST_IMAGE_FILENAMES = []string{"test.png", "testjpg.jpg", "testgif.gif"}
)
diff --git a/api/command.go b/api/command.go
index 449483bbf..aedbe07cc 100644
--- a/api/command.go
+++ b/api/command.go
@@ -9,6 +9,8 @@ import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"net/http"
+ "reflect"
+ "runtime"
"strconv"
"strings"
)
@@ -19,16 +21,13 @@ var commands = []commandHandler{
logoutCommand,
joinCommand,
loadTestCommand,
+ echoCommand,
}
func InitCommand(r *mux.Router) {
l4g.Debug("Initializing command api routes")
r.Handle("/command", ApiUserRequired(command)).Methods("POST")
- if utils.Cfg.TeamSettings.AllowValet {
- commands = append(commands, echoCommand)
- }
-
hub.Start()
}
@@ -59,6 +58,8 @@ func checkCommand(c *Context, command *model.Command) bool {
return false
}
+ tchan := Srv.Store.Team().Get(c.Session.TeamId)
+
if len(command.ChannelId) > 0 {
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, command.ChannelId, c.Session.UserId)
@@ -67,7 +68,21 @@ func checkCommand(c *Context, command *model.Command) bool {
}
}
+ allowValet := false
+ if tResult := <-tchan; tResult.Err != nil {
+ c.Err = model.NewAppError("checkCommand", "Could not find the team for this session, team_id="+c.Session.TeamId, "")
+ return false
+ } else {
+ allowValet = tResult.Data.(*model.Team).AllowValet
+ }
+
+ ec := runtime.FuncForPC(reflect.ValueOf(echoCommand).Pointer()).Name()
+
for _, v := range commands {
+ if !allowValet && ec == runtime.FuncForPC(reflect.ValueOf(v).Pointer()).Name() {
+ continue
+ }
+
if v(c, command) {
return true
} else if c.Err != nil {
diff --git a/api/context.go b/api/context.go
index 16105c8af..501e4e77f 100644
--- a/api/context.go
+++ b/api/context.go
@@ -303,6 +303,10 @@ func IsTestDomain(r *http.Request) bool {
return true
}
+ if strings.Index(r.Host, "dockerhost") == 0 {
+ return true
+ }
+
if strings.Index(r.Host, "test") == 0 {
return true
}
diff --git a/api/post.go b/api/post.go
index 36607c231..99cbdcb85 100644
--- a/api/post.go
+++ b/api/post.go
@@ -58,11 +58,7 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
}
func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.Cfg.TeamSettings.AllowValet {
- c.Err = model.NewAppError("createValetPost", "The valet feature is currently turned off. Please contact your system administrator for details.", "")
- c.Err.StatusCode = http.StatusNotImplemented
- return
- }
+ tchan := Srv.Store.Team().Get(c.Session.TeamId)
post := model.PostFromJson(r.Body)
if post == nil {
@@ -70,13 +66,25 @@ func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- // Any one with access to the team can post as valet to any open channel
cchan := Srv.Store.Channel().CheckOpenChannelPermissions(c.Session.TeamId, post.ChannelId)
+ // Any one with access to the team can post as valet to any open channel
if !c.HasPermissionsToChannel(cchan, "createValetPost") {
return
}
+ // Make sure this team has the valet feature enabled
+ if tResult := <-tchan; tResult.Err != nil {
+ c.Err = model.NewAppError("createValetPost", "Could not find the team for this session, team_id="+c.Session.TeamId, "")
+ return
+ } else {
+ if !tResult.Data.(*model.Team).AllowValet {
+ c.Err = model.NewAppError("createValetPost", "The valet feature is currently turned off. Please contact your team administrator for details.", "")
+ c.Err.StatusCode = http.StatusNotImplemented
+ return
+ }
+ }
+
if rp, err := CreateValetPost(c, post); err != nil {
c.Err = err
@@ -302,7 +310,7 @@ func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
// Build a map as a list of unique user_ids that are mentioned in this post
splitF := func(c rune) bool {
- return c == ',' || c == ' ' || c == '.' || c == '!' || c == '?' || c == ':' || c == '<' || c == '>'
+ return model.SplitRunes[c]
}
splitMessage := strings.FieldsFunc(strings.Replace(post.Message, "<br>", " ", -1), splitF)
for _, word := range splitMessage {
diff --git a/api/post_test.go b/api/post_test.go
index b322a5017..03f70bff7 100644
--- a/api/post_test.go
+++ b/api/post_test.go
@@ -147,7 +147,7 @@ func TestCreateValetPost(t *testing.T) {
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
- if utils.Cfg.TeamSettings.AllowValet {
+ if utils.Cfg.TeamSettings.AllowValetDefault {
post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
rpost1, err := Client.CreateValetPost(post1)
if err != nil {
diff --git a/api/team.go b/api/team.go
index cb60602c6..775bc29ae 100644
--- a/api/team.go
+++ b/api/team.go
@@ -29,6 +29,8 @@ func InitTeam(r *mux.Router) {
sr.Handle("/email_teams", ApiAppHandler(emailTeams)).Methods("POST")
sr.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST")
sr.Handle("/update_name", ApiUserRequired(updateTeamName)).Methods("POST")
+ sr.Handle("/update_valet_feature", ApiUserRequired(updateValetFeature)).Methods("POST")
+ sr.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET")
}
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -136,6 +138,8 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
+ teamSignup.Team.AllowValet = utils.Cfg.TeamSettings.AllowValetDefault
+
if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil {
c.Err = result.Err
return
@@ -157,7 +161,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- if utils.Cfg.TeamSettings.AllowValet {
+ if teamSignup.Team.AllowValet {
CreateValet(c, rteam)
if c.Err != nil {
return
@@ -200,6 +204,13 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
+ if rteam.AllowValet {
+ CreateValet(c, rteam)
+ if c.Err != nil {
+ return
+ }
+ }
+
w.Write([]byte(rteam.ToJson()))
}
}
@@ -542,3 +553,72 @@ func updateTeamName(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.MapToJson(props)))
}
+
+func updateValetFeature(c *Context, w http.ResponseWriter, r *http.Request) {
+
+ props := model.MapFromJson(r.Body)
+
+ allowValetStr := props["allow_valet"]
+ if len(allowValetStr) == 0 {
+ c.SetInvalidParam("updateValetFeature", "allow_valet")
+ return
+ }
+
+ allowValet := allowValetStr == "true"
+
+ teamId := props["team_id"]
+ if len(teamId) > 0 && len(teamId) != 26 {
+ c.SetInvalidParam("updateValetFeature", "team_id")
+ return
+ } else if len(teamId) == 0 {
+ teamId = c.Session.TeamId
+ }
+
+ tchan := Srv.Store.Team().Get(teamId)
+
+ if !c.HasPermissionsToTeam(teamId, "updateValetFeature") {
+ return
+ }
+
+ if !strings.Contains(c.Session.Roles, model.ROLE_ADMIN) {
+ c.Err = model.NewAppError("updateValetFeature", "You do not have the appropriate permissions", "userId="+c.Session.UserId)
+ c.Err.StatusCode = http.StatusForbidden
+ return
+ }
+
+ var team *model.Team
+ if tResult := <-tchan; tResult.Err != nil {
+ c.Err = tResult.Err
+ return
+ } else {
+ team = tResult.Data.(*model.Team)
+ }
+
+ team.AllowValet = allowValet
+
+ if result := <-Srv.Store.Team().Update(team); result.Err != nil {
+ c.Err = result.Err
+ return
+ }
+
+ w.Write([]byte(model.MapToJson(props)))
+}
+
+func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) {
+
+ if len(c.Session.TeamId) == 0 {
+ return
+ }
+
+ if result := <-Srv.Store.Team().Get(c.Session.TeamId); result.Err != nil {
+ c.Err = result.Err
+ return
+ } else if HandleEtag(result.Data.(*model.Team).Etag(), w, r) {
+ return
+ } else {
+ w.Header().Set(model.HEADER_ETAG_SERVER, result.Data.(*model.Team).Etag())
+ w.Header().Set("Expires", "-1")
+ w.Write([]byte(result.Data.(*model.Team).ToJson()))
+ return
+ }
+}
diff --git a/api/team_test.go b/api/team_test.go
index 74a184634..042c0a2e9 100644
--- a/api/team_test.go
+++ b/api/team_test.go
@@ -286,3 +286,106 @@ func TestFuzzyTeamCreate(t *testing.T) {
}
}
}
+
+func TestGetMyTeam(t *testing.T) {
+ Setup()
+
+ team := model.Team{Name: "Name", Domain: "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.com", FullName: "Corey Hulen", Password: "pwd"}
+ ruser, _ := Client.CreateUser(&user, "")
+ Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id)
+
+ Client.LoginByEmail(team.Domain, user.Email, user.Password)
+
+ if result, err := Client.GetMyTeam(""); err != nil {
+ t.Fatal("Failed to get user")
+ } else {
+ if result.Data.(*model.Team).Name != team.Name {
+ t.Fatal("team names did not match")
+ }
+ if result.Data.(*model.Team).Domain != team.Domain {
+ t.Fatal("team domains did not match")
+ }
+ if result.Data.(*model.Team).Type != team.Type {
+ t.Fatal("team types did not match")
+ }
+ }
+}
+
+func TestUpdateValetFeature(t *testing.T) {
+ Setup()
+
+ team := &model.Team{Name: "Name", Domain: "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", FullName: "Corey Hulen", Password: "pwd"}
+ user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
+ Srv.Store.User().VerifyEmail(user.Id)
+
+ user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
+ user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
+ Srv.Store.User().VerifyEmail(user2.Id)
+
+ team2 := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
+ team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
+
+ user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
+ user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
+ Srv.Store.User().VerifyEmail(user3.Id)
+
+ Client.LoginByEmail(team.Domain, user2.Email, "pwd")
+
+ data := make(map[string]string)
+ data["allow_valet"] = "true"
+ if _, err := Client.UpdateValetFeature(data); err == nil {
+ t.Fatal("Should have errored, not admin")
+ }
+
+ Client.LoginByEmail(team.Domain, user.Email, "pwd")
+
+ data["allow_valet"] = ""
+ if _, err := Client.UpdateValetFeature(data); err == nil {
+ t.Fatal("Should have errored, empty allow_valet field")
+ }
+
+ data["allow_valet"] = "true"
+ if _, err := Client.UpdateValetFeature(data); err != nil {
+ t.Fatal(err)
+ }
+
+ rteam := Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
+ if rteam.AllowValet != true {
+ t.Fatal("Should have errored - allow valet property not updated")
+ }
+
+ data["team_id"] = "junk"
+ if _, err := Client.UpdateValetFeature(data); err == nil {
+ t.Fatal("Should have errored, junk team id")
+ }
+
+ data["team_id"] = "12345678901234567890123456"
+ if _, err := Client.UpdateValetFeature(data); err == nil {
+ t.Fatal("Should have errored, bad team id")
+ }
+
+ data["team_id"] = team.Id
+ data["allow_valet"] = "false"
+ if _, err := Client.UpdateValetFeature(data); err != nil {
+ t.Fatal(err)
+ }
+
+ rteam = Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
+ if rteam.AllowValet != false {
+ t.Fatal("Should have errored - allow valet property not updated")
+ }
+
+ Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
+
+ data["team_id"] = team.Id
+ data["allow_valet"] = "true"
+ if _, err := Client.UpdateValetFeature(data); err == nil {
+ t.Fatal("Should have errored, not part of team")
+ }
+}
diff --git a/api/user.go b/api/user.go
index 83e29b28e..f8382cf2f 100644
--- a/api/user.go
+++ b/api/user.go
@@ -5,7 +5,6 @@ package api
import (
"bytes"
- "code.google.com/p/draw2d/draw2d"
l4g "code.google.com/p/log4go"
"fmt"
"github.com/goamz/goamz/aws"
@@ -19,6 +18,7 @@ import (
"hash/fnv"
"image"
"image/color"
+ "image/draw"
_ "image/gif"
_ "image/jpeg"
"image/png"
@@ -145,10 +145,6 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
}
func CreateValet(c *Context, team *model.Team) *model.User {
- if !utils.Cfg.TeamSettings.AllowValet {
- return &model.User{}
- }
-
valet := &model.User{}
valet.TeamId = team.Id
valet.Email = utils.Cfg.EmailSettings.FeedbackEmail
@@ -567,7 +563,7 @@ func getAudits(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
-func createProfileImage(username string, userId string) *image.RGBA {
+func createProfileImage(username string, userId string) ([]byte, *model.AppError) {
colors := []color.NRGBA{
{197, 8, 126, 255},
@@ -602,48 +598,20 @@ func createProfileImage(username string, userId string) *image.RGBA {
h.Write([]byte(userId))
seed := h.Sum32()
- initials := ""
- parts := strings.Split(username, " ")
-
- for _, v := range parts {
-
- if len(v) > 0 {
- initials += string(strings.ToUpper(v)[0])
- }
- }
+ color := colors[int(seed)%len(colors)]
+ img := image.NewRGBA(image.Rect(0, 0, int(utils.Cfg.ImageSettings.ProfileWidth), int(utils.Cfg.ImageSettings.ProfileHeight)))
+ draw.Draw(img, img.Bounds(), &image.Uniform{color}, image.ZP, draw.Src)
- if len(initials) == 0 {
- initials = "^"
- }
+ buf := new(bytes.Buffer)
- if len(initials) > 2 {
- initials = initials[0:2]
+ if imgErr := png.Encode(buf, img); imgErr != nil {
+ return nil, model.NewAppError("getProfileImage", "Could not encode default profile image", imgErr.Error())
+ } else {
+ return buf.Bytes(), nil
}
-
- draw2d.SetFontFolder(utils.FindDir("web/static/fonts"))
- i := image.NewRGBA(image.Rect(0, 0, 128, 128))
- gc := draw2d.NewGraphicContext(i)
- draw2d.Rect(gc, 0, 0, 128, 128)
- gc.SetFillColor(colors[int(seed)%len(colors)])
- gc.Fill()
- gc.SetFontSize(50)
- gc.SetFontData(draw2d.FontData{"luxi", draw2d.FontFamilyMono, draw2d.FontStyleBold | draw2d.FontStyleItalic})
- left, top, right, bottom := gc.GetStringBounds("CH")
- width := (128 - (right - left + 10)) / 2
- height := (128 - (top - bottom + 6)) / 2
- gc.Translate(width, height)
- gc.SetFillColor(image.White)
- gc.FillString(initials)
- return i
}
func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
- if !utils.IsS3Configured() {
- c.Err = model.NewAppError("getProfileImage", "Unable to get image. Amazon S3 not configured. ", "")
- c.Err.StatusCode = http.StatusNotImplemented
- return
- }
-
params := mux.Vars(r)
id := params["id"]
@@ -651,36 +619,41 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
c.Err = result.Err
return
} else {
- var auth aws.Auth
- auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
- auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
+ var img []byte
+ var err *model.AppError
- s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
- bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
+ if !utils.IsS3Configured() {
+ img, err = createProfileImage(result.Data.(*model.User).Username, id)
+ if err != nil {
+ c.Err = err
+ return
+ }
+ } else {
+ var auth aws.Auth
+ auth.AccessKey = utils.Cfg.AWSSettings.S3AccessKeyId
+ auth.SecretKey = utils.Cfg.AWSSettings.S3SecretAccessKey
- path := "teams/" + c.Session.TeamId + "/users/" + id + "/profile.png"
+ s := s3.New(auth, aws.Regions[utils.Cfg.AWSSettings.S3Region])
+ bucket := s.Bucket(utils.Cfg.AWSSettings.S3Bucket)
- var img []byte
+ path := "teams/" + c.Session.TeamId + "/users/" + id + "/profile.png"
- if data, getErr := bucket.Get(path); getErr != nil {
- rawImg := createProfileImage(result.Data.(*model.User).Username, id)
- buf := new(bytes.Buffer)
+ if data, getErr := bucket.Get(path); getErr != nil {
+ img, err = createProfileImage(result.Data.(*model.User).Username, id)
+ if err != nil {
+ c.Err = err
+ return
+ }
- if imgErr := png.Encode(buf, rawImg); imgErr != nil {
- c.Err = model.NewAppError("getProfileImage", "Could not encode default profile image", imgErr.Error())
- return
- } else {
- img = buf.Bytes()
- }
+ options := s3.Options{}
+ if err := bucket.Put(path, img, "image", s3.Private, options); err != nil {
+ c.Err = model.NewAppError("getImage", "Couldn't upload default profile image", err.Error())
+ return
+ }
- options := s3.Options{}
- if err := bucket.Put(path, buf.Bytes(), "image", s3.Private, options); err != nil {
- c.Err = model.NewAppError("getImage", "Couldn't upload default profile image", err.Error())
- return
+ } else {
+ img = data
}
-
- } else {
- img = data
}
if c.Session.UserId == id {
diff --git a/api/user_test.go b/api/user_test.go
index 4d5d2b3f0..92ab216aa 100644
--- a/api/user_test.go
+++ b/api/user_test.go
@@ -10,6 +10,7 @@ import (
"github.com/goamz/goamz/s3"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
+ "image"
"image/color"
"io"
"mime/multipart"
@@ -324,14 +325,20 @@ func TestGetAudits(t *testing.T) {
func TestUserCreateImage(t *testing.T) {
Setup()
- i := createProfileImage("Corey Hulen", "eo1zkdr96pdj98pjmq8zy35wba")
- if i == nil {
- t.Fatal("Failed to gen image")
+ b, err := createProfileImage("Corey Hulen", "eo1zkdr96pdj98pjmq8zy35wba")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rdr := bytes.NewReader(b)
+ img, _, err2 := image.Decode(rdr)
+ if err2 != nil {
+ t.Fatal(err)
}
colorful := color.RGBA{116, 49, 196, 255}
- if i.RGBAAt(1, 1) != colorful {
+ if img.At(1, 1) != colorful {
t.Fatal("Failed to create correct color")
}