summaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/admin.go46
-rw-r--r--api/admin_test.go82
-rw-r--r--api/channel_test.go4
-rw-r--r--api/command.go6
-rw-r--r--api/context.go2
-rw-r--r--api/file.go97
6 files changed, 218 insertions, 19 deletions
diff --git a/api/admin.go b/api/admin.go
index 6d7a9028f..646597755 100644
--- a/api/admin.go
+++ b/api/admin.go
@@ -7,6 +7,7 @@ import (
"bufio"
"net/http"
"os"
+ "strings"
l4g "code.google.com/p/log4go"
"github.com/gorilla/mux"
@@ -20,6 +21,8 @@ func InitAdmin(r *mux.Router) {
sr := r.PathPrefix("/admin").Subrouter()
sr.Handle("/logs", ApiUserRequired(getLogs)).Methods("GET")
+ sr.Handle("/config", ApiUserRequired(getConfig)).Methods("GET")
+ sr.Handle("/save_config", ApiUserRequired(saveConfig)).Methods("POST")
sr.Handle("/client_props", ApiAppHandler(getClientProperties)).Methods("GET")
}
@@ -33,7 +36,7 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
if utils.Cfg.LogSettings.FileEnable {
- file, err := os.Open(utils.Cfg.LogSettings.FileLocation)
+ file, err := os.Open(utils.GetLogFileLocation(utils.Cfg.LogSettings.FileLocation))
if err != nil {
c.Err = model.NewAppError("getLogs", "Error reading log file", err.Error())
}
@@ -54,3 +57,44 @@ func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
func getClientProperties(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.MapToJson(utils.ClientProperties)))
}
+
+func getConfig(c *Context, w http.ResponseWriter, r *http.Request) {
+ if !c.HasSystemAdminPermissions("getConfig") {
+ return
+ }
+
+ json := utils.Cfg.ToJson()
+ cfg := model.ConfigFromJson(strings.NewReader(json))
+ json = cfg.ToJson()
+
+ w.Write([]byte(json))
+}
+
+func saveConfig(c *Context, w http.ResponseWriter, r *http.Request) {
+ if !c.HasSystemAdminPermissions("getConfig") {
+ return
+ }
+
+ cfg := model.ConfigFromJson(r.Body)
+ if cfg == nil {
+ c.SetInvalidParam("saveConfig", "config")
+ return
+ }
+
+ if len(cfg.ServiceSettings.Port) == 0 {
+ c.SetInvalidParam("saveConfig", "config")
+ return
+ }
+
+ if cfg.TeamSettings.MaxUsersPerTeam == 0 {
+ c.SetInvalidParam("saveConfig", "config")
+ return
+ }
+
+ // TODO run some cleanup validators
+
+ utils.SaveConfig(utils.CfgFileName, cfg)
+ utils.LoadConfig(utils.CfgFileName)
+ json := utils.Cfg.ToJson()
+ w.Write([]byte(json))
+}
diff --git a/api/admin_test.go b/api/admin_test.go
index e67077c55..e1778b5ac 100644
--- a/api/admin_test.go
+++ b/api/admin_test.go
@@ -8,6 +8,7 @@ import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
+ "github.com/mattermost/platform/utils"
)
func TestGetLogs(t *testing.T) {
@@ -20,6 +21,12 @@ func TestGetLogs(t *testing.T) {
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
+ Client.LoginByEmail(team.Name, user.Email, "pwd")
+
+ if _, err := Client.GetLogs(); err == nil {
+ t.Fatal("Shouldn't have permissions")
+ }
+
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
@@ -37,8 +44,81 @@ func TestGetLogs(t *testing.T) {
func TestGetClientProperties(t *testing.T) {
Setup()
- if _, err := Client.GetClientProperties(); err != nil {
+ if result, err := Client.GetClientProperties(); err != nil {
+ t.Fatal(err)
+ } else {
+ props := result.Data.(map[string]string)
+
+ if len(props["Version"]) == 0 {
+ t.Fatal()
+ }
+ }
+}
+
+func TestGetConfig(t *testing.T) {
+ Setup()
+
+ team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
+ team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
+
+ user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
+ user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
+ store.Must(Srv.Store.User().VerifyEmail(user.Id))
+
+ Client.LoginByEmail(team.Name, user.Email, "pwd")
+
+ if _, err := Client.GetConfig(); 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.GetConfig(); err != nil {
+ t.Fatal(err)
+ } else {
+ cfg := result.Data.(*model.Config)
+
+ if len(cfg.ServiceSettings.SiteName) == 0 {
+ t.Fatal()
+ }
+ }
+}
+
+func TestSaveConfig(t *testing.T) {
+ Setup()
+
+ team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
+ team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
+ user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
+ user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
+ store.Must(Srv.Store.User().VerifyEmail(user.Id))
+
+ Client.LoginByEmail(team.Name, user.Email, "pwd")
+
+ if _, err := Client.SaveConfig(utils.Cfg); err == nil {
+ t.Fatal("Shouldn't have permissions")
+ }
+
+ c := &Context{}
+ c.RequestId = model.NewId()
+ c.IpAddress = "cmd_line"
+ UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
+
+ Client.LoginByEmail(team.Name, user.Email, "pwd")
+
+ if result, err := Client.SaveConfig(utils.Cfg); err != nil {
t.Fatal(err)
+ } else {
+ cfg := result.Data.(*model.Config)
+
+ if len(cfg.ServiceSettings.SiteName) == 0 {
+ t.Fatal()
+ }
}
}
diff --git a/api/channel_test.go b/api/channel_test.go
index 7e9267192..14bfe1cf7 100644
--- a/api/channel_test.go
+++ b/api/channel_test.go
@@ -57,7 +57,7 @@ func TestCreateChannel(t *testing.T) {
rchannel.Data.(*model.Channel).Id = ""
if _, err := Client.CreateChannel(rchannel.Data.(*model.Channel)); err != nil {
- if err.Message != "A channel with that handle already exists" {
+ if err.Message != "A channel with that URL already exists" {
t.Fatal(err)
}
}
@@ -68,7 +68,7 @@ func TestCreateChannel(t *testing.T) {
Client.DeleteChannel(savedId)
if _, err := Client.CreateChannel(rchannel.Data.(*model.Channel)); err != nil {
- if err.Message != "A channel with that handle was previously created" {
+ if err.Message != "A channel with that URL was previously created" {
t.Fatal(err)
}
}
diff --git a/api/command.go b/api/command.go
index be1d3229b..bc55f206b 100644
--- a/api/command.go
+++ b/api/command.go
@@ -341,7 +341,7 @@ func loadTestSetupCommand(c *Context, command *model.Command) bool {
}
}
} else {
- client.MockSession(c.Session.Id)
+ client.MockSession(c.Session.Token)
CreateTestEnviromentInTeam(
client,
c.Session.TeamId,
@@ -406,7 +406,7 @@ func loadTestChannelsCommand(c *Context, command *model.Command) bool {
channelsr = utils.Range{20, 30}
}
client := model.NewClient(c.GetSiteURL())
- client.MockSession(c.Session.Id)
+ client.MockSession(c.Session.Token)
channelCreator := NewAutoChannelCreator(client, c.Session.TeamId)
channelCreator.Fuzzy = doFuzz
channelCreator.CreateTestChannels(channelsr)
@@ -458,7 +458,7 @@ func loadTestPostsCommand(c *Context, command *model.Command) bool {
}
client := model.NewClient(c.GetSiteURL())
- client.MockSession(c.Session.Id)
+ client.MockSession(c.Session.Token)
testPoster := NewAutoPostCreator(client, command.ChannelId)
testPoster.Fuzzy = doFuzz
testPoster.Users = usernames
diff --git a/api/context.go b/api/context.go
index 5925c817f..02716bb33 100644
--- a/api/context.go
+++ b/api/context.go
@@ -125,7 +125,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.setSiteURL(protocol + "://" + r.Host)
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
- w.Header().Set(model.HEADER_VERSION_ID, utils.Cfg.ServiceSettings.Version+fmt.Sprintf(".%v", utils.CfgLastModified))
+ w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v", model.CurrentVersion, utils.CfgLastModified))
// Instruct the browser not to display us in an iframe for anti-clickjacking
if !h.isApi {
diff --git a/api/file.go b/api/file.go
index f249b3d9e..3602b5ed4 100644
--- a/api/file.go
+++ b/api/file.go
@@ -5,6 +5,7 @@ package api
import (
"bytes"
+ "code.google.com/p/graphics-go/graphics"
l4g "code.google.com/p/log4go"
"fmt"
"github.com/goamz/goamz/aws"
@@ -13,6 +14,7 @@ import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"github.com/nfnt/resize"
+ "github.com/rwcarlsen/goexif/exif"
_ "golang.org/x/image/bmp"
"image"
"image/color"
@@ -21,6 +23,7 @@ import (
"image/jpeg"
"io"
"io/ioutil"
+ "math"
"mime"
"net/http"
"net/url"
@@ -31,6 +34,27 @@ import (
"time"
)
+const (
+ /*
+ EXIF Image Orientations
+ 1 2 3 4 5 6 7 8
+
+ 888888 888888 88 88 8888888888 88 88 8888888888
+ 88 88 88 88 88 88 88 88 88 88 88 88
+ 8888 8888 8888 8888 88 8888888888 8888888888 88
+ 88 88 88 88
+ 88 88 888888 888888
+ */
+ Upright = 1
+ UprightMirrored = 2
+ UpsideDown = 3
+ UpsideDownMirrored = 4
+ RotatedCWMirrored = 5
+ RotatedCCW = 6
+ RotatedCCWMirrored = 7
+ RotatedCW = 8
+)
+
var fileInfoCache *utils.Cache = utils.NewLru(1000)
func InitFile(r *mux.Router) {
@@ -144,25 +168,59 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
return
}
- // Decode image config
- imgConfig, _, err := image.DecodeConfig(bytes.NewReader(fileData[i]))
- if err != nil {
- l4g.Error("Unable to decode image config channelId=%v userId=%v filename=%v err=%v", channelId, userId, filename, err)
- return
+ width := img.Bounds().Dx()
+ height := img.Bounds().Dy()
+
+ // Get the image's orientation and ignore any errors since not all images will have orientation data
+ orientation, _ := getImageOrientation(fileData[i])
+
+ // Create a temporary image that will be manipulated and then used to make the thumbnail and preview image
+ var temp *image.RGBA
+ switch orientation {
+ case Upright, UprightMirrored, UpsideDown, UpsideDownMirrored:
+ temp = image.NewRGBA(img.Bounds())
+ case RotatedCCW, RotatedCCWMirrored, RotatedCW, RotatedCWMirrored:
+ bounds := img.Bounds()
+ temp = image.NewRGBA(image.Rect(bounds.Min.Y, bounds.Min.X, bounds.Max.Y, bounds.Max.X))
+
+ width, height = height, width
}
- // Remove transparency due to JPEG's lack of support of it
- temp := image.NewRGBA(img.Bounds())
+ // Draw a white background since JPEGs lack transparency
draw.Draw(temp, temp.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src)
- draw.Draw(temp, temp.Bounds(), img, img.Bounds().Min, draw.Over)
+
+ // Copy the original image onto the temporary one while rotating it as necessary
+ switch orientation {
+ case UpsideDown, UpsideDownMirrored:
+ // rotate 180 degrees
+ err := graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: math.Pi})
+ if err != nil {
+ l4g.Error("Unable to rotate image")
+ }
+ case RotatedCW, RotatedCWMirrored:
+ // rotate 90 degrees CCW
+ graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: 3 * math.Pi / 2})
+ if err != nil {
+ l4g.Error("Unable to rotate image")
+ }
+ case RotatedCCW, RotatedCCWMirrored:
+ // rotate 90 degrees CW
+ graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: math.Pi / 2})
+ if err != nil {
+ l4g.Error("Unable to rotate image")
+ }
+ case Upright, UprightMirrored:
+ draw.Draw(temp, temp.Bounds(), img, img.Bounds().Min, draw.Over)
+ }
+
img = temp
// Create thumbnail
go func() {
thumbWidth := float64(utils.Cfg.ImageSettings.ThumbnailWidth)
thumbHeight := float64(utils.Cfg.ImageSettings.ThumbnailHeight)
- imgWidth := float64(imgConfig.Width)
- imgHeight := float64(imgConfig.Height)
+ imgWidth := float64(width)
+ imgHeight := float64(height)
var thumbnail image.Image
if imgHeight < thumbHeight && imgWidth < thumbWidth {
@@ -189,7 +247,7 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
// Create preview
go func() {
var preview image.Image
- if imgConfig.Width > int(utils.Cfg.ImageSettings.PreviewWidth) {
+ if width > int(utils.Cfg.ImageSettings.PreviewWidth) {
preview = resize.Resize(utils.Cfg.ImageSettings.PreviewWidth, utils.Cfg.ImageSettings.PreviewHeight, img, resize.Lanczos3)
} else {
preview = img
@@ -213,6 +271,23 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch
}()
}
+func getImageOrientation(imageData []byte) (int, error) {
+ if exifData, err := exif.Decode(bytes.NewReader(imageData)); err != nil {
+ return Upright, err
+ } else {
+ if tag, err := exifData.Get("Orientation"); err != nil {
+ return Upright, err
+ } else {
+ orientation, err := tag.Int(0)
+ if err != nil {
+ return Upright, err
+ } else {
+ return orientation, nil
+ }
+ }
+ }
+}
+
type ImageGetResult struct {
Error error
ImageData []byte