Refactor and migrate more functions out of api into app package (#5063)

Этот коммит содержится в:
Joram Wilander
2017-01-13 15:17:50 -05:00
коммит произвёл Harrison Healey
родитель 97558f6a6e
Коммит 0e2b321e6f
33 изменённых файлов: 1673 добавлений и 1399 удалений

Просмотреть файл

@@ -665,7 +665,7 @@ func adminResetMfa(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if err := DeactivateMfa(userId); err != nil {
if err := app.DeactivateMfa(userId); err != nil {
c.Err = err
return
}

Просмотреть файл

@@ -119,7 +119,7 @@ func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if sc, err := CreateDirectChannel(c.Session.UserId, userId); err != nil {
if sc, err := app.CreateDirectChannel(c.Session.UserId, userId); err != nil {
c.Err = err
return
} else {
@@ -127,33 +127,6 @@ func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
func CreateDirectChannel(userId string, otherUserId string) (*model.Channel, *model.AppError) {
uc := app.Srv.Store.User().Get(otherUserId)
if uresult := <-uc; uresult.Err != nil {
return nil, model.NewLocAppError("CreateDirectChannel", "api.channel.create_direct_channel.invalid_user.app_error", nil, otherUserId)
}
if result := <-app.Srv.Store.Channel().CreateDirectChannel(userId, otherUserId); result.Err != nil {
if result.Err.Id == store.CHANNEL_EXISTS_ERROR {
return result.Data.(*model.Channel), nil
} else {
return nil, result.Err
}
} else {
channel := result.Data.(*model.Channel)
app.InvalidateCacheForUser(userId)
app.InvalidateCacheForUser(otherUserId)
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_DIRECT_ADDED, "", channel.Id, "", nil)
message.Add("teammate_id", otherUserId)
go app.Publish(message)
return channel, nil
}
}
func CanManageChannel(c *Context, channel *model.Channel) bool {
if channel.Type == model.CHANNEL_OPEN && !HasPermissionToChannelContext(c, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES) {
return false
@@ -229,7 +202,9 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
} else {
if oldChannelDisplayName != channel.DisplayName {
go PostUpdateChannelDisplayNameMessage(c, channel.Id, oldChannelDisplayName, channel.DisplayName)
if err := app.PostUpdateChannelDisplayNameMessage(c.Session.UserId, channel.Id, c.TeamId, oldChannelDisplayName, channel.DisplayName); err != nil {
l4g.Error(err.Error())
}
}
c.LogAudit("name=" + channel.Name)
w.Write([]byte(oldChannel.ToJson()))
@@ -277,76 +252,15 @@ func updateChannelHeader(c *Context, w http.ResponseWriter, r *http.Request) {
c.Err = ucresult.Err
return
} else {
go PostUpdateChannelHeaderMessage(c, channel.Id, oldChannelHeader, channelHeader)
if err := app.PostUpdateChannelHeaderMessage(c.Session.UserId, channel.Id, c.TeamId, oldChannelHeader, channelHeader); err != nil {
l4g.Error(err.Error())
}
c.LogAudit("name=" + channel.Name)
w.Write([]byte(channel.ToJson()))
}
}
}
func PostUpdateChannelHeaderMessage(c *Context, channelId string, oldChannelHeader, newChannelHeader string) {
uc := app.Srv.Store.User().Get(c.Session.UserId)
if uresult := <-uc; uresult.Err != nil {
l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.retrieve_user.error"), uresult.Err)
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 {
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,
UserId: c.Session.UserId,
Props: model.StringInterface{
"old_header": oldChannelHeader,
"new_header": newChannelHeader,
},
}
if _, err := app.CreatePost(post, c.TeamId, false); err != nil {
l4g.Error(utils.T("api.channel.post_update_channel_header_message_and_forget.join_leave.error"), err)
}
}
}
func PostUpdateChannelDisplayNameMessage(c *Context, channelId string, oldChannelDisplayName, newChannelDisplayName string) {
uc := app.Srv.Store.User().Get(c.Session.UserId)
if uresult := <-uc; uresult.Err != nil {
l4g.Error(utils.T("api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error"), uresult.Err)
return
} else {
user := uresult.Data.(*model.User)
message := fmt.Sprintf(utils.T("api.channel.post_update_channel_displayname_message_and_forget.updated_from"), user.Username, oldChannelDisplayName, newChannelDisplayName)
post := &model.Post{
ChannelId: channelId,
Message: message,
Type: model.POST_DISPLAYNAME_CHANGE,
UserId: c.Session.UserId,
Props: model.StringInterface{
"old_displayname": oldChannelDisplayName,
"new_displayname": newChannelDisplayName,
},
}
if _, err := app.CreatePost(post, c.TeamId, false); err != nil {
l4g.Error(utils.T("api.channel.post_update_channel_displayname_message_and_forget.create_post.error"), err)
}
}
}
func updateChannelPurpose(c *Context, w http.ResponseWriter, r *http.Request) {
props := model.MapFromJson(r.Body)
channelId := props["channel_id"]
@@ -473,84 +387,34 @@ func join(c *Context, w http.ResponseWriter, r *http.Request) {
channelId := params["channel_id"]
channelName := params["channel_name"]
var outChannel *model.Channel = nil
var channel *model.Channel
var err *model.AppError
if channelId != "" {
if err, channel := JoinChannelById(c, c.Session.UserId, channelId); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusForbidden
return
} else {
outChannel = channel
}
channel, err = app.GetChannel(channelId)
} else if channelName != "" {
if err, channel := JoinChannelByName(c, c.Session.UserId, c.TeamId, channelName); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusForbidden
return
} else {
outChannel = channel
}
channel, err = app.GetChannelByName(channelName, c.TeamId)
} else {
c.SetInvalidParam("join", "channel_id, channel_name")
return
}
w.Write([]byte(outChannel.ToJson()))
}
func JoinChannelByName(c *Context, userId string, teamId string, channelName string) (*model.AppError, *model.Channel) {
channelChannel := app.Srv.Store.Channel().GetByName(teamId, channelName)
userChannel := app.Srv.Store.User().Get(userId)
return joinChannel(c, channelChannel, userChannel)
}
func JoinChannelById(c *Context, userId string, channelId string) (*model.AppError, *model.Channel) {
channelChannel := app.Srv.Store.Channel().Get(channelId, true)
userChannel := app.Srv.Store.User().Get(userId)
return joinChannel(c, channelChannel, userChannel)
}
func joinChannel(c *Context, channelChannel store.StoreChannel, userChannel store.StoreChannel) (*model.AppError, *model.Channel) {
if cresult := <-channelChannel; cresult.Err != nil {
return cresult.Err, nil
} else if uresult := <-userChannel; uresult.Err != nil {
return uresult.Err, nil
} else {
channel := cresult.Data.(*model.Channel)
user := uresult.Data.(*model.User)
if mresult := <-app.Srv.Store.Channel().GetMember(channel.Id, user.Id); mresult.Err == nil && mresult.Data != nil {
// the user is already in the channel so just return successful
return nil, channel
}
if err != nil {
c.Err = err
return
}
if channel.Type == model.CHANNEL_OPEN {
if !HasPermissionToTeamContext(c, channel.TeamId, model.PERMISSION_JOIN_PUBLIC_CHANNELS) {
return c.Err, nil
return
}
}
if channel.Type == model.CHANNEL_OPEN {
if _, err := app.AddUserToChannel(user, channel); err != nil {
return err, nil
}
go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.join_channel.post_and_forget"), user.Username), model.POST_JOIN_LEAVE)
} else {
return model.NewLocAppError("join", "api.channel.join_channel.permissions.app_error", nil, ""), nil
}
return nil, channel
if err = app.JoinChannel(channel, c.Session.UserId); err != nil {
c.Err = err
return
}
}
func PostUserAddRemoveMessage(c *Context, channelId string, message, postType string) {
post := &model.Post{
ChannelId: channelId,
Message: message,
Type: postType,
UserId: c.Session.UserId,
}
if _, err := app.CreatePost(post, c.TeamId, false); err != nil {
l4g.Error(utils.T("api.channel.post_user_add_remove_message_and_forget.error"), err)
}
w.Write([]byte(channel.ToJson()))
}
func leave(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -601,7 +465,7 @@ func leave(c *Context, w http.ResponseWriter, r *http.Request) {
RemoveUserFromChannel(c.Session.UserId, c.Session.UserId, channel)
go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.leave.left"), user.Username), model.POST_JOIN_LEAVE)
go app.PostUserAddRemoveMessage(c.Session.UserId, channel.Id, channel.TeamId, fmt.Sprintf(utils.T("api.channel.leave.left"), user.Username), model.POST_JOIN_LEAVE)
result := make(map[string]string)
result["id"] = channel.Id
@@ -902,7 +766,7 @@ func addMember(c *Context, w http.ResponseWriter, r *http.Request) {
c.LogAudit("name=" + channel.Name + " user_id=" + userId)
go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.add_member.added"), nUser.Username, oUser.Username), model.POST_ADD_REMOVE)
go app.PostUserAddRemoveMessage(c.Session.UserId, channel.Id, channel.TeamId, fmt.Sprintf(utils.T("api.channel.add_member.added"), nUser.Username, oUser.Username), model.POST_ADD_REMOVE)
<-app.Srv.Store.Channel().UpdateLastViewedAt([]string{id}, oUser.Id)
w.Write([]byte(cm.ToJson()))
@@ -956,7 +820,7 @@ func removeMember(c *Context, w http.ResponseWriter, r *http.Request) {
c.LogAudit("name=" + channel.Name + " user_id=" + userIdToRemove)
go PostUserAddRemoveMessage(c, channel.Id, fmt.Sprintf(utils.T("api.channel.remove_member.removed"), oUser.Username), model.POST_ADD_REMOVE)
go app.PostUserAddRemoveMessage(c.Session.UserId, channel.Id, channel.TeamId, fmt.Sprintf(utils.T("api.channel.remove_member.removed"), oUser.Username), model.POST_ADD_REMOVE)
result := make(map[string]string)
result["channel_id"] = channel.Id

Просмотреть файл

@@ -45,7 +45,7 @@ func (me *JoinProvider) DoCommand(c *Context, args *model.CommandArgs, message s
return &model.CommandResponse{Text: c.T("api.command_join.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}
if err, _ := JoinChannelById(c, c.Session.UserId, channel.Id); err != nil {
if err := app.JoinChannel(channel, c.Session.UserId); err != nil {
return &model.CommandResponse{Text: c.T("api.command_join.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}

Просмотреть файл

@@ -4,6 +4,7 @@
package api
import (
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
)
@@ -38,8 +39,7 @@ func (me *LogoutProvider) DoCommand(c *Context, args *model.CommandArgs, message
// We can't actually remove the user's cookie from here so we just dump their session and let the browser figure it out
if c.Session.Id != "" {
RevokeSessionById(c, c.Session.Id)
if c.Err != nil {
if err := app.RevokeSessionById(c.Session.Id); err != nil {
return FAIL
}
return SUCCESS

Просмотреть файл

@@ -66,7 +66,7 @@ func (me *msgProvider) DoCommand(c *Context, args *model.CommandArgs, message st
targetChannelId := ""
if channel := <-app.Srv.Store.Channel().GetByName(c.TeamId, channelName); channel.Err != nil {
if channel.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
if directChannel, err := CreateDirectChannel(c.Session.UserId, userProfile.Id); err != nil {
if directChannel, err := app.CreateDirectChannel(c.Session.UserId, userProfile.Id); err != nil {
c.Err = err
return &model.CommandResponse{Text: c.T("api.command_msg.dm_fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} else {

Просмотреть файл

@@ -469,7 +469,7 @@ func (c *Context) CheckTeamId() {
return
}
} else {
// just return because it fail on the HasPermissionToContext and the error is already on the Context c.Err
// HasPermissionToContext automatically fills the Context error
return
}
}

Просмотреть файл

@@ -163,7 +163,7 @@ func uploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppErro
if err := gif.EncodeAll(newbuf, resized_gif); err != nil {
return model.NewLocAppError("uploadEmojiImage", "api.emoji.upload.large_image.gif_encode_error", nil, "")
}
if err := WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil {
if err := app.WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil {
return err
}
}
@@ -175,13 +175,13 @@ func uploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppErro
if err := png.Encode(newbuf, resized_image); err != nil {
return model.NewLocAppError("uploadEmojiImage", "api.emoji.upload.large_image.encode_error", nil, "")
}
if err := WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil {
if err := app.WriteFile(newbuf.Bytes(), getEmojiImagePath(id)); err != nil {
return err
}
}
}
} else {
if err := WriteFile(buf.Bytes(), getEmojiImagePath(id)); err != nil {
if err := app.WriteFile(buf.Bytes(), getEmojiImagePath(id)); err != nil {
return err
}
}
@@ -236,7 +236,7 @@ func deleteEmoji(c *Context, w http.ResponseWriter, r *http.Request) {
}
func deleteEmojiImage(id string) {
if err := MoveFile(getEmojiImagePath(id), "emoji/"+id+"/image_deleted"); err != nil {
if err := app.MoveFile(getEmojiImagePath(id), "emoji/"+id+"/image_deleted"); err != nil {
l4g.Error("Failed to rename image when deleting emoji %v", id)
}
}
@@ -275,7 +275,7 @@ func getEmojiImage(c *Context, w http.ResponseWriter, r *http.Request) {
} else {
var img []byte
if data, err := ReadFile(getEmojiImagePath(id)); err != nil {
if data, err := app.ReadFile(getEmojiImagePath(id)); err != nil {
c.Err = model.NewLocAppError("getEmojiImage", "api.emoji.get_image.read.app_error", nil, err.Error())
return
} else {

Просмотреть файл

@@ -317,7 +317,7 @@ func createTestPng(t *testing.T, width int, height int) []byte {
func createTestEmoji(t *testing.T, emoji *model.Emoji, imageData []byte) *model.Emoji {
emoji = store.Must(app.Srv.Store.Emoji().Save(emoji)).(*model.Emoji)
if err := WriteFile(imageData, "emoji/"+emoji.Id+"/image"); err != nil {
if err := app.WriteFile(imageData, "emoji/"+emoji.Id+"/image"); err != nil {
store.Must(app.Srv.Store.Emoji().Delete(emoji.Id, time.Now().Unix()))
t.Fatalf("failed to write image: %v", err.Error())
}

Просмотреть файл

@@ -5,24 +5,17 @@ package api
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"fmt"
"image"
"image/color"
"image/draw"
_ "image/gif"
"image/jpeg"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
l4g "github.com/alecthomas/log4go"
"github.com/disintegration/imaging"
@@ -32,8 +25,6 @@ import (
"github.com/mattermost/platform/utils"
"github.com/rwcarlsen/goexif/exif"
_ "golang.org/x/image/bmp"
s3 "github.com/minio/minio-go"
)
const (
@@ -182,7 +173,7 @@ func doUploadFile(teamId string, channelId string, userId string, rawFilename st
info.ThumbnailPath = pathPrefix + nameWithoutExtension + "_thumb.jpg"
}
if err := WriteFile(data, info.Path); err != nil {
if err := app.WriteFile(data, info.Path); err != nil {
return nil, err
}
@@ -285,7 +276,7 @@ func generateThumbnailImage(img image.Image, thumbnailPath string, width int, he
return
}
if err := WriteFile(buf.Bytes(), thumbnailPath); err != nil {
if err := app.WriteFile(buf.Bytes(), thumbnailPath); err != nil {
l4g.Error(utils.T("api.file.handle_images_forget.upload_thumb.error"), thumbnailPath, err)
return
}
@@ -306,7 +297,7 @@ func generatePreviewImage(img image.Image, previewPath string, width int) {
return
}
if err := WriteFile(buf.Bytes(), previewPath); err != nil {
if err := app.WriteFile(buf.Bytes(), previewPath); err != nil {
l4g.Error(utils.T("api.file.handle_images_forget.upload_preview.error"), previewPath, err)
return
}
@@ -319,7 +310,7 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if data, err := ReadFile(info.Path); err != nil {
if data, err := app.ReadFile(info.Path); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusNotFound
} else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil {
@@ -341,7 +332,7 @@ func getFileThumbnail(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if data, err := ReadFile(info.ThumbnailPath); err != nil {
if data, err := app.ReadFile(info.ThumbnailPath); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusNotFound
} else if err := writeFileResponse(info.Name, "", data, w, r); err != nil {
@@ -363,7 +354,7 @@ func getFilePreview(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if data, err := ReadFile(info.PreviewPath); err != nil {
if data, err := app.ReadFile(info.PreviewPath); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusNotFound
} else if err := writeFileResponse(info.Name, "", data, w, r); err != nil {
@@ -400,7 +391,7 @@ func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) {
hash := r.URL.Query().Get("h")
if len(hash) > 0 {
correctHash := generatePublicLinkHash(info.Id, *utils.Cfg.FileSettings.PublicLinkSalt)
correctHash := app.GeneratePublicLinkHash(info.Id, *utils.Cfg.FileSettings.PublicLinkSalt)
if hash != correctHash {
c.Err = model.NewLocAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "")
@@ -413,7 +404,7 @@ func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if data, err := ReadFile(info.Path); err != nil {
if data, err := app.ReadFile(info.Path); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusNotFound
} else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil {
@@ -482,7 +473,7 @@ func getPublicFileOld(c *Context, w http.ResponseWriter, r *http.Request) {
hash := r.URL.Query().Get("h")
if len(hash) > 0 {
correctHash := generatePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt)
correctHash := app.GeneratePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt)
if hash != correctHash {
c.Err = model.NewLocAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "")
@@ -511,7 +502,7 @@ func getPublicFileOld(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if data, err := ReadFile(info.Path); err != nil {
if data, err := app.ReadFile(info.Path); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusNotFound
} else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil {
@@ -560,320 +551,5 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
w.Write([]byte(model.StringToJson(generatePublicLink(c.GetSiteURL(), info))))
}
func generatePublicLink(siteURL string, info *model.FileInfo) string {
hash := generatePublicLinkHash(info.Id, *utils.Cfg.FileSettings.PublicLinkSalt)
return fmt.Sprintf("%s%s/public/files/%v/get?h=%s", siteURL, model.API_URL_SUFFIX, info.Id, hash)
}
func generatePublicLinkHash(fileId, salt string) string {
hash := sha256.New()
hash.Write([]byte(salt))
hash.Write([]byte(fileId))
return base64.RawURLEncoding.EncodeToString(hash.Sum(nil))
}
var fileMigrationLock sync.Mutex
// Creates and stores FileInfos for a post created before the FileInfos table existed.
func migrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo {
if len(post.Filenames) == 0 {
l4g.Warn(utils.T("api.file.migrate_filenames_to_file_infos.no_filenames.warn"), post.Id)
return []*model.FileInfo{}
}
cchan := app.Srv.Store.Channel().Get(post.ChannelId, true)
// There's a weird bug that rarely happens where a post ends up with duplicate Filenames so remove those
filenames := utils.RemoveDuplicatesFromStringArray(post.Filenames)
var channel *model.Channel
if result := <-cchan; result.Err != nil {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.channel.app_error"), post.Id, post.ChannelId, result.Err)
return []*model.FileInfo{}
} else {
channel = result.Data.(*model.Channel)
}
// Find the team that was used to make this post since its part of the file path that isn't saved in the Filename
var teamId string
if channel.TeamId == "" {
// This post was made in a cross-team DM channel so we need to find where its files were saved
teamId = findTeamIdForFilename(post, filenames[0])
} else {
teamId = channel.TeamId
}
// Create FileInfo objects for this post
infos := make([]*model.FileInfo, 0, len(filenames))
if teamId == "" {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.team_id.error"), post.Id, filenames)
} else {
for _, filename := range filenames {
info := getInfoForFilename(post, teamId, filename)
if info == nil {
continue
}
infos = append(infos, info)
}
}
// Lock to prevent only one migration thread from trying to update the post at once, preventing duplicate FileInfos from being created
fileMigrationLock.Lock()
defer fileMigrationLock.Unlock()
if result := <-app.Srv.Store.Post().Get(post.Id); result.Err != nil {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.get_post_again.app_error"), post.Id, result.Err)
return []*model.FileInfo{}
} else if newPost := result.Data.(*model.PostList).Posts[post.Id]; len(newPost.Filenames) != len(post.Filenames) {
// Another thread has already created FileInfos for this post, so just return those
if result := <-app.Srv.Store.FileInfo().GetForPost(post.Id); result.Err != nil {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.get_post_file_infos_again.app_error"), post.Id, result.Err)
return []*model.FileInfo{}
} else {
l4g.Debug(utils.T("api.file.migrate_filenames_to_file_infos.not_migrating_post.debug"), post.Id)
return result.Data.([]*model.FileInfo)
}
}
l4g.Debug(utils.T("api.file.migrate_filenames_to_file_infos.migrating_post.debug"), post.Id)
savedInfos := make([]*model.FileInfo, 0, len(infos))
fileIds := make([]string, 0, len(filenames))
for _, info := range infos {
if result := <-app.Srv.Store.FileInfo().Save(info); result.Err != nil {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.save_file_info.app_error"), post.Id, info.Id, info.Path, result.Err)
continue
}
savedInfos = append(savedInfos, info)
fileIds = append(fileIds, info.Id)
}
// Copy and save the updated post
newPost := &model.Post{}
*newPost = *post
newPost.Filenames = []string{}
newPost.FileIds = fileIds
// Update Posts to clear Filenames and set FileIds
if result := <-app.Srv.Store.Post().Update(newPost, post); result.Err != nil {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.save_post.app_error"), post.Id, newPost.FileIds, post.Filenames, result.Err)
return []*model.FileInfo{}
} else {
return savedInfos
}
}
func findTeamIdForFilename(post *model.Post, filename string) string {
split := strings.SplitN(filename, "/", 5)
id := split[3]
name, _ := url.QueryUnescape(split[4])
// This post is in a direct channel so we need to figure out what team the files are stored under.
if result := <-app.Srv.Store.Team().GetTeamsByUserId(post.UserId); result.Err != nil {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.teams.app_error"), post.Id, result.Err)
} else if teams := result.Data.([]*model.Team); len(teams) == 1 {
// The user has only one team so the post must've been sent from it
return teams[0].Id
} else {
for _, team := range teams {
path := fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/%s", team.Id, post.ChannelId, post.UserId, id, name)
if _, err := ReadFile(path); err == nil {
// Found the team that this file was posted from
return team.Id
}
}
}
return ""
}
func getInfoForFilename(post *model.Post, teamId string, filename string) *model.FileInfo {
// Find the path from the Filename of the form /{channelId}/{userId}/{uid}/{nameWithExtension}
split := strings.SplitN(filename, "/", 5)
if len(split) < 5 {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.unexpected_filename.error"), post.Id, filename)
return nil
}
channelId := split[1]
userId := split[2]
oldId := split[3]
name, _ := url.QueryUnescape(split[4])
if split[0] != "" || split[1] != post.ChannelId || split[2] != post.UserId || strings.Contains(split[4], "/") {
l4g.Warn(utils.T("api.file.migrate_filenames_to_file_infos.mismatched_filename.warn"), post.Id, post.ChannelId, post.UserId, filename)
}
pathPrefix := fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/", teamId, channelId, userId, oldId)
path := pathPrefix + name
// Open the file and populate the fields of the FileInfo
var info *model.FileInfo
if data, err := ReadFile(path); err != nil {
l4g.Error(utils.T("api.file.migrate_filenames_to_file_infos.file_not_found.error"), post.Id, filename, path, err)
return nil
} else {
var err *model.AppError
info, err = model.GetInfoForBytes(name, data)
if err != nil {
l4g.Warn(utils.T("api.file.migrate_filenames_to_file_infos.info.app_error"), post.Id, filename, err)
}
}
// Generate a new ID because with the old system, you could very rarely get multiple posts referencing the same file
info.Id = model.NewId()
info.CreatorId = post.UserId
info.PostId = post.Id
info.CreateAt = post.CreateAt
info.UpdateAt = post.UpdateAt
info.Path = path
if info.IsImage() {
nameWithoutExtension := name[:strings.LastIndex(name, ".")]
info.PreviewPath = pathPrefix + nameWithoutExtension + "_preview.jpg"
info.ThumbnailPath = pathPrefix + nameWithoutExtension + "_thumb.jpg"
}
return info
}
func WriteFile(f []byte, path string) *model.AppError {
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
endpoint := utils.Cfg.FileSettings.AmazonS3Endpoint
accessKey := utils.Cfg.FileSettings.AmazonS3AccessKeyId
secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey
secure := *utils.Cfg.FileSettings.AmazonS3SSL
s3Clnt, err := s3.New(endpoint, accessKey, secretKey, secure)
if err != nil {
return model.NewLocAppError("WriteFile", "api.file.write_file.s3.app_error", nil, err.Error())
}
bucket := utils.Cfg.FileSettings.AmazonS3Bucket
ext := filepath.Ext(path)
if model.IsFileExtImage(ext) {
_, err = s3Clnt.PutObject(bucket, path, bytes.NewReader(f), model.GetImageMimeType(ext))
} else {
_, err = s3Clnt.PutObject(bucket, path, bytes.NewReader(f), "binary/octet-stream")
}
if err != nil {
return model.NewLocAppError("WriteFile", "api.file.write_file.s3.app_error", nil, err.Error())
}
} else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
if err := writeFileLocally(f, utils.Cfg.FileSettings.Directory+path); err != nil {
return err
}
} else {
return model.NewLocAppError("WriteFile", "api.file.write_file.configured.app_error", nil, "")
}
return nil
}
func MoveFile(oldPath, newPath string) *model.AppError {
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
endpoint := utils.Cfg.FileSettings.AmazonS3Endpoint
accessKey := utils.Cfg.FileSettings.AmazonS3AccessKeyId
secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey
secure := *utils.Cfg.FileSettings.AmazonS3SSL
s3Clnt, err := s3.New(endpoint, accessKey, secretKey, secure)
if err != nil {
return model.NewLocAppError("moveFile", "api.file.write_file.s3.app_error", nil, err.Error())
}
bucket := utils.Cfg.FileSettings.AmazonS3Bucket
var copyConds = s3.NewCopyConditions()
if err = s3Clnt.CopyObject(bucket, newPath, "/"+path.Join(bucket, oldPath), copyConds); err != nil {
return model.NewLocAppError("moveFile", "api.file.move_file.delete_from_s3.app_error", nil, err.Error())
}
if err = s3Clnt.RemoveObject(bucket, oldPath); err != nil {
return model.NewLocAppError("moveFile", "api.file.move_file.delete_from_s3.app_error", nil, err.Error())
}
} else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+newPath), 0774); err != nil {
return model.NewLocAppError("moveFile", "api.file.move_file.rename.app_error", nil, err.Error())
}
if err := os.Rename(utils.Cfg.FileSettings.Directory+oldPath, utils.Cfg.FileSettings.Directory+newPath); err != nil {
return model.NewLocAppError("moveFile", "api.file.move_file.rename.app_error", nil, err.Error())
}
} else {
return model.NewLocAppError("moveFile", "api.file.move_file.configured.app_error", nil, "")
}
return nil
}
func writeFileLocally(f []byte, path string) *model.AppError {
if err := os.MkdirAll(filepath.Dir(path), 0774); err != nil {
directory, _ := filepath.Abs(filepath.Dir(path))
return model.NewLocAppError("WriteFile", "api.file.write_file_locally.create_dir.app_error", nil, "directory="+directory+", err="+err.Error())
}
if err := ioutil.WriteFile(path, f, 0644); err != nil {
return model.NewLocAppError("WriteFile", "api.file.write_file_locally.writing.app_error", nil, err.Error())
}
return nil
}
func ReadFile(path string) ([]byte, *model.AppError) {
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
endpoint := utils.Cfg.FileSettings.AmazonS3Endpoint
accessKey := utils.Cfg.FileSettings.AmazonS3AccessKeyId
secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey
secure := *utils.Cfg.FileSettings.AmazonS3SSL
s3Clnt, err := s3.New(endpoint, accessKey, secretKey, secure)
if err != nil {
return nil, model.NewLocAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error())
}
bucket := utils.Cfg.FileSettings.AmazonS3Bucket
minioObject, err := s3Clnt.GetObject(bucket, path)
defer minioObject.Close()
if err != nil {
return nil, model.NewLocAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error())
}
if f, err := ioutil.ReadAll(minioObject); err != nil {
return nil, model.NewLocAppError("ReadFile", "api.file.read_file.s3.app_error", nil, err.Error())
} else {
return f, nil
}
} else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
if f, err := ioutil.ReadFile(utils.Cfg.FileSettings.Directory + path); err != nil {
return nil, model.NewLocAppError("ReadFile", "api.file.read_file.reading_local.app_error", nil, err.Error())
} else {
return f, nil
}
} else {
return nil, model.NewLocAppError("ReadFile", "api.file.read_file.configured.app_error", nil, "")
}
}
func openFileWriteStream(path string) (io.Writer, *model.AppError) {
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
return nil, model.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.s3.app_error", nil, "")
} else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+path), 0774); err != nil {
return nil, model.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.creating_dir.app_error", nil, err.Error())
}
if fileHandle, err := os.Create(utils.Cfg.FileSettings.Directory + path); err != nil {
return nil, model.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.local_server.app_error", nil, err.Error())
} else {
fileHandle.Chmod(0644)
return fileHandle, nil
}
}
return nil, model.NewLocAppError("openFileWriteStream", "api.file.open_file_write_stream.configured.app_error", nil, "")
}
func closeFileWriteStream(file io.Writer) {
file.(*os.File).Close()
w.Write([]byte(model.StringToJson(app.GeneratePublicLink(c.GetSiteURL(), info))))
}

Просмотреть файл

@@ -508,7 +508,7 @@ func TestGetPublicFileOld(t *testing.T) {
}
func generatePublicLinkOld(siteURL, teamId, channelId, userId, filename string) string {
hash := generatePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt)
hash := app.GeneratePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt)
return fmt.Sprintf("%s%s/public/files/get/%s/%s/%s/%s?h=%s", siteURL, model.API_URL_SUFFIX, teamId, channelId, userId, filename, hash)
}
@@ -581,29 +581,6 @@ func TestGetPublicLink(t *testing.T) {
}
}
func TestGeneratePublicLinkHash(t *testing.T) {
filename1 := model.NewId() + "/" + model.NewRandomString(16) + ".txt"
filename2 := model.NewId() + "/" + model.NewRandomString(16) + ".txt"
salt1 := model.NewRandomString(32)
salt2 := model.NewRandomString(32)
hash1 := generatePublicLinkHash(filename1, salt1)
hash2 := generatePublicLinkHash(filename2, salt1)
hash3 := generatePublicLinkHash(filename1, salt2)
if hash1 != generatePublicLinkHash(filename1, salt1) {
t.Fatal("hash should be equal for the same file name and salt")
}
if hash1 == hash2 {
t.Fatal("hashes for different files should not be equal")
}
if hash1 == hash3 {
t.Fatal("hashes for the same file with different salts should not be equal")
}
}
func TestMigrateFilenamesToFileInfos(t *testing.T) {
th := Setup().InitBasic()
@@ -740,7 +717,7 @@ func TestFindTeamIdForFilename(t *testing.T) {
Filenames: []string{fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId1, "test.png")},
})).(*model.Post)
if teamId := findTeamIdForFilename(post1, post1.Filenames[0]); teamId != team1.Id {
if teamId := app.FindTeamIdForFilename(post1, post1.Filenames[0]); teamId != team1.Id {
t.Fatal("file should've been found under team1")
}
@@ -753,7 +730,7 @@ func TestFindTeamIdForFilename(t *testing.T) {
})).(*model.Post)
Client.SetTeamId(team1.Id)
if teamId := findTeamIdForFilename(post2, post2.Filenames[0]); teamId != team2.Id {
if teamId := app.FindTeamIdForFilename(post2, post2.Filenames[0]); teamId != team2.Id {
t.Fatal("file should've been found under team2")
}
}
@@ -795,7 +772,7 @@ func TestGetInfoForFilename(t *testing.T) {
Filenames: []string{fmt.Sprintf("/%s/%s/%s/%s", channel1.Id, user1.Id, fileId1, "test.png")},
})).(*model.Post)
if info := getInfoForFilename(post1, team1.Id, post1.Filenames[0]); info == nil {
if info := app.GetInfoForFilename(post1, team1.Id, post1.Filenames[0]); info == nil {
t.Fatal("info shouldn't be nil")
} else if info.Id == "" {
t.Fatal("info.Id shouldn't be empty")

Просмотреть файл

@@ -250,32 +250,6 @@ func getAuthorizedApps(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
func RevokeAccessToken(token string) *model.AppError {
session, _ := app.GetSession(token)
schan := app.Srv.Store.Session().Remove(token)
if result := <-app.Srv.Store.OAuth().GetAccessData(token); result.Err != nil {
return model.NewLocAppError("RevokeAccessToken", "api.oauth.revoke_access_token.get.app_error", nil, "")
}
tchan := app.Srv.Store.OAuth().RemoveAccessData(token)
if result := <-tchan; result.Err != nil {
return model.NewLocAppError("RevokeAccessToken", "api.oauth.revoke_access_token.del_token.app_error", nil, "")
}
if result := <-schan; result.Err != nil {
return model.NewLocAppError("RevokeAccessToken", "api.oauth.revoke_access_token.del_session.app_error", nil, "")
}
if session != nil {
app.RemoveAllSessionsForUserId(session.UserId)
}
return nil
}
func GetAuthData(code string) *model.AuthData {
if result := <-app.Srv.Store.OAuth().GetAuthData(code); result.Err != nil {
l4g.Error(utils.T("api.oauth.get_auth_data.find.error"), code)
@@ -311,7 +285,11 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
action := props["action"]
switch action {
case model.OAUTH_ACTION_SIGNUP:
CreateOAuthUser(c, w, r, service, body, teamId)
if user, err := app.CreateOAuthUser(service, body, teamId); err != nil {
c.Err = err
} else {
doLogin(c, w, r, user, "")
}
if c.Err == nil {
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
}
@@ -931,7 +909,7 @@ func deauthorizeOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
accessData := result.Data.([]*model.AccessData)
for _, a := range accessData {
if err := RevokeAccessToken(a.Token); err != nil {
if err := app.RevokeAccessToken(a.Token); err != nil {
c.Err = err
return
}

Просмотреть файл

@@ -362,13 +362,18 @@ func getPermalinkTmp(c *Context, w http.ResponseWriter, r *http.Request) {
}
post := list.Posts[list.Order[0]]
// Because we confuse permissions and membership in Mattermost's model, we have to just
// try to join the channel without checking if we already have permission to it. This is
// because system admins have permissions to every channel but are not nessisary a member
// of every channel. If we checked here then system admins would skip joining the channel and
// error when they tried to view it.
if err, _ := JoinChannelById(c, c.Session.UserId, post.ChannelId); err != nil {
// On error just return with permissions error
var channel *model.Channel
var err *model.AppError
if channel, err = app.GetChannel(post.ChannelId); err != nil {
c.Err = err
return
}
if !HasPermissionToTeamContext(c, channel.TeamId, model.PERMISSION_JOIN_PUBLIC_CHANNELS) {
return
}
if err = app.JoinChannel(channel, c.Session.UserId); err != nil {
c.Err = err
return
}
@@ -611,7 +616,7 @@ func getFileInfosForPost(c *Context, w http.ResponseWriter, r *http.Request) {
if len(post.Filenames) > 0 {
// The post has Filenames that need to be replaced with FileInfos
infos = migrateFilenamesToFileInfos(post)
infos = app.MigrateFilenamesToFileInfos(post)
}
}

Просмотреть файл

@@ -248,7 +248,10 @@ func revokeAllSessions(c *Context, w http.ResponseWriter, r *http.Request) {
c.LogAudit("revoked_all=" + id)
if session.IsOAuth {
RevokeAccessToken(session.Token)
if err := app.RevokeAccessToken(session.Token); err != nil {
c.Err = err
return
}
} else {
if result := <-app.Srv.Store.Session().Remove(session.Id); result.Err != nil {
c.Err = result.Err

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@@ -107,25 +107,6 @@ func TestCheckUserDomain(t *testing.T) {
}
}
func TestIsUsernameTaken(t *testing.T) {
th := Setup().InitBasic()
user := th.BasicUser
taken := IsUsernameTaken(user.Username)
if !taken {
t.Logf("the username '%v' should be taken", user.Username)
t.FailNow()
}
newUsername := "randomUsername"
taken = IsUsernameTaken(newUsername)
if taken {
t.Logf("the username '%v' should not be taken", newUsername)
t.FailNow()
}
}
func TestLogin(t *testing.T) {
th := Setup()
Client := th.CreateClient()
@@ -227,7 +208,10 @@ func TestLogin(t *testing.T) {
data := model.MapToJson(props)
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
ruser2, _ := Client.CreateUserFromSignup(&user2, data, hash)
ruser2, err := Client.CreateUserFromSignup(&user2, data, hash)
if err != nil {
t.Fatal(err)
}
if _, err := Client.Login(ruser2.Data.(*model.User).Email, user2.Password); err != nil {
t.Fatal("From verfied hash")
@@ -686,7 +670,7 @@ func TestUserCreateImage(t *testing.T) {
th := Setup()
Client := th.CreateClient()
b, err := createProfileImage("Corey Hulen", "eo1zkdr96pdj98pjmq8zy35wba")
b, err := app.CreateProfileImage("Corey Hulen", "eo1zkdr96pdj98pjmq8zy35wba")
if err != nil {
t.Fatal(err)
}

Просмотреть файл

@@ -115,22 +115,3 @@ func closeBody(r *http.Response) {
r.Body.Close()
}
}
func RevokeWebrtcToken(sessionId string) {
token := base64.StdEncoding.EncodeToString([]byte(sessionId))
data := make(map[string]string)
data["janus"] = "remove_token"
data["token"] = token
data["transaction"] = model.NewId()
data["admin_secret"] = *utils.Cfg.WebrtcSettings.GatewayAdminSecret
rq, _ := http.NewRequest("POST", *utils.Cfg.WebrtcSettings.GatewayAdminUrl, strings.NewReader(model.MapToJson(data)))
rq.Header.Set("Content-Type", "application/json")
// we do not care about the response
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
}
httpClient := &http.Client{Transport: tr}
httpClient.Do(rq)
}

Просмотреть файл

@@ -5,6 +5,7 @@ package api
import (
"fmt"
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"testing"
@@ -39,5 +40,5 @@ func TestWebrtcToken(t *testing.T) {
fmt.Println("Turn Password", result["turn_password"])
}
RevokeWebrtcToken(sessionId)
app.RevokeWebrtcToken(sessionId)
}