Move away from the "andForget" style of function (#3046)
This is the second and last part of the refactoring. First part is documented here: https://github.com/mattermost/platform/pull/3043
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
02576f3d59
Коммит
55f6a0b21c
@@ -5,14 +5,15 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
l4g "github.com/alecthomas/log4go"
|
l4g "github.com/alecthomas/log4go"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
"github.com/mattermost/platform/store"
|
"github.com/mattermost/platform/store"
|
||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -154,7 +155,7 @@ func CreateDirectChannel(userId string, otherUserId string) (*model.Channel, *mo
|
|||||||
} else {
|
} else {
|
||||||
message := model.NewMessage("", channel.Id, userId, model.ACTION_DIRECT_ADDED)
|
message := model.NewMessage("", channel.Id, userId, model.ACTION_DIRECT_ADDED)
|
||||||
message.Add("teammate_id", otherUserId)
|
message.Add("teammate_id", otherUserId)
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
|
|
||||||
return result.Data.(*model.Channel), nil
|
return result.Data.(*model.Channel), nil
|
||||||
}
|
}
|
||||||
@@ -291,42 +292,40 @@ func updateChannelHeader(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
c.Err = ucresult.Err
|
c.Err = ucresult.Err
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
PostUpdateChannelHeaderMessageAndForget(c, channel.Id, oldChannelHeader, channelHeader)
|
go PostUpdateChannelHeaderMessage(c, channel.Id, oldChannelHeader, channelHeader)
|
||||||
c.LogAudit("name=" + channel.Name)
|
c.LogAudit("name=" + channel.Name)
|
||||||
w.Write([]byte(channel.ToJson()))
|
w.Write([]byte(channel.ToJson()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostUpdateChannelHeaderMessageAndForget(c *Context, channelId string, oldChannelHeader, newChannelHeader string) {
|
func PostUpdateChannelHeaderMessage(c *Context, channelId string, oldChannelHeader, newChannelHeader string) {
|
||||||
go func() {
|
uc := Srv.Store.User().Get(c.Session.UserId)
|
||||||
uc := Srv.Store.User().Get(c.Session.UserId)
|
|
||||||
|
|
||||||
if uresult := <-uc; uresult.Err != nil {
|
if uresult := <-uc; uresult.Err != nil {
|
||||||
l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.retrieve_user.error"), uresult.Err)
|
l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.retrieve_user.error"), uresult.Err)
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
user := uresult.Data.(*model.User)
|
||||||
|
|
||||||
|
var message string
|
||||||
|
if oldChannelHeader == "" {
|
||||||
|
message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_to"), user.Username, newChannelHeader)
|
||||||
|
} else if newChannelHeader == "" {
|
||||||
|
message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.removed"), user.Username, oldChannelHeader)
|
||||||
} else {
|
} else {
|
||||||
user := uresult.Data.(*model.User)
|
message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_from"), user.Username, oldChannelHeader, newChannelHeader)
|
||||||
|
|
||||||
var message string
|
|
||||||
if oldChannelHeader == "" {
|
|
||||||
message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_to"), user.Username, newChannelHeader)
|
|
||||||
} else if newChannelHeader == "" {
|
|
||||||
message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.removed"), user.Username, oldChannelHeader)
|
|
||||||
} else {
|
|
||||||
message = fmt.Sprintf(utils.T("api.channel.post_update_channel_header_message_and_forget.updated_from"), user.Username, oldChannelHeader, newChannelHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
post := &model.Post{
|
|
||||||
ChannelId: channelId,
|
|
||||||
Message: message,
|
|
||||||
Type: model.POST_HEADER_CHANGE,
|
|
||||||
}
|
|
||||||
if _, err := CreatePost(c, post, false); err != nil {
|
|
||||||
l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.join_leave.error"), err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
post := &model.Post{
|
||||||
|
ChannelId: channelId,
|
||||||
|
Message: message,
|
||||||
|
Type: model.POST_HEADER_CHANGE,
|
||||||
|
}
|
||||||
|
if _, err := CreatePost(c, post, false); err != nil {
|
||||||
|
l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.join_leave.error"), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateChannelPurpose(c *Context, w http.ResponseWriter, r *http.Request) {
|
func updateChannelPurpose(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -490,7 +489,7 @@ func joinChannel(c *Context, channelChannel store.StoreChannel, userChannel stor
|
|||||||
if _, err := AddUserToChannel(user, channel); err != nil {
|
if _, err := AddUserToChannel(user, channel); err != nil {
|
||||||
return err, nil
|
return err, nil
|
||||||
}
|
}
|
||||||
PostUserAddRemoveMessageAndForget(c, channel.Id, fmt.Sprintf(utils.T("api.channel.join_channel.post_and_forget"), user.Username))
|
go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.join_channel.post_and_forget"), user.Username))
|
||||||
} else {
|
} else {
|
||||||
return model.NewLocAppError("join", "api.channel.join_channel.permissions.app_error", nil, ""), nil
|
return model.NewLocAppError("join", "api.channel.join_channel.permissions.app_error", nil, ""), nil
|
||||||
}
|
}
|
||||||
@@ -498,17 +497,15 @@ func joinChannel(c *Context, channelChannel store.StoreChannel, userChannel stor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostUserAddRemoveMessageAndForget(c *Context, channelId string, message string) {
|
func PostUserAddRemoveMessage(c *Context, channelId string, message string) {
|
||||||
go func() {
|
post := &model.Post{
|
||||||
post := &model.Post{
|
ChannelId: channelId,
|
||||||
ChannelId: channelId,
|
Message: message,
|
||||||
Message: message,
|
Type: model.POST_JOIN_LEAVE,
|
||||||
Type: model.POST_JOIN_LEAVE,
|
}
|
||||||
}
|
if _, err := CreatePost(c, post, false); err != nil {
|
||||||
if _, err := CreatePost(c, post, false); err != nil {
|
l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err)
|
||||||
l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err)
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) {
|
func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) {
|
||||||
@@ -539,7 +536,7 @@ func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
|
|||||||
InvalidateCacheForUser(user.Id)
|
InvalidateCacheForUser(user.Id)
|
||||||
|
|
||||||
message := model.NewMessage(channel.TeamId, channel.Id, user.Id, model.ACTION_USER_ADDED)
|
message := model.NewMessage(channel.TeamId, channel.Id, user.Id, model.ACTION_USER_ADDED)
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return newMember, nil
|
return newMember, nil
|
||||||
@@ -627,7 +624,7 @@ func leave(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
RemoveUserFromChannel(c.Session.UserId, c.Session.UserId, channel)
|
RemoveUserFromChannel(c.Session.UserId, c.Session.UserId, channel)
|
||||||
|
|
||||||
PostUserAddRemoveMessageAndForget(c, channel.Id, fmt.Sprintf(utils.T("api.channel.leave.left"), user.Username))
|
go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.leave.left"), user.Username))
|
||||||
|
|
||||||
result := make(map[string]string)
|
result := make(map[string]string)
|
||||||
result["id"] = channel.Id
|
result["id"] = channel.Id
|
||||||
@@ -722,7 +719,7 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
go func() {
|
go func() {
|
||||||
InvalidateCacheForChannel(channel.Id)
|
InvalidateCacheForChannel(channel.Id)
|
||||||
message := model.NewMessage(c.TeamId, channel.Id, c.Session.UserId, model.ACTION_CHANNEL_DELETED)
|
message := model.NewMessage(c.TeamId, channel.Id, c.Session.UserId, model.ACTION_CHANNEL_DELETED)
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
|
|
||||||
post := &model.Post{
|
post := &model.Post{
|
||||||
ChannelId: channel.Id,
|
ChannelId: channel.Id,
|
||||||
@@ -758,7 +755,7 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
message := model.NewMessage(c.TeamId, id, c.Session.UserId, model.ACTION_CHANNEL_VIEWED)
|
message := model.NewMessage(c.TeamId, id, c.Session.UserId, model.ACTION_CHANNEL_VIEWED)
|
||||||
message.Add("channel_id", id)
|
message.Add("channel_id", id)
|
||||||
|
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
|
|
||||||
result := make(map[string]string)
|
result := make(map[string]string)
|
||||||
result["id"] = id
|
result["id"] = id
|
||||||
@@ -907,7 +904,7 @@ func addMember(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
c.LogAudit("name=" + channel.Name + " user_id=" + userId)
|
c.LogAudit("name=" + channel.Name + " user_id=" + userId)
|
||||||
|
|
||||||
PostUserAddRemoveMessageAndForget(c, channel.Id, fmt.Sprintf(utils.T("api.channel.add_member.added"), nUser.Username, oUser.Username))
|
go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.add_member.added"), nUser.Username, oUser.Username))
|
||||||
|
|
||||||
<-Srv.Store.Channel().UpdateLastViewedAt(id, oUser.Id)
|
<-Srv.Store.Channel().UpdateLastViewedAt(id, oUser.Id)
|
||||||
w.Write([]byte(cm.ToJson()))
|
w.Write([]byte(cm.ToJson()))
|
||||||
@@ -978,7 +975,7 @@ func RemoveUserFromChannel(userIdToRemove string, removerUserId string, channel
|
|||||||
|
|
||||||
message := model.NewMessage(channel.TeamId, channel.Id, userIdToRemove, model.ACTION_USER_REMOVED)
|
message := model.NewMessage(channel.TeamId, channel.Id, userIdToRemove, model.ACTION_USER_REMOVED)
|
||||||
message.Add("remover_id", removerUserId)
|
message.Add("remover_id", removerUserId)
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
224
api/file.go
224
api/file.go
@@ -6,16 +6,6 @@ package api
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
l4g "github.com/alecthomas/log4go"
|
|
||||||
"github.com/disintegration/imaging"
|
|
||||||
"github.com/goamz/goamz/aws"
|
|
||||||
"github.com/goamz/goamz/s3"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/mattermost/platform/model"
|
|
||||||
"github.com/mattermost/platform/utils"
|
|
||||||
"github.com/mssola/user_agent"
|
|
||||||
"github.com/rwcarlsen/goexif/exif"
|
|
||||||
_ "golang.org/x/image/bmp"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
@@ -30,6 +20,17 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
l4g "github.com/alecthomas/log4go"
|
||||||
|
"github.com/disintegration/imaging"
|
||||||
|
"github.com/goamz/goamz/aws"
|
||||||
|
"github.com/goamz/goamz/s3"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/mattermost/platform/model"
|
||||||
|
"github.com/mattermost/platform/utils"
|
||||||
|
"github.com/mssola/user_agent"
|
||||||
|
"github.com/rwcarlsen/goexif/exif"
|
||||||
|
_ "golang.org/x/image/bmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -165,110 +166,107 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
resStruct.ClientIds = append(resStruct.ClientIds, clientId)
|
resStruct.ClientIds = append(resStruct.ClientIds, clientId)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleImagesAndForget(imageNameList, imageDataList, c.TeamId, channelId, c.Session.UserId)
|
go handleImages(imageNameList, imageDataList, c.TeamId, channelId, c.Session.UserId)
|
||||||
|
|
||||||
w.Write([]byte(resStruct.ToJson()))
|
w.Write([]byte(resStruct.ToJson()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleImagesAndForget(filenames []string, fileData [][]byte, teamId, channelId, userId string) {
|
func handleImages(filenames []string, fileData [][]byte, teamId, channelId, userId string) {
|
||||||
|
dest := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/"
|
||||||
|
|
||||||
go func() {
|
for i, filename := range filenames {
|
||||||
dest := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/"
|
name := filename[:strings.LastIndex(filename, ".")]
|
||||||
|
go func() {
|
||||||
|
// Decode image bytes into Image object
|
||||||
|
img, imgType, err := image.Decode(bytes.NewReader(fileData[i]))
|
||||||
|
if err != nil {
|
||||||
|
l4g.Error(utils.T("api.file.handle_images_forget.decode.error"), channelId, userId, filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for i, filename := range filenames {
|
width := img.Bounds().Dx()
|
||||||
name := filename[:strings.LastIndex(filename, ".")]
|
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])
|
||||||
|
|
||||||
|
if imgType == "png" {
|
||||||
|
dst := image.NewRGBA(img.Bounds())
|
||||||
|
draw.Draw(dst, dst.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src)
|
||||||
|
draw.Draw(dst, dst.Bounds(), img, img.Bounds().Min, draw.Over)
|
||||||
|
img = dst
|
||||||
|
}
|
||||||
|
|
||||||
|
switch orientation {
|
||||||
|
case UprightMirrored:
|
||||||
|
img = imaging.FlipH(img)
|
||||||
|
case UpsideDown:
|
||||||
|
img = imaging.Rotate180(img)
|
||||||
|
case UpsideDownMirrored:
|
||||||
|
img = imaging.FlipV(img)
|
||||||
|
case RotatedCWMirrored:
|
||||||
|
img = imaging.Transpose(img)
|
||||||
|
case RotatedCCW:
|
||||||
|
img = imaging.Rotate270(img)
|
||||||
|
case RotatedCCWMirrored:
|
||||||
|
img = imaging.Transverse(img)
|
||||||
|
case RotatedCW:
|
||||||
|
img = imaging.Rotate90(img)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create thumbnail
|
||||||
go func() {
|
go func() {
|
||||||
// Decode image bytes into Image object
|
thumbWidth := float64(utils.Cfg.FileSettings.ThumbnailWidth)
|
||||||
img, imgType, err := image.Decode(bytes.NewReader(fileData[i]))
|
thumbHeight := float64(utils.Cfg.FileSettings.ThumbnailHeight)
|
||||||
|
imgWidth := float64(width)
|
||||||
|
imgHeight := float64(height)
|
||||||
|
|
||||||
|
var thumbnail image.Image
|
||||||
|
if imgHeight < thumbHeight && imgWidth < thumbWidth {
|
||||||
|
thumbnail = img
|
||||||
|
} else if imgHeight/imgWidth < thumbHeight/thumbWidth {
|
||||||
|
thumbnail = imaging.Resize(img, 0, utils.Cfg.FileSettings.ThumbnailHeight, imaging.Lanczos)
|
||||||
|
} else {
|
||||||
|
thumbnail = imaging.Resize(img, utils.Cfg.FileSettings.ThumbnailWidth, 0, imaging.Lanczos)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err = jpeg.Encode(buf, thumbnail, &jpeg.Options{Quality: 90})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l4g.Error(utils.T("api.file.handle_images_forget.decode.error"), channelId, userId, filename, err)
|
l4g.Error(utils.T("api.file.handle_images_forget.encode_jpeg.error"), channelId, userId, filename, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
width := img.Bounds().Dx()
|
if err := WriteFile(buf.Bytes(), dest+name+"_thumb.jpg"); err != nil {
|
||||||
height := img.Bounds().Dy()
|
l4g.Error(utils.T("api.file.handle_images_forget.upload_thumb.error"), channelId, userId, filename, err)
|
||||||
|
return
|
||||||
// Get the image's orientation and ignore any errors since not all images will have orientation data
|
|
||||||
orientation, _ := getImageOrientation(fileData[i])
|
|
||||||
|
|
||||||
if imgType == "png" {
|
|
||||||
dst := image.NewRGBA(img.Bounds())
|
|
||||||
draw.Draw(dst, dst.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src)
|
|
||||||
draw.Draw(dst, dst.Bounds(), img, img.Bounds().Min, draw.Over)
|
|
||||||
img = dst
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch orientation {
|
|
||||||
case UprightMirrored:
|
|
||||||
img = imaging.FlipH(img)
|
|
||||||
case UpsideDown:
|
|
||||||
img = imaging.Rotate180(img)
|
|
||||||
case UpsideDownMirrored:
|
|
||||||
img = imaging.FlipV(img)
|
|
||||||
case RotatedCWMirrored:
|
|
||||||
img = imaging.Transpose(img)
|
|
||||||
case RotatedCCW:
|
|
||||||
img = imaging.Rotate270(img)
|
|
||||||
case RotatedCCWMirrored:
|
|
||||||
img = imaging.Transverse(img)
|
|
||||||
case RotatedCW:
|
|
||||||
img = imaging.Rotate90(img)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create thumbnail
|
|
||||||
go func() {
|
|
||||||
thumbWidth := float64(utils.Cfg.FileSettings.ThumbnailWidth)
|
|
||||||
thumbHeight := float64(utils.Cfg.FileSettings.ThumbnailHeight)
|
|
||||||
imgWidth := float64(width)
|
|
||||||
imgHeight := float64(height)
|
|
||||||
|
|
||||||
var thumbnail image.Image
|
|
||||||
if imgHeight < thumbHeight && imgWidth < thumbWidth {
|
|
||||||
thumbnail = img
|
|
||||||
} else if imgHeight/imgWidth < thumbHeight/thumbWidth {
|
|
||||||
thumbnail = imaging.Resize(img, 0, utils.Cfg.FileSettings.ThumbnailHeight, imaging.Lanczos)
|
|
||||||
} else {
|
|
||||||
thumbnail = imaging.Resize(img, utils.Cfg.FileSettings.ThumbnailWidth, 0, imaging.Lanczos)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
err = jpeg.Encode(buf, thumbnail, &jpeg.Options{Quality: 90})
|
|
||||||
if err != nil {
|
|
||||||
l4g.Error(utils.T("api.file.handle_images_forget.encode_jpeg.error"), channelId, userId, filename, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := WriteFile(buf.Bytes(), dest+name+"_thumb.jpg"); err != nil {
|
|
||||||
l4g.Error(utils.T("api.file.handle_images_forget.upload_thumb.error"), channelId, userId, filename, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Create preview
|
|
||||||
go func() {
|
|
||||||
var preview image.Image
|
|
||||||
if width > int(utils.Cfg.FileSettings.PreviewWidth) {
|
|
||||||
preview = imaging.Resize(img, utils.Cfg.FileSettings.PreviewWidth, utils.Cfg.FileSettings.PreviewHeight, imaging.Lanczos)
|
|
||||||
} else {
|
|
||||||
preview = img
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
err = jpeg.Encode(buf, preview, &jpeg.Options{Quality: 90})
|
|
||||||
if err != nil {
|
|
||||||
l4g.Error(utils.T("api.file.handle_images_forget.encode_preview.error"), channelId, userId, filename, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := WriteFile(buf.Bytes(), dest+name+"_preview.jpg"); err != nil {
|
|
||||||
l4g.Error(utils.T("api.file.handle_images_forget.upload_preview.error"), channelId, userId, filename, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}()
|
}()
|
||||||
}
|
|
||||||
}()
|
// Create preview
|
||||||
|
go func() {
|
||||||
|
var preview image.Image
|
||||||
|
if width > int(utils.Cfg.FileSettings.PreviewWidth) {
|
||||||
|
preview = imaging.Resize(img, utils.Cfg.FileSettings.PreviewWidth, utils.Cfg.FileSettings.PreviewHeight, imaging.Lanczos)
|
||||||
|
} else {
|
||||||
|
preview = img
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
err = jpeg.Encode(buf, preview, &jpeg.Options{Quality: 90})
|
||||||
|
if err != nil {
|
||||||
|
l4g.Error(utils.T("api.file.handle_images_forget.encode_preview.error"), channelId, userId, filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := WriteFile(buf.Bytes(), dest+name+"_preview.jpg"); err != nil {
|
||||||
|
l4g.Error(utils.T("api.file.handle_images_forget.upload_preview.error"), channelId, userId, filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getImageOrientation(imageData []byte) (int, error) {
|
func getImageOrientation(imageData []byte) (int, error) {
|
||||||
@@ -329,7 +327,7 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
info = cached.(*model.FileInfo)
|
info = cached.(*model.FileInfo)
|
||||||
} else {
|
} else {
|
||||||
fileData := make(chan []byte)
|
fileData := make(chan []byte)
|
||||||
getFileAndForget(path, fileData)
|
go readFile(path, fileData)
|
||||||
|
|
||||||
newInfo, err := model.GetInfoForBytes(filename, <-fileData)
|
newInfo, err := model.GetInfoForBytes(filename, <-fileData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -435,7 +433,7 @@ func getFileData(teamId string, channelId string, userId string, filename string
|
|||||||
path := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
|
path := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
|
||||||
|
|
||||||
fileChan := make(chan []byte)
|
fileChan := make(chan []byte)
|
||||||
getFileAndForget(path, fileChan)
|
go readFile(path, fileChan)
|
||||||
|
|
||||||
if bytes := <-fileChan; bytes == nil {
|
if bytes := <-fileChan; bytes == nil {
|
||||||
err := model.NewLocAppError("writeFileResponse", "api.file.get_file.not_found.app_error", nil, "path="+path)
|
err := model.NewLocAppError("writeFileResponse", "api.file.get_file.not_found.app_error", nil, "path="+path)
|
||||||
@@ -472,16 +470,14 @@ func writeFileResponse(filename string, bytes []byte, w http.ResponseWriter, r *
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileAndForget(path string, fileData chan []byte) {
|
func readFile(path string, fileData chan []byte) {
|
||||||
go func() {
|
data, getErr := ReadFile(path)
|
||||||
data, getErr := ReadFile(path)
|
if getErr != nil {
|
||||||
if getErr != nil {
|
l4g.Error(getErr)
|
||||||
l4g.Error(getErr)
|
fileData <- nil
|
||||||
fileData <- nil
|
} else {
|
||||||
} else {
|
fileData <- data
|
||||||
fileData <- data
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -588,7 +584,7 @@ func WriteFile(f []byte, path string) *model.AppError {
|
|||||||
func MoveFile(oldPath, newPath string) *model.AppError {
|
func MoveFile(oldPath, newPath string) *model.AppError {
|
||||||
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
|
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
|
||||||
fileData := make(chan []byte)
|
fileData := make(chan []byte)
|
||||||
getFileAndForget(oldPath, fileData)
|
go readFile(oldPath, fileData)
|
||||||
fileBytes := <-fileData
|
fileBytes := <-fileData
|
||||||
|
|
||||||
if fileBytes == nil {
|
if fileBytes == nil {
|
||||||
|
|||||||
359
api/post.go
359
api/post.go
@@ -6,11 +6,6 @@ package api
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
l4g "github.com/alecthomas/log4go"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/mattermost/platform/model"
|
|
||||||
"github.com/mattermost/platform/store"
|
|
||||||
"github.com/mattermost/platform/utils"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -20,6 +15,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
l4g "github.com/alecthomas/log4go"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/mattermost/platform/model"
|
||||||
|
"github.com/mattermost/platform/store"
|
||||||
|
"github.com/mattermost/platform/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitPost() {
|
func InitPost() {
|
||||||
@@ -147,8 +148,7 @@ func CreatePost(c *Context, post *model.Post, triggerWebhooks bool) (*model.Post
|
|||||||
} else {
|
} else {
|
||||||
rpost = result.Data.(*model.Post)
|
rpost = result.Data.(*model.Post)
|
||||||
|
|
||||||
handlePostEventsAndForget(c, rpost, triggerWebhooks)
|
go handlePostEvents(c, rpost, triggerWebhooks)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpost, nil
|
return rpost, nil
|
||||||
@@ -227,76 +227,74 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc
|
|||||||
return post, nil
|
return post, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePostEventsAndForget(c *Context, post *model.Post, triggerWebhooks bool) {
|
func handlePostEvents(c *Context, post *model.Post, triggerWebhooks bool) {
|
||||||
go func() {
|
tchan := Srv.Store.Team().Get(c.TeamId)
|
||||||
tchan := Srv.Store.Team().Get(c.TeamId)
|
cchan := Srv.Store.Channel().Get(post.ChannelId)
|
||||||
cchan := Srv.Store.Channel().Get(post.ChannelId)
|
uchan := Srv.Store.User().Get(post.UserId)
|
||||||
uchan := Srv.Store.User().Get(post.UserId)
|
pchan := Srv.Store.User().GetProfiles(c.TeamId)
|
||||||
pchan := Srv.Store.User().GetProfiles(c.TeamId)
|
dpchan := Srv.Store.User().GetDirectProfiles(c.Session.UserId)
|
||||||
dpchan := Srv.Store.User().GetDirectProfiles(c.Session.UserId)
|
mchan := Srv.Store.Channel().GetMembers(post.ChannelId)
|
||||||
mchan := Srv.Store.Channel().GetMembers(post.ChannelId)
|
|
||||||
|
|
||||||
var team *model.Team
|
var team *model.Team
|
||||||
if result := <-tchan; result.Err != nil {
|
if result := <-tchan; result.Err != nil {
|
||||||
l4g.Error(utils.T("api.post.handle_post_events_and_forget.team.error"), c.TeamId, result.Err)
|
l4g.Error(utils.T("api.post.handle_post_events_and_forget.team.error"), c.TeamId, result.Err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
team = result.Data.(*model.Team)
|
team = result.Data.(*model.Team)
|
||||||
|
}
|
||||||
|
|
||||||
|
var channel *model.Channel
|
||||||
|
if result := <-cchan; result.Err != nil {
|
||||||
|
l4g.Error(utils.T("api.post.handle_post_events_and_forget.channel.error"), post.ChannelId, result.Err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
channel = result.Data.(*model.Channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
var profiles map[string]*model.User
|
||||||
|
if result := <-pchan; result.Err != nil {
|
||||||
|
l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
profiles = result.Data.(map[string]*model.User)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-dpchan; result.Err != nil {
|
||||||
|
l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
dps := result.Data.(map[string]*model.User)
|
||||||
|
for k, v := range dps {
|
||||||
|
profiles[k] = v
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var channel *model.Channel
|
var members []model.ChannelMember
|
||||||
if result := <-cchan; result.Err != nil {
|
if result := <-mchan; result.Err != nil {
|
||||||
l4g.Error(utils.T("api.post.handle_post_events_and_forget.channel.error"), post.ChannelId, result.Err)
|
l4g.Error(utils.T("api.post.handle_post_events_and_forget.members.error"), post.ChannelId, result.Err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
channel = result.Data.(*model.Channel)
|
members = result.Data.([]model.ChannelMember)
|
||||||
}
|
}
|
||||||
|
|
||||||
var profiles map[string]*model.User
|
go sendNotifications(c, post, team, channel, profiles, members)
|
||||||
if result := <-pchan; result.Err != nil {
|
go checkForOutOfChannelMentions(c, post, channel, profiles, members)
|
||||||
l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
profiles = result.Data.(map[string]*model.User)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result := <-dpchan; result.Err != nil {
|
var user *model.User
|
||||||
l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err)
|
if result := <-uchan; result.Err != nil {
|
||||||
return
|
l4g.Error(utils.T("api.post.handle_post_events_and_forget.user.error"), post.UserId, result.Err)
|
||||||
} else {
|
return
|
||||||
dps := result.Data.(map[string]*model.User)
|
} else {
|
||||||
for k, v := range dps {
|
user = result.Data.(*model.User)
|
||||||
profiles[k] = v
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var members []model.ChannelMember
|
if triggerWebhooks {
|
||||||
if result := <-mchan; result.Err != nil {
|
go handleWebhookEvents(c, post, team, channel, user)
|
||||||
l4g.Error(utils.T("api.post.handle_post_events_and_forget.members.error"), post.ChannelId, result.Err)
|
}
|
||||||
return
|
|
||||||
} else {
|
|
||||||
members = result.Data.([]model.ChannelMember)
|
|
||||||
}
|
|
||||||
|
|
||||||
go sendNotifications(c, post, team, channel, profiles, members)
|
if channel.Type == model.CHANNEL_DIRECT {
|
||||||
go checkForOutOfChannelMentions(c, post, channel, profiles, members)
|
go makeDirectChannelVisible(c.TeamId, post.ChannelId)
|
||||||
|
}
|
||||||
var user *model.User
|
|
||||||
if result := <-uchan; result.Err != nil {
|
|
||||||
l4g.Error(utils.T("api.post.handle_post_events_and_forget.user.error"), post.UserId, result.Err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
user = result.Data.(*model.User)
|
|
||||||
}
|
|
||||||
|
|
||||||
if triggerWebhooks {
|
|
||||||
handleWebhookEventsAndForget(c, post, team, channel, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
if channel.Type == model.CHANNEL_DIRECT {
|
|
||||||
go makeDirectChannelVisible(c.TeamId, post.ChannelId)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDirectChannelVisible(teamId string, channelId string) {
|
func makeDirectChannelVisible(teamId string, channelId string) {
|
||||||
@@ -332,7 +330,7 @@ func makeDirectChannelVisible(teamId string, channelId string) {
|
|||||||
message := model.NewMessage(teamId, channelId, member.UserId, model.ACTION_PREFERENCE_CHANGED)
|
message := model.NewMessage(teamId, channelId, member.UserId, model.ACTION_PREFERENCE_CHANGED)
|
||||||
message.Add("preference", preference.ToJson())
|
message.Add("preference", preference.ToJson())
|
||||||
|
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
preference := result.Data.(model.Preference)
|
preference := result.Data.(model.Preference)
|
||||||
@@ -347,127 +345,123 @@ func makeDirectChannelVisible(teamId string, channelId string) {
|
|||||||
message := model.NewMessage(teamId, channelId, member.UserId, model.ACTION_PREFERENCE_CHANGED)
|
message := model.NewMessage(teamId, channelId, member.UserId, model.ACTION_PREFERENCE_CHANGED)
|
||||||
message.Add("preference", preference.ToJson())
|
message.Add("preference", preference.ToJson())
|
||||||
|
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team, channel *model.Channel, user *model.User) {
|
func handleWebhookEvents(c *Context, post *model.Post, team *model.Team, channel *model.Channel, user *model.User) {
|
||||||
go func() {
|
if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
|
||||||
if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
|
return
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if channel.Type != model.CHANNEL_OPEN {
|
if channel.Type != model.CHANNEL_OPEN {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hchan := Srv.Store.Webhook().GetOutgoingByTeam(c.TeamId)
|
hchan := Srv.Store.Webhook().GetOutgoingByTeam(c.TeamId)
|
||||||
|
|
||||||
hooks := []*model.OutgoingWebhook{}
|
hooks := []*model.OutgoingWebhook{}
|
||||||
|
|
||||||
if result := <-hchan; result.Err != nil {
|
if result := <-hchan; result.Err != nil {
|
||||||
l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.getting.error"), result.Err)
|
l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.getting.error"), result.Err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
hooks = result.Data.([]*model.OutgoingWebhook)
|
hooks = result.Data.([]*model.OutgoingWebhook)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hooks) == 0 {
|
if len(hooks) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
splitWords := strings.Fields(post.Message)
|
splitWords := strings.Fields(post.Message)
|
||||||
|
|
||||||
if len(splitWords) == 0 {
|
if len(splitWords) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
firstWord := splitWords[0]
|
firstWord := splitWords[0]
|
||||||
|
|
||||||
relevantHooks := []*model.OutgoingWebhook{}
|
relevantHooks := []*model.OutgoingWebhook{}
|
||||||
|
|
||||||
for _, hook := range hooks {
|
for _, hook := range hooks {
|
||||||
if hook.ChannelId == post.ChannelId {
|
if hook.ChannelId == post.ChannelId {
|
||||||
if len(hook.TriggerWords) == 0 || hook.HasTriggerWord(firstWord) {
|
if len(hook.TriggerWords) == 0 || hook.HasTriggerWord(firstWord) {
|
||||||
relevantHooks = append(relevantHooks, hook)
|
|
||||||
}
|
|
||||||
} else if len(hook.ChannelId) == 0 && hook.HasTriggerWord(firstWord) {
|
|
||||||
relevantHooks = append(relevantHooks, hook)
|
relevantHooks = append(relevantHooks, hook)
|
||||||
}
|
}
|
||||||
|
} else if len(hook.ChannelId) == 0 && hook.HasTriggerWord(firstWord) {
|
||||||
|
relevantHooks = append(relevantHooks, hook)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, hook := range relevantHooks {
|
for _, hook := range relevantHooks {
|
||||||
go func(hook *model.OutgoingWebhook) {
|
go func(hook *model.OutgoingWebhook) {
|
||||||
p := url.Values{}
|
p := url.Values{}
|
||||||
p.Set("token", hook.Token)
|
p.Set("token", hook.Token)
|
||||||
|
|
||||||
p.Set("team_id", hook.TeamId)
|
p.Set("team_id", hook.TeamId)
|
||||||
p.Set("team_domain", team.Name)
|
p.Set("team_domain", team.Name)
|
||||||
|
|
||||||
p.Set("channel_id", post.ChannelId)
|
p.Set("channel_id", post.ChannelId)
|
||||||
p.Set("channel_name", channel.Name)
|
p.Set("channel_name", channel.Name)
|
||||||
|
|
||||||
p.Set("timestamp", strconv.FormatInt(post.CreateAt/1000, 10))
|
p.Set("timestamp", strconv.FormatInt(post.CreateAt/1000, 10))
|
||||||
|
|
||||||
p.Set("user_id", post.UserId)
|
p.Set("user_id", post.UserId)
|
||||||
p.Set("user_name", user.Username)
|
p.Set("user_name", user.Username)
|
||||||
|
|
||||||
p.Set("text", post.Message)
|
p.Set("text", post.Message)
|
||||||
p.Set("trigger_word", firstWord)
|
p.Set("trigger_word", firstWord)
|
||||||
|
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
|
||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
|
|
||||||
for _, url := range hook.CallbackURLs {
|
for _, url := range hook.CallbackURLs {
|
||||||
go func(url string) {
|
go func(url string) {
|
||||||
req, _ := http.NewRequest("POST", url, strings.NewReader(p.Encode()))
|
req, _ := http.NewRequest("POST", url, strings.NewReader(p.Encode()))
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
req.Header.Set("Accept", "application/json")
|
req.Header.Set("Accept", "application/json")
|
||||||
if resp, err := client.Do(req); err != nil {
|
if resp, err := client.Do(req); err != nil {
|
||||||
l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.event_post.error"), err.Error())
|
l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.event_post.error"), err.Error())
|
||||||
} else {
|
} else {
|
||||||
respProps := model.MapFromJson(resp.Body)
|
respProps := model.MapFromJson(resp.Body)
|
||||||
|
|
||||||
// copy the context and create a mock session for posting the message
|
// copy the context and create a mock session for posting the message
|
||||||
mockSession := model.Session{
|
mockSession := model.Session{
|
||||||
UserId: hook.CreatorId,
|
UserId: hook.CreatorId,
|
||||||
TeamMembers: []*model.TeamMember{{TeamId: hook.TeamId, UserId: hook.CreatorId}},
|
TeamMembers: []*model.TeamMember{{TeamId: hook.TeamId, UserId: hook.CreatorId}},
|
||||||
IsOAuth: false,
|
IsOAuth: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
newContext := &Context{
|
newContext := &Context{
|
||||||
Session: mockSession,
|
Session: mockSession,
|
||||||
RequestId: model.NewId(),
|
RequestId: model.NewId(),
|
||||||
IpAddress: "",
|
IpAddress: "",
|
||||||
Path: c.Path,
|
Path: c.Path,
|
||||||
Err: nil,
|
Err: nil,
|
||||||
teamURLValid: c.teamURLValid,
|
teamURLValid: c.teamURLValid,
|
||||||
teamURL: c.teamURL,
|
teamURL: c.teamURL,
|
||||||
siteURL: c.siteURL,
|
siteURL: c.siteURL,
|
||||||
T: c.T,
|
T: c.T,
|
||||||
Locale: c.Locale,
|
Locale: c.Locale,
|
||||||
TeamId: hook.TeamId,
|
TeamId: hook.TeamId,
|
||||||
}
|
}
|
||||||
|
|
||||||
if text, ok := respProps["text"]; ok {
|
if text, ok := respProps["text"]; ok {
|
||||||
if _, err := CreateWebhookPost(newContext, post.ChannelId, text, respProps["username"], respProps["icon_url"], post.Props, post.Type); err != nil {
|
if _, err := CreateWebhookPost(newContext, post.ChannelId, text, respProps["username"], respProps["icon_url"], post.Props, post.Type); err != nil {
|
||||||
l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.create_post.error"), err)
|
l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.create_post.error"), err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(url)
|
}
|
||||||
}
|
}(url)
|
||||||
|
}
|
||||||
}(hook)
|
|
||||||
}
|
|
||||||
|
|
||||||
}()
|
|
||||||
|
|
||||||
|
}(hook)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *model.Channel, profileMap map[string]*model.User, members []model.ChannelMember) {
|
func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *model.Channel, profileMap map[string]*model.User, members []model.ChannelMember) {
|
||||||
@@ -595,7 +589,7 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
|
|||||||
}
|
}
|
||||||
|
|
||||||
for id := range toEmailMap {
|
for id := range toEmailMap {
|
||||||
updateMentionCountAndForget(post.ChannelId, id)
|
go updateMentionCount(post.ChannelId, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,15 +773,13 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
|
|||||||
message.Add("mentions", model.ArrayToJson(mentionedUsers))
|
message.Add("mentions", model.ArrayToJson(mentionedUsers))
|
||||||
}
|
}
|
||||||
|
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMentionCountAndForget(channelId, userId string) {
|
func updateMentionCount(channelId, userId string) {
|
||||||
go func() {
|
if result := <-Srv.Store.Channel().IncrementMentionCount(channelId, userId); result.Err != nil {
|
||||||
if result := <-Srv.Store.Channel().IncrementMentionCount(channelId, userId); result.Err != nil {
|
l4g.Error(utils.T("api.post.update_mention_count_and_forget.update_error"), userId, channelId, result.Err)
|
||||||
l4g.Error(utils.T("api.post.update_mention_count_and_forget.update_error"), userId, channelId, result.Err)
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkForOutOfChannelMentions(c *Context, post *model.Post, channel *model.Channel, allProfiles map[string]*model.User, members []model.ChannelMember) {
|
func checkForOutOfChannelMentions(c *Context, post *model.Post, channel *model.Channel, allProfiles map[string]*model.User, members []model.ChannelMember) {
|
||||||
@@ -876,7 +868,7 @@ func SendEphemeralPost(teamId, userId string, post *model.Post) {
|
|||||||
message := model.NewMessage(teamId, post.ChannelId, userId, model.ACTION_EPHEMERAL_MESSAGE)
|
message := model.NewMessage(teamId, post.ChannelId, userId, model.ACTION_EPHEMERAL_MESSAGE)
|
||||||
message.Add("post", post.ToJson())
|
message.Add("post", post.ToJson())
|
||||||
|
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -938,7 +930,7 @@ func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
message := model.NewMessage(c.TeamId, rpost.ChannelId, c.Session.UserId, model.ACTION_POST_EDITED)
|
message := model.NewMessage(c.TeamId, rpost.ChannelId, c.Session.UserId, model.ACTION_POST_EDITED)
|
||||||
message.Add("post", rpost.ToJson())
|
message.Add("post", rpost.ToJson())
|
||||||
|
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
|
|
||||||
w.Write([]byte(rpost.ToJson()))
|
w.Write([]byte(rpost.ToJson()))
|
||||||
}
|
}
|
||||||
@@ -1202,8 +1194,8 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
message := model.NewMessage(c.TeamId, post.ChannelId, c.Session.UserId, model.ACTION_POST_DELETED)
|
message := model.NewMessage(c.TeamId, post.ChannelId, c.Session.UserId, model.ACTION_POST_DELETED)
|
||||||
message.Add("post", post.ToJson())
|
message.Add("post", post.ToJson())
|
||||||
|
|
||||||
PublishAndForget(message)
|
go Publish(message)
|
||||||
DeletePostFilesAndForget(c.TeamId, post)
|
go DeletePostFiles(c.TeamId, post)
|
||||||
|
|
||||||
result := make(map[string]string)
|
result := make(map[string]string)
|
||||||
result["id"] = postId
|
result["id"] = postId
|
||||||
@@ -1211,21 +1203,18 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeletePostFilesAndForget(teamId string, post *model.Post) {
|
func DeletePostFiles(teamId string, post *model.Post) {
|
||||||
go func() {
|
if len(post.Filenames) == 0 {
|
||||||
if len(post.Filenames) == 0 {
|
return
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
prefix := "teams/" + teamId + "/channels/" + post.ChannelId + "/users/" + post.UserId + "/"
|
prefix := "teams/" + teamId + "/channels/" + post.ChannelId + "/users/" + post.UserId + "/"
|
||||||
for _, filename := range post.Filenames {
|
for _, filename := range post.Filenames {
|
||||||
splitUrl := strings.Split(filename, "/")
|
splitUrl := strings.Split(filename, "/")
|
||||||
oldPath := prefix + splitUrl[len(splitUrl)-2] + "/" + splitUrl[len(splitUrl)-1]
|
oldPath := prefix + splitUrl[len(splitUrl)-2] + "/" + splitUrl[len(splitUrl)-1]
|
||||||
newPath := prefix + splitUrl[len(splitUrl)-2] + "/deleted_" + splitUrl[len(splitUrl)-1]
|
newPath := prefix + splitUrl[len(splitUrl)-2] + "/deleted_" + splitUrl[len(splitUrl)-1]
|
||||||
MoveFile(oldPath, newPath)
|
MoveFile(oldPath, newPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPostsBefore(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getPostsBefore(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
|
|||||||
InvalidateCacheForUser(user.Id)
|
InvalidateCacheForUser(user.Id)
|
||||||
|
|
||||||
// This message goes to every channel, so the channelId is irrelevant
|
// This message goes to every channel, so the channelId is irrelevant
|
||||||
PublishAndForget(model.NewMessage("", "", user.Id, model.ACTION_NEW_USER))
|
go Publish(model.NewMessage("", "", user.Id, model.ACTION_NEW_USER))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ func CreateUser(user *model.User) (*model.User, *model.AppError) {
|
|||||||
ruser.Sanitize(map[string]bool{})
|
ruser.Sanitize(map[string]bool{})
|
||||||
|
|
||||||
// This message goes to every channel, so the channelId is irrelevant
|
// This message goes to every channel, so the channelId is irrelevant
|
||||||
PublishAndForget(model.NewMessage("", "", ruser.Id, model.ACTION_NEW_USER))
|
go Publish(model.NewMessage("", "", ruser.Id, model.ACTION_NEW_USER))
|
||||||
|
|
||||||
return ruser, nil
|
return ruser, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
l4g "github.com/alecthomas/log4go"
|
l4g "github.com/alecthomas/log4go"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -77,7 +78,7 @@ func (c *WebConn) readPump() {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
msg.UserId = c.UserId
|
msg.UserId = c.UserId
|
||||||
PublishAndForget(&msg)
|
go Publish(&msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,8 @@ var hub = &Hub{
|
|||||||
invalidateChannel: make(chan string),
|
invalidateChannel: make(chan string),
|
||||||
}
|
}
|
||||||
|
|
||||||
func PublishAndForget(message *model.Message) {
|
func Publish(message *model.Message) {
|
||||||
go func() {
|
hub.Broadcast(message)
|
||||||
hub.Broadcast(message)
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func InvalidateCacheForUser(userId string) {
|
func InvalidateCacheForUser(userId string) {
|
||||||
|
|||||||
140
mattermost.go
140
mattermost.go
@@ -121,7 +121,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setDiagnosticId()
|
setDiagnosticId()
|
||||||
runSecurityAndDiagnosticsJobAndForget()
|
go runSecurityAndDiagnosticsJob()
|
||||||
|
|
||||||
if einterfaces.GetComplianceInterface() != nil {
|
if einterfaces.GetComplianceInterface() != nil {
|
||||||
einterfaces.GetComplianceInterface().StartComplianceDailyJob()
|
einterfaces.GetComplianceInterface().StartComplianceDailyJob()
|
||||||
@@ -152,96 +152,94 @@ func setDiagnosticId() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSecurityAndDiagnosticsJobAndForget() {
|
func runSecurityAndDiagnosticsJob() {
|
||||||
go func() {
|
for {
|
||||||
for {
|
if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert {
|
||||||
if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert {
|
if result := <-api.Srv.Store.System().Get(); result.Err == nil {
|
||||||
if result := <-api.Srv.Store.System().Get(); result.Err == nil {
|
props := result.Data.(model.StringMap)
|
||||||
props := result.Data.(model.StringMap)
|
lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0)
|
||||||
lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0)
|
currentTime := model.GetMillis()
|
||||||
currentTime := model.GetMillis()
|
|
||||||
|
|
||||||
if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
|
if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
|
||||||
l4g.Debug(utils.T("mattermost.security_checks.debug"))
|
l4g.Debug(utils.T("mattermost.security_checks.debug"))
|
||||||
|
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
|
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
|
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
|
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
|
v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
|
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
|
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)
|
v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)
|
||||||
|
|
||||||
if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 {
|
if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 {
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1")
|
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1")
|
||||||
} else {
|
} else {
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0")
|
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)}
|
systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)}
|
||||||
if lastSecurityTime == 0 {
|
if lastSecurityTime == 0 {
|
||||||
<-api.Srv.Store.System().Save(systemSecurityLastTime)
|
<-api.Srv.Store.System().Save(systemSecurityLastTime)
|
||||||
} else {
|
} else {
|
||||||
<-api.Srv.Store.System().Update(systemSecurityLastTime)
|
<-api.Srv.Store.System().Update(systemSecurityLastTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
|
if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ucr := <-api.Srv.Store.User().GetTotalActiveUsersCount(); ucr.Err == nil {
|
if ucr := <-api.Srv.Store.User().GetTotalActiveUsersCount(); ucr.Err == nil {
|
||||||
v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
|
res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l4g.Error(utils.T("mattermost.security_info.error"))
|
l4g.Error(utils.T("mattermost.security_info.error"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bulletins := model.SecurityBulletinsFromJson(res.Body)
|
bulletins := model.SecurityBulletinsFromJson(res.Body)
|
||||||
|
|
||||||
for _, bulletin := range bulletins {
|
for _, bulletin := range bulletins {
|
||||||
if bulletin.AppliesToVersion == model.CurrentVersion {
|
if bulletin.AppliesToVersion == model.CurrentVersion {
|
||||||
if props["SecurityBulletin_"+bulletin.Id] == "" {
|
if props["SecurityBulletin_"+bulletin.Id] == "" {
|
||||||
if results := <-api.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
|
if results := <-api.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
|
||||||
l4g.Error(utils.T("mattermost.system_admins.error"))
|
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(utils.T("mattermost.security_bulletin.error"))
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
users := results.Data.(map[string]*model.User)
|
|
||||||
|
|
||||||
resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id)
|
|
||||||
if err != nil {
|
|
||||||
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(utils.T("mattermost.security_bulletin_read.error"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email)
|
|
||||||
utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
|
body, err := ioutil.ReadAll(resBody.Body)
|
||||||
<-api.Srv.Store.System().Save(bulletinSeen)
|
res.Body.Close()
|
||||||
|
if err != nil || resBody.StatusCode != 200 {
|
||||||
|
l4g.Error(utils.T("mattermost.security_bulletin_read.error"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email)
|
||||||
|
utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
|
||||||
|
<-api.Srv.Store.System().Save(bulletinSeen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(time.Hour * 4)
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
time.Sleep(time.Hour * 4)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCmds() {
|
func parseCmds() {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user