Merge remote-tracking branch 'origin/master' into advanced-permissions-phase-2
Этот коммит содержится в:
@@ -30,7 +30,7 @@ func (a *App) GetAnalytics(name string, teamId string) (model.AnalyticsRows, *mo
|
||||
}
|
||||
|
||||
if name == "standard" {
|
||||
var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 10)
|
||||
var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 11)
|
||||
rows[0] = &model.AnalyticsRow{Name: "channel_open_count", Value: 0}
|
||||
rows[1] = &model.AnalyticsRow{Name: "channel_private_count", Value: 0}
|
||||
rows[2] = &model.AnalyticsRow{Name: "post_count", Value: 0}
|
||||
@@ -41,13 +41,17 @@ func (a *App) GetAnalytics(name string, teamId string) (model.AnalyticsRows, *mo
|
||||
rows[7] = &model.AnalyticsRow{Name: "total_read_db_connections", Value: 0}
|
||||
rows[8] = &model.AnalyticsRow{Name: "daily_active_users", Value: 0}
|
||||
rows[9] = &model.AnalyticsRow{Name: "monthly_active_users", Value: 0}
|
||||
rows[10] = &model.AnalyticsRow{Name: "inactive_user_count", Value: 0}
|
||||
|
||||
openChan := a.Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_OPEN)
|
||||
privateChan := a.Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_PRIVATE)
|
||||
teamChan := a.Srv.Store.Team().AnalyticsTeamCount()
|
||||
|
||||
var userChan store.StoreChannel
|
||||
if teamId != "" {
|
||||
var userInactiveChan store.StoreChannel
|
||||
if teamId == "" {
|
||||
userInactiveChan = a.Srv.Store.User().AnalyticsGetInactiveUsersCount()
|
||||
} else {
|
||||
userChan = a.Srv.Store.User().AnalyticsUniqueUserCount(teamId)
|
||||
}
|
||||
|
||||
@@ -91,6 +95,16 @@ func (a *App) GetAnalytics(name string, teamId string) (model.AnalyticsRows, *mo
|
||||
}
|
||||
}
|
||||
|
||||
if userInactiveChan == nil {
|
||||
rows[10].Value = -1
|
||||
} else {
|
||||
if r := <-userInactiveChan; r.Err != nil {
|
||||
return nil, r.Err
|
||||
} else {
|
||||
rows[10].Value = float64(r.Data.(int64))
|
||||
}
|
||||
}
|
||||
|
||||
if r := <-teamChan; r.Err != nil {
|
||||
return nil, r.Err
|
||||
} else {
|
||||
|
||||
@@ -560,6 +560,14 @@ func (a *App) DoAdvancedPermissionsMigration() {
|
||||
return
|
||||
}
|
||||
|
||||
config := a.Config()
|
||||
if *config.ServiceSettings.AllowEditPost == model.ALLOW_EDIT_POST_ALWAYS {
|
||||
*config.ServiceSettings.PostEditTimeLimit = -1
|
||||
if err := a.SaveConfig(config, true); err != nil {
|
||||
mlog.Error("Failed to update config in Advanced Permissions Phase 1 Migration.", mlog.String("error", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
system := model.System{
|
||||
Name: ADVANCED_PERMISSIONS_MIGRATION_KEY,
|
||||
Value: "true",
|
||||
|
||||
@@ -426,4 +426,32 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, permissions, role.Permissions)
|
||||
}
|
||||
|
||||
// Check that the config setting for "always" and "time_limit" edit posts is updated correctly.
|
||||
th.ResetRoleMigration()
|
||||
|
||||
config := th.App.GetConfig()
|
||||
*config.ServiceSettings.AllowEditPost = "always"
|
||||
*config.ServiceSettings.PostEditTimeLimit = 300
|
||||
th.App.SaveConfig(config, false)
|
||||
|
||||
th.App.DoAdvancedPermissionsMigration()
|
||||
config = th.App.GetConfig()
|
||||
assert.Equal(t, -1, *config.ServiceSettings.PostEditTimeLimit)
|
||||
|
||||
th.ResetRoleMigration()
|
||||
|
||||
config = th.App.GetConfig()
|
||||
*config.ServiceSettings.AllowEditPost = "time_limit"
|
||||
*config.ServiceSettings.PostEditTimeLimit = 300
|
||||
th.App.SaveConfig(config, false)
|
||||
|
||||
th.App.DoAdvancedPermissionsMigration()
|
||||
config = th.App.GetConfig()
|
||||
assert.Equal(t, 300, *config.ServiceSettings.PostEditTimeLimit)
|
||||
|
||||
config = th.App.GetConfig()
|
||||
*config.ServiceSettings.AllowEditPost = "always"
|
||||
*config.ServiceSettings.PostEditTimeLimit = 300
|
||||
th.App.SaveConfig(config, false)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost-server/mlog"
|
||||
@@ -42,8 +41,6 @@ func (me *InviteProvider) DoCommand(a *App, args *model.CommandArgs, message str
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite.missing_message.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
mlog.Debug(fmt.Sprint(message))
|
||||
|
||||
splitMessage := strings.SplitN(message, " ", 2)
|
||||
targetUsername := splitMessage[0]
|
||||
targetUsername = strings.TrimPrefix(targetUsername, "@")
|
||||
@@ -77,12 +74,7 @@ func (me *InviteProvider) DoCommand(a *App, args *model.CommandArgs, message str
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite.directchannel.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
// Check if user is already in the channel
|
||||
_, err = a.GetChannelMember(channelToJoin.Id, userProfile.Id)
|
||||
if err == nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite.user_already_in_channel.app_error", map[string]interface{}{"User": userProfile.Username}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
// Check Permissions
|
||||
if channelToJoin.Type == model.CHANNEL_OPEN && !a.SessionHasPermissionToChannel(args.Session, channelToJoin.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS) {
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
@@ -91,6 +83,12 @@ func (me *InviteProvider) DoCommand(a *App, args *model.CommandArgs, message str
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite.permission.app_error", map[string]interface{}{"User": userProfile.Username, "Channel": channelToJoin.Name}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
// Check if user is already in the channel
|
||||
_, err = a.GetChannelMember(channelToJoin.Id, userProfile.Id)
|
||||
if err == nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite.user_already_in_channel.app_error", map[string]interface{}{"User": userProfile.Username}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
if _, err := a.AddChannelMember(userProfile.Id, channelToJoin, args.Session.UserId, ""); err != nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_invite.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ func (a *App) trackActivity() {
|
||||
activeUserCount = ucr.Data.(int64)
|
||||
}
|
||||
|
||||
if iucr := <-a.Srv.Store.Status().GetTotalActiveUsersCount(); iucr.Err == nil {
|
||||
if iucr := <-a.Srv.Store.User().AnalyticsGetInactiveUsersCount(); iucr.Err == nil {
|
||||
inactiveUserCount = iucr.Data.(int64)
|
||||
}
|
||||
|
||||
@@ -171,17 +171,17 @@ func (a *App) trackActivity() {
|
||||
}
|
||||
|
||||
a.SendDiagnostic(TRACK_ACTIVITY, map[string]interface{}{
|
||||
"registered_users": userCount,
|
||||
"active_users": activeUserCount,
|
||||
"registered_inactive_users": inactiveUserCount,
|
||||
"teams": teamCount,
|
||||
"public_channels": publicChannelCount,
|
||||
"private_channels": privateChannelCount,
|
||||
"direct_message_channels": directChannelCount,
|
||||
"public_channels_deleted": deletedPublicChannelCount,
|
||||
"private_channels_deleted": deletedPrivateChannelCount,
|
||||
"posts": postsCount,
|
||||
"used_apiv3": atomic.LoadInt32(model.UsedApiV3) == 1,
|
||||
"registered_users": userCount,
|
||||
"active_users": activeUserCount,
|
||||
"registered_deactivated_users": inactiveUserCount,
|
||||
"teams": teamCount,
|
||||
"public_channels": publicChannelCount,
|
||||
"private_channels": privateChannelCount,
|
||||
"direct_message_channels": directChannelCount,
|
||||
"public_channels_deleted": deletedPublicChannelCount,
|
||||
"private_channels_deleted": deletedPrivateChannelCount,
|
||||
"posts": postsCount,
|
||||
"used_apiv3": atomic.LoadInt32(model.UsedApiV3) == 1,
|
||||
})
|
||||
|
||||
atomic.StoreInt32(model.UsedApiV3, 0)
|
||||
|
||||
@@ -250,7 +250,7 @@ func (a *App) sendBatchedEmailNotification(userId string, notifications []*batch
|
||||
body.Props["BodyText"] = translateFunc("api.email_batching.send_batched_email_notification.body_text", len(notifications))
|
||||
|
||||
if err := a.SendMail(user.Email, subject, body.Render()); err != nil {
|
||||
mlog.Warn(fmt.Sprint("api.email_batchings.send_batched_email_notification.send.app_error FIXME: NOT FOUND IN TRANSLATIONS FILE", user.Email, err))
|
||||
mlog.Warn(fmt.Sprintf("Unable to send batched email notification err=%v", err), mlog.String("email", user.Email))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
67
app/file.go
67
app/file.go
@@ -98,7 +98,7 @@ func (a *App) GetInfoForFilename(post *model.Post, teamId string, filename strin
|
||||
// Find the path from the Filename of the form /{channelId}/{userId}/{uid}/{nameWithExtension}
|
||||
split := strings.SplitN(filename, "/", 5)
|
||||
if len(split) < 5 {
|
||||
mlog.Error(fmt.Sprintf("Unable to decipher filename when migrating post to use FileInfos, post_id=%v, filename=%v", post.Id, filename), mlog.String("post_id", post.Id))
|
||||
mlog.Error("Unable to decipher filename when migrating post to use FileInfos", mlog.String("post_id", post.Id), mlog.String("filename", filename))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -108,7 +108,13 @@ func (a *App) GetInfoForFilename(post *model.Post, teamId string, filename strin
|
||||
name, _ := url.QueryUnescape(split[4])
|
||||
|
||||
if split[0] != "" || split[1] != post.ChannelId || split[2] != post.UserId || strings.Contains(split[4], "/") {
|
||||
mlog.Warn(fmt.Sprintf("Found an unusual filename when migrating post to use FileInfos, post_id=%v, channel_id=%v, user_id=%v, filename=%v", post.Id, post.ChannelId, post.UserId, filename), mlog.String("post_id", post.Id))
|
||||
mlog.Warn(
|
||||
"Found an unusual filename when migrating post to use FileInfos",
|
||||
mlog.String("post_id", post.Id),
|
||||
mlog.String("channel_id", post.ChannelId),
|
||||
mlog.String("user_id", post.UserId),
|
||||
mlog.String("filename", filename),
|
||||
)
|
||||
}
|
||||
|
||||
pathPrefix := fmt.Sprintf("teams/%s/channels/%s/users/%s/%s/", teamId, channelId, userId, oldId)
|
||||
@@ -117,13 +123,22 @@ func (a *App) GetInfoForFilename(post *model.Post, teamId string, filename strin
|
||||
// Open the file and populate the fields of the FileInfo
|
||||
var info *model.FileInfo
|
||||
if data, err := a.ReadFile(path); err != nil {
|
||||
mlog.Error(fmt.Sprint("api.file.migrate_filenames_to_file_infos.file_not_found.error FIXME: NOT FOUND IN TRANSLATIONS FILE", post.Id, filename, path, err), mlog.String("post_id", post.Id))
|
||||
mlog.Error(
|
||||
fmt.Sprintf("File not found when migrating post to use FileInfos, err=%v", err),
|
||||
mlog.String("post_id", post.Id),
|
||||
mlog.String("filename", filename),
|
||||
mlog.String("path", path),
|
||||
)
|
||||
return nil
|
||||
} else {
|
||||
var err *model.AppError
|
||||
info, err = model.GetInfoForBytes(name, data)
|
||||
if err != nil {
|
||||
mlog.Warn(fmt.Sprintf("Unable to fully decode file info when migrating post to use FileInfos, post_id=%v, filename=%v, err=%v", post.Id, filename, err), mlog.String("post_id", post.Id))
|
||||
mlog.Warn(
|
||||
fmt.Sprintf("Unable to fully decode file info when migrating post to use FileInfos, err=%v", err),
|
||||
mlog.String("post_id", post.Id),
|
||||
mlog.String("filename", filename),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +166,7 @@ func (a *App) FindTeamIdForFilename(post *model.Post, filename string) string {
|
||||
|
||||
// This post is in a direct channel so we need to figure out what team the files are stored under.
|
||||
if result := <-a.Srv.Store.Team().GetTeamsByUserId(post.UserId); result.Err != nil {
|
||||
mlog.Error(fmt.Sprintf("Unable to get teams when migrating post to use FileInfos, post_id=%v, err=%v", post.Id, result.Err), mlog.String("post_id", post.Id))
|
||||
mlog.Error(fmt.Sprintf("Unable to get teams when migrating post to use FileInfo, err=%v", result.Err), mlog.String("post_id", post.Id))
|
||||
} 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
|
||||
@@ -173,7 +188,7 @@ var fileMigrationLock sync.Mutex
|
||||
// Creates and stores FileInfos for a post created before the FileInfos table existed.
|
||||
func (a *App) MigrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo {
|
||||
if len(post.Filenames) == 0 {
|
||||
mlog.Warn(fmt.Sprintf("Unable to migrate post to use FileInfos with an empty Filenames field, post_id=%v", post.Id), mlog.String("post_id", post.Id))
|
||||
mlog.Warn("Unable to migrate post to use FileInfos with an empty Filenames field", mlog.String("post_id", post.Id))
|
||||
return []*model.FileInfo{}
|
||||
}
|
||||
|
||||
@@ -184,7 +199,11 @@ func (a *App) MigrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo {
|
||||
|
||||
var channel *model.Channel
|
||||
if result := <-cchan; result.Err != nil {
|
||||
mlog.Error(fmt.Sprintf("Unable to get channel when migrating post to use FileInfos, post_id=%v, channel_id=%v, err=%v", post.Id, post.ChannelId, result.Err), mlog.String("post_id", post.Id))
|
||||
mlog.Error(
|
||||
fmt.Sprintf("Unable to get channel when migrating post to use FileInfos, err=%v", result.Err),
|
||||
mlog.String("post_id", post.Id),
|
||||
mlog.String("channel_id", post.ChannelId),
|
||||
)
|
||||
return []*model.FileInfo{}
|
||||
} else {
|
||||
channel = result.Data.(*model.Channel)
|
||||
@@ -202,7 +221,10 @@ func (a *App) MigrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo {
|
||||
// Create FileInfo objects for this post
|
||||
infos := make([]*model.FileInfo, 0, len(filenames))
|
||||
if teamId == "" {
|
||||
mlog.Error(fmt.Sprint("api.file.migrate_filenames_to_file_infos.team_id.error FIXME: NOT FOUND IN TRANSLATIONS FILE", post.Id, filenames), mlog.String("post_id", post.Id))
|
||||
mlog.Error(
|
||||
fmt.Sprintf("Unable to find team id for files when migrating post to use FileInfos, filenames=%v", filenames),
|
||||
mlog.String("post_id", post.Id),
|
||||
)
|
||||
} else {
|
||||
for _, filename := range filenames {
|
||||
info := a.GetInfoForFilename(post, teamId, filename)
|
||||
@@ -219,26 +241,31 @@ func (a *App) MigrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo {
|
||||
defer fileMigrationLock.Unlock()
|
||||
|
||||
if result := <-a.Srv.Store.Post().Get(post.Id); result.Err != nil {
|
||||
mlog.Error(fmt.Sprint("api.file.migrate_filenames_to_file_infos.get_post_again.app_error FIXME: NOT FOUND IN TRANSLATIONS FILE", post.Id, result.Err), mlog.String("post_id", post.Id))
|
||||
mlog.Error(fmt.Sprintf("Unable to get post when migrating post to use FileInfos, err=%v", result.Err), mlog.String("post_id", post.Id))
|
||||
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 := <-a.Srv.Store.FileInfo().GetForPost(post.Id, true, false); result.Err != nil {
|
||||
mlog.Error(fmt.Sprint("api.file.migrate_filenames_to_file_infos.get_post_file_infos_again.app_error FIXME: NOT FOUND IN TRANSLATIONS FILE", post.Id, result.Err), mlog.String("post_id", post.Id))
|
||||
mlog.Error(fmt.Sprintf("Unable to get FileInfos for migrated post, err=%v", result.Err), mlog.String("post_id", post.Id))
|
||||
return []*model.FileInfo{}
|
||||
} else {
|
||||
mlog.Debug(fmt.Sprintf("Post already migrated to use FileInfos, post_id=%v", post.Id), mlog.String("post_id", post.Id))
|
||||
mlog.Debug("Post already migrated to use FileInfos", mlog.String("post_id", post.Id))
|
||||
return result.Data.([]*model.FileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
mlog.Debug(fmt.Sprintf("Migrating post to use FileInfos, post_id=%v", post.Id), mlog.String("post_id", post.Id))
|
||||
mlog.Debug("Migrating post to use FileInfos", mlog.String("post_id", post.Id))
|
||||
|
||||
savedInfos := make([]*model.FileInfo, 0, len(infos))
|
||||
fileIds := make([]string, 0, len(filenames))
|
||||
for _, info := range infos {
|
||||
if result := <-a.Srv.Store.FileInfo().Save(info); result.Err != nil {
|
||||
mlog.Error(fmt.Sprint("api.file.migrate_filenames_to_file_infos.save_file_info.app_error FIXME: NOT FOUND IN TRANSLATIONS FILE", post.Id, info.Id, info.Path, result.Err), mlog.String("post_id", post.Id))
|
||||
mlog.Error(
|
||||
fmt.Sprintf("Unable to save file info when migrating post to use FileInfos, err=%v", result.Err),
|
||||
mlog.String("post_id", post.Id),
|
||||
mlog.String("file_info_id", info.Id),
|
||||
mlog.String("file_info_path", info.Path),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -255,7 +282,7 @@ func (a *App) MigrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo {
|
||||
|
||||
// Update Posts to clear Filenames and set FileIds
|
||||
if result := <-a.Srv.Store.Post().Update(newPost, post); result.Err != nil {
|
||||
mlog.Error(fmt.Sprint("api.file.migrate_filenames_to_file_infos.save_post.app_error FIXME: NOT FOUND IN TRANSLATIONS FILE", post.Id, newPost.FileIds, post.Filenames, result.Err), mlog.String("post_id", post.Id))
|
||||
mlog.Error(fmt.Sprintf("Unable to save migrated post when migrating to use FileInfos, new_file_ids=%v, old_filenames=%v, err=%v", newPost.FileIds, post.Filenames, result.Err), mlog.String("post_id", post.Id))
|
||||
return []*model.FileInfo{}
|
||||
} else {
|
||||
return savedInfos
|
||||
@@ -361,6 +388,14 @@ func (a *App) DoUploadFile(now time.Time, rawTeamId string, rawChannelId string,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if orientation, err := getImageOrientation(bytes.NewReader(data)); err == nil &&
|
||||
(orientation == RotatedCWMirrored ||
|
||||
orientation == RotatedCCW ||
|
||||
orientation == RotatedCCWMirrored ||
|
||||
orientation == RotatedCW) {
|
||||
info.Width, info.Height = info.Height, info.Width
|
||||
}
|
||||
|
||||
info.Id = model.NewId()
|
||||
info.CreatorId = userId
|
||||
|
||||
@@ -514,12 +549,12 @@ func (a *App) generatePreviewImage(img image.Image, previewPath string, width in
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if err := jpeg.Encode(buf, preview, &jpeg.Options{Quality: 90}); err != nil {
|
||||
mlog.Error(fmt.Sprintf("Unable to encode image as preview jpg path=%v err=%v", previewPath, err))
|
||||
mlog.Error(fmt.Sprintf("Unable to encode image as preview jpg err=%v", err), mlog.String("path", previewPath))
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.WriteFile(buf.Bytes(), previewPath); err != nil {
|
||||
mlog.Error(fmt.Sprintf("Unable to upload preview path=%v err=%v", previewPath, err))
|
||||
mlog.Error(fmt.Sprintf("Unable to upload preview err=%v", err), mlog.String("path", previewPath))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestSendNotifications(t *testing.T) {
|
||||
} else if mentions == nil {
|
||||
t.Log(mentions)
|
||||
t.Fatal("user should have been mentioned")
|
||||
} else if mentions[0] != th.BasicUser2.Id {
|
||||
} else if !utils.StringInSlice(th.BasicUser2.Id, mentions) {
|
||||
t.Log(mentions)
|
||||
t.Fatal("user should have been mentioned")
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user