MM-27493 Shared channels (MVP) (#17301)
Remote Cluster Service - provides ability for multiple Mattermost cluster instances to create a trusted connection with each other and exchange messages - trusted connections are managed via slash commands (for now) - facilitates features requiring inter-cluster communication, such as Shared Channels Shared Channels Service - provides ability to shared channels between one or more Mattermost cluster instances (using trusted connection) - sharing/unsharing of channels is managed via slash commands (for now)
Этот коммит содержится в:
@@ -567,14 +567,20 @@ func (s SqlChannelStore) Save(channel *model.Channel, maxChannelsPerTeam int64)
|
||||
return newChannel, err
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) CreateDirectChannel(user *model.User, otherUser *model.User) (*model.Channel, error) {
|
||||
func (s SqlChannelStore) CreateDirectChannel(user *model.User, otherUser *model.User, channelOptions ...model.ChannelOption) (*model.Channel, error) {
|
||||
channel := new(model.Channel)
|
||||
|
||||
for _, option := range channelOptions {
|
||||
option(channel)
|
||||
}
|
||||
|
||||
channel.DisplayName = ""
|
||||
channel.Name = model.GetDMNameFromIds(otherUser.Id, user.Id)
|
||||
|
||||
channel.Header = ""
|
||||
channel.Type = model.CHANNEL_DIRECT
|
||||
channel.Shared = model.NewBool(user.IsRemote() || otherUser.IsRemote())
|
||||
channel.CreatorId = user.Id
|
||||
|
||||
cm1 := &model.ChannelMember{
|
||||
UserId: user.Id,
|
||||
@@ -592,13 +598,13 @@ func (s SqlChannelStore) CreateDirectChannel(user *model.User, otherUser *model.
|
||||
return s.SaveDirectChannel(channel, cm1, cm2)
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) (*model.Channel, error) {
|
||||
if directchannel.DeleteAt != 0 {
|
||||
return nil, store.NewErrInvalidInput("Channel", "DeleteAt", directchannel.DeleteAt)
|
||||
func (s SqlChannelStore) SaveDirectChannel(directChannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) (*model.Channel, error) {
|
||||
if directChannel.DeleteAt != 0 {
|
||||
return nil, store.NewErrInvalidInput("Channel", "DeleteAt", directChannel.DeleteAt)
|
||||
}
|
||||
|
||||
if directchannel.Type != model.CHANNEL_DIRECT {
|
||||
return nil, store.NewErrInvalidInput("Channel", "Type", directchannel.Type)
|
||||
if directChannel.Type != model.CHANNEL_DIRECT {
|
||||
return nil, store.NewErrInvalidInput("Channel", "Type", directChannel.Type)
|
||||
}
|
||||
|
||||
transaction, err := s.GetMaster().Begin()
|
||||
@@ -607,8 +613,8 @@ func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1
|
||||
}
|
||||
defer finalizeTransaction(transaction)
|
||||
|
||||
directchannel.TeamId = ""
|
||||
newChannel, err := s.saveChannelT(transaction, directchannel, 0)
|
||||
directChannel.TeamId = ""
|
||||
newChannel, err := s.saveChannelT(transaction, directChannel, 0)
|
||||
if err != nil {
|
||||
return newChannel, err
|
||||
}
|
||||
@@ -635,7 +641,7 @@ func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *model.Channel, maxChannelsPerTeam int64) (*model.Channel, error) {
|
||||
if channel.Id != "" {
|
||||
if channel.Id != "" && !channel.IsShared() {
|
||||
return nil, store.NewErrInvalidInput("Channel", "Id", channel.Id)
|
||||
}
|
||||
|
||||
@@ -3363,3 +3369,53 @@ func (s SqlChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// SetShared sets the Shared flag true/false
|
||||
func (s SqlChannelStore) SetShared(channelId string, shared bool) error {
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Update("Channels").
|
||||
Set("Shared", shared).
|
||||
Where(sq.Eq{"Id": channelId}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "channel_set_shared_tosql")
|
||||
}
|
||||
|
||||
result, err := s.GetMaster().Exec(squery, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to update `Shared` for Channels")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to determine rows affected")
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("id not found: %s", channelId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTeamForChannel returns the team for a given channelID.
|
||||
func (s SqlChannelStore) GetTeamForChannel(channelID string) (*model.Team, error) {
|
||||
nestedQ, nestedArgs, err := s.getQueryBuilder().Select("TeamId").From("Channels").Where(sq.Eq{"Id": channelID}).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get_team_for_channel_nested_tosql")
|
||||
}
|
||||
query, args, err := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("Teams").Where(sq.Expr("Id = ("+nestedQ+")", nestedArgs...)).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get_team_for_channel_tosql")
|
||||
}
|
||||
|
||||
team := model.Team{}
|
||||
err = s.GetReplica().SelectOne(&team, query, args...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("Team", fmt.Sprintf("channel_id=%s", channelID))
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to find team with channel_id=%s", channelID)
|
||||
}
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ func newSqlFileInfoStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterfac
|
||||
"FileInfo.HasPreviewImage",
|
||||
"FileInfo.MiniPreview",
|
||||
"Coalesce(FileInfo.Content, '') AS Content",
|
||||
"Coalesce(FileInfo.RemoteId, '') AS RemoteId",
|
||||
}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
@@ -67,6 +68,7 @@ func newSqlFileInfoStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterfac
|
||||
table.ColMap("Content").SetMaxSize(0)
|
||||
table.ColMap("Extension").SetMaxSize(64)
|
||||
table.ColMap("MimeType").SetMaxSize(256)
|
||||
table.ColMap("RemoteId").SetMaxSize(26)
|
||||
}
|
||||
|
||||
return s
|
||||
|
||||
@@ -42,7 +42,7 @@ func (s *SqlPostStore) ClearCaches() {
|
||||
}
|
||||
|
||||
func postSliceColumns() []string {
|
||||
return []string{"Id", "CreateAt", "UpdateAt", "EditAt", "DeleteAt", "IsPinned", "UserId", "ChannelId", "RootId", "ParentId", "OriginalId", "Message", "Type", "Props", "Hashtags", "Filenames", "FileIds", "HasReactions"}
|
||||
return []string{"Id", "CreateAt", "UpdateAt", "EditAt", "DeleteAt", "IsPinned", "UserId", "ChannelId", "RootId", "ParentId", "OriginalId", "Message", "Type", "Props", "Hashtags", "Filenames", "FileIds", "HasReactions", "RemoteId"}
|
||||
}
|
||||
|
||||
func postToSlice(post *model.Post) []interface{} {
|
||||
@@ -65,6 +65,7 @@ func postToSlice(post *model.Post) []interface{} {
|
||||
model.ArrayToJson(post.Filenames),
|
||||
model.ArrayToJson(post.FileIds),
|
||||
post.HasReactions,
|
||||
post.RemoteId,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +90,7 @@ func newSqlPostStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) s
|
||||
table.ColMap("Props").SetMaxSize(8000)
|
||||
table.ColMap("Filenames").SetMaxSize(model.POST_FILENAMES_MAX_RUNES)
|
||||
table.ColMap("FileIds").SetMaxSize(300)
|
||||
table.ColMap("RemoteId").SetMaxSize(26)
|
||||
}
|
||||
|
||||
return s
|
||||
@@ -117,7 +119,7 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
|
||||
rootIds := make(map[string]int)
|
||||
maxDateRootIds := make(map[string]int64)
|
||||
for idx, post := range posts {
|
||||
if post.Id != "" {
|
||||
if post.Id != "" && !post.IsRemote() {
|
||||
return nil, idx, store.NewErrInvalidInput("Post", "id", post.Id)
|
||||
}
|
||||
post.PreSave()
|
||||
@@ -211,7 +213,7 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
|
||||
}
|
||||
}
|
||||
|
||||
unknownRepliesPosts := []*model.Post{}
|
||||
var unknownRepliesPosts []*model.Post
|
||||
for _, post := range posts {
|
||||
if post.RootId == "" {
|
||||
count, ok := rootIds[post.Id]
|
||||
@@ -521,9 +523,23 @@ func (s *SqlPostStore) Get(ctx context.Context, id string, skipFetchThreads, col
|
||||
return pl, nil
|
||||
}
|
||||
|
||||
func (s *SqlPostStore) GetSingle(id string) (*model.Post, error) {
|
||||
func (s *SqlPostStore) GetSingle(id string, inclDeleted bool) (*model.Post, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("Posts").
|
||||
Where(sq.Eq{"Id": id})
|
||||
|
||||
if !inclDeleted {
|
||||
query = query.Where(sq.Eq{"DeleteAt": 0})
|
||||
}
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getsingleincldeleted_tosql")
|
||||
}
|
||||
|
||||
var post model.Post
|
||||
err := s.GetReplica().SelectOne(&post, "SELECT * FROM Posts WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id})
|
||||
err = s.GetReplica().SelectOne(&post, queryString, args...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("Post", id)
|
||||
@@ -869,6 +885,11 @@ func (s *SqlPostStore) GetPostsSince(options model.GetPostsSinceOptions, allowFr
|
||||
|
||||
var posts []*model.Post
|
||||
|
||||
order := "DESC"
|
||||
if options.SortAscending {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
replyCountQuery1 := ""
|
||||
replyCountQuery2 := ""
|
||||
if options.SkipFetchThreads {
|
||||
@@ -905,7 +926,7 @@ func (s *SqlPostStore) GetPostsSince(options model.GetPostsSinceOptions, allowFr
|
||||
AND ChannelId = :ChannelId
|
||||
LIMIT 1000) temp_tab))
|
||||
) j ON p1.Id = j.Id
|
||||
ORDER BY CreateAt DESC`
|
||||
ORDER BY CreateAt ` + order
|
||||
} else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
||||
query = `WITH cte AS (SELECT
|
||||
*
|
||||
@@ -917,7 +938,7 @@ func (s *SqlPostStore) GetPostsSince(options model.GetPostsSinceOptions, allowFr
|
||||
(SELECT *` + replyCountQuery2 + ` FROM cte)
|
||||
UNION
|
||||
(SELECT *` + replyCountQuery1 + ` FROM Posts p1 WHERE id in (SELECT rootid FROM cte))
|
||||
ORDER BY CreateAt DESC`
|
||||
ORDER BY CreateAt ` + order
|
||||
}
|
||||
_, err := s.GetReplica().Select(&posts, query, map[string]interface{}{"ChannelId": options.ChannelId, "Time": options.Time})
|
||||
|
||||
@@ -937,6 +958,56 @@ func (s *SqlPostStore) GetPostsSince(options model.GetPostsSinceOptions, allowFr
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (s *SqlPostStore) GetPostsSinceForSync(options model.GetPostsSinceForSyncOptions, _ /* allowFromCache */ bool) ([]*model.Post, error) {
|
||||
if options.Limit < 0 || options.Limit > 1000 {
|
||||
return nil, store.NewErrInvalidInput("Post", "<options.Limit>", options.Limit)
|
||||
}
|
||||
|
||||
order := " ASC"
|
||||
if options.SortDescending {
|
||||
order = " DESC"
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("Posts").
|
||||
Where(sq.GtOrEq{"UpdateAt": options.Since}).
|
||||
Where(sq.Eq{"ChannelId": options.ChannelId}).
|
||||
Limit(uint64(options.Limit)).
|
||||
OrderBy("CreateAt"+order, "DeleteAt", "Id")
|
||||
|
||||
if options.Until > 0 {
|
||||
query = query.Where(sq.LtOrEq{"UpdateAt": options.Until})
|
||||
}
|
||||
|
||||
if !options.IncludeDeleted {
|
||||
query = query.Where(sq.Eq{"DeleteAt": 0})
|
||||
}
|
||||
|
||||
if options.ExcludeRemoteId != "" {
|
||||
query = query.Where(sq.NotEq{"COALESCE(Posts.RemoteId,'')": options.ExcludeRemoteId})
|
||||
}
|
||||
|
||||
if options.Offset > 0 {
|
||||
query = query.Offset(uint64(options.Offset))
|
||||
}
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getpostssinceforsync_tosql")
|
||||
}
|
||||
|
||||
var posts []*model.Post
|
||||
|
||||
_, err = s.GetReplica().Select(&posts, queryString, args...)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to find Posts with channelId=%s", options.ChannelId)
|
||||
}
|
||||
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
func (s *SqlPostStore) GetPostsBefore(options model.GetPostsOptions) (*model.PostList, error) {
|
||||
return s.getPostsAround(true, options)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
"github.com/mattermost/mattermost-server/v5/shared/mlog"
|
||||
"github.com/mattermost/mattermost-server/v5/store"
|
||||
@@ -24,6 +26,7 @@ func newSqlReactionStore(sqlStore *SqlStore) store.ReactionStore {
|
||||
table.ColMap("UserId").SetMaxSize(26)
|
||||
table.ColMap("PostId").SetMaxSize(26)
|
||||
table.ColMap("EmojiName").SetMaxSize(64)
|
||||
table.ColMap("RemoteId").SetMaxSize(26)
|
||||
}
|
||||
|
||||
return s
|
||||
@@ -75,26 +78,56 @@ func (s *SqlReactionStore) Delete(reaction *model.Reaction) (*model.Reaction, er
|
||||
return reaction, nil
|
||||
}
|
||||
|
||||
// GetForPost returns all reactions associated with `postId` that are not deleted.
|
||||
func (s *SqlReactionStore) GetForPost(postId string, allowFromCache bool) ([]*model.Reaction, error) {
|
||||
var reactions []*model.Reaction
|
||||
queryString, args, err := s.getQueryBuilder().
|
||||
Select("UserId", "PostId", "EmojiName", "CreateAt", "COALESCE(UpdateAt, CreateAt) As UpdateAt",
|
||||
"COALESCE(DeleteAt, 0) As DeleteAt", "RemoteId").
|
||||
From("Reactions").
|
||||
Where(sq.Eq{"PostId": postId}).
|
||||
Where(sq.Eq{"COALESCE(DeleteAt, 0)": 0}).
|
||||
OrderBy("CreateAt").
|
||||
ToSql()
|
||||
|
||||
if _, err := s.GetReplica().Select(&reactions,
|
||||
`SELECT
|
||||
UserId,
|
||||
PostId,
|
||||
EmojiName,
|
||||
CreateAt,
|
||||
COALESCE(UpdateAt, CreateAt) As UpdateAt,
|
||||
COALESCE(DeleteAt, 0) As DeleteAt
|
||||
FROM
|
||||
Reactions
|
||||
WHERE
|
||||
PostId = :PostId AND COALESCE(DeleteAt, 0) = 0
|
||||
ORDER BY
|
||||
CreateAt`, map[string]interface{}{"PostId": postId}); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get Reactions with postId=%s", postId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reactions_getforpost_tosql")
|
||||
}
|
||||
|
||||
var reactions []*model.Reaction
|
||||
if _, err := s.GetReplica().Select(&reactions, queryString, args...); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get Reactions with postId=%s", postId)
|
||||
}
|
||||
return reactions, nil
|
||||
}
|
||||
|
||||
// GetForPostSince returns all reactions associated with `postId` updated after `since`.
|
||||
func (s *SqlReactionStore) GetForPostSince(postId string, since int64, excludeRemoteId string, inclDeleted bool) ([]*model.Reaction, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("UserId", "PostId", "EmojiName", "CreateAt", "COALESCE(UpdateAt, CreateAt) As UpdateAt",
|
||||
"COALESCE(DeleteAt, 0) As DeleteAt", "RemoteId").
|
||||
From("Reactions").
|
||||
Where(sq.Eq{"PostId": postId}).
|
||||
Where(sq.Gt{"UpdateAt": since})
|
||||
|
||||
if excludeRemoteId != "" {
|
||||
query = query.Where(sq.NotEq{"COALESCE(RemoteId, '')": excludeRemoteId})
|
||||
}
|
||||
|
||||
if !inclDeleted {
|
||||
query = query.Where(sq.Eq{"COALESCE(DeleteAt, 0)": 0})
|
||||
}
|
||||
|
||||
query.OrderBy("CreateAt")
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reactions_getforpostsince_tosql")
|
||||
}
|
||||
|
||||
var reactions []*model.Reaction
|
||||
if _, err := s.GetReplica().Select(&reactions, queryString, args...); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to find reactions")
|
||||
}
|
||||
return reactions, nil
|
||||
}
|
||||
|
||||
@@ -109,7 +142,8 @@ func (s *SqlReactionStore) BulkGetForPosts(postIds []string) ([]*model.Reaction,
|
||||
EmojiName,
|
||||
CreateAt,
|
||||
COALESCE(UpdateAt, CreateAt) As UpdateAt,
|
||||
COALESCE(DeleteAt, 0) As DeleteAt
|
||||
COALESCE(DeleteAt, 0) As DeleteAt,
|
||||
RemoteId
|
||||
FROM
|
||||
Reactions
|
||||
WHERE
|
||||
@@ -133,16 +167,17 @@ func (s *SqlReactionStore) DeleteAllWithEmojiName(emojiName string) error {
|
||||
|
||||
if _, err := s.GetReplica().Select(&reactions,
|
||||
`SELECT
|
||||
UserId,
|
||||
PostId,
|
||||
EmojiName,
|
||||
CreateAt,
|
||||
COALESCE(UpdateAt, CreateAt) As UpdateAt,
|
||||
COALESCE(DeleteAt, 0) As DeleteAt
|
||||
FROM
|
||||
Reactions
|
||||
WHERE
|
||||
EmojiName = :EmojiName AND COALESCE(DeleteAt, 0) = 0`, params); err != nil {
|
||||
UserId,
|
||||
PostId,
|
||||
EmojiName,
|
||||
CreateAt,
|
||||
COALESCE(UpdateAt, CreateAt) As UpdateAt,
|
||||
COALESCE(DeleteAt, 0) As DeleteAt,
|
||||
RemoteId
|
||||
FROM
|
||||
Reactions
|
||||
WHERE
|
||||
EmojiName = :EmojiName AND COALESCE(DeleteAt, 0) = 0`, params); err != nil {
|
||||
return errors.Wrapf(err, "failed to get Reactions with emojiName=%s", emojiName)
|
||||
}
|
||||
|
||||
@@ -201,28 +236,29 @@ func (s *SqlReactionStore) saveReactionAndUpdatePost(transaction *gorp.Transacti
|
||||
"EmojiName": reaction.EmojiName,
|
||||
"CreateAt": reaction.CreateAt,
|
||||
"UpdateAt": reaction.UpdateAt,
|
||||
"RemoteId": reaction.RemoteId,
|
||||
}
|
||||
|
||||
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||
if _, err := transaction.Exec(
|
||||
`INSERT INTO
|
||||
Reactions
|
||||
(UserId, PostId, EmojiName, CreateAt, UpdateAt, DeleteAt)
|
||||
(UserId, PostId, EmojiName, CreateAt, UpdateAt, DeleteAt, RemoteId)
|
||||
VALUES
|
||||
(:UserId, :PostId, :EmojiName, :CreateAt, :UpdateAt, 0)
|
||||
(:UserId, :PostId, :EmojiName, :CreateAt, :UpdateAt, 0, :RemoteId)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
UpdateAt = :UpdateAt, DeleteAt = 0`, params); err != nil {
|
||||
UpdateAt = :UpdateAt, DeleteAt = 0, RemoteId = :RemoteId`, params); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
||||
if _, err := transaction.Exec(
|
||||
`INSERT INTO
|
||||
Reactions
|
||||
(UserId, PostId, EmojiName, CreateAt, UpdateAt, DeleteAt)
|
||||
(UserId, PostId, EmojiName, CreateAt, UpdateAt, DeleteAt, RemoteId)
|
||||
VALUES
|
||||
(:UserId, :PostId, :EmojiName, :CreateAt, :UpdateAt, 0)
|
||||
(:UserId, :PostId, :EmojiName, :CreateAt, :UpdateAt, 0, :RemoteId)
|
||||
ON CONFLICT (UserId, PostId, EmojiName)
|
||||
DO UPDATE SET UpdateAt = :UpdateAt, DeleteAt = 0`, params); err != nil {
|
||||
DO UPDATE SET UpdateAt = :UpdateAt, DeleteAt = 0, RemoteId = :RemoteId`, params); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -237,13 +273,14 @@ func deleteReactionAndUpdatePost(transaction *gorp.Transaction, reaction *model.
|
||||
"CreateAt": reaction.CreateAt,
|
||||
"UpdateAt": reaction.UpdateAt,
|
||||
"DeleteAt": reaction.UpdateAt, // DeleteAt = UpdateAt
|
||||
"RemoteId": reaction.RemoteId,
|
||||
}
|
||||
|
||||
if _, err := transaction.Exec(
|
||||
`UPDATE
|
||||
Reactions
|
||||
SET
|
||||
UpdateAt = :UpdateAt, DeleteAt = :DeleteAt
|
||||
UpdateAt = :UpdateAt, DeleteAt = :DeleteAt, RemoteId = :RemoteId
|
||||
WHERE
|
||||
PostId = :PostId AND
|
||||
UserId = :UserId AND
|
||||
|
||||
186
store/sqlstore/remote_cluster_store.go
Обычный файл
186
store/sqlstore/remote_cluster_store.go
Обычный файл
@@ -0,0 +1,186 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
"github.com/mattermost/mattermost-server/v5/store"
|
||||
)
|
||||
|
||||
type sqlRemoteClusterStore struct {
|
||||
*SqlStore
|
||||
}
|
||||
|
||||
func newSqlRemoteClusterStore(sqlStore *SqlStore) store.RemoteClusterStore {
|
||||
s := &sqlRemoteClusterStore{sqlStore}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
table := db.AddTableWithName(model.RemoteCluster{}, "RemoteClusters").SetKeys(false, "RemoteId")
|
||||
table.ColMap("RemoteId").SetMaxSize(26)
|
||||
table.ColMap("RemoteTeamId").SetMaxSize(26)
|
||||
table.ColMap("DisplayName").SetMaxSize(64)
|
||||
table.ColMap("SiteURL").SetMaxSize(512)
|
||||
table.ColMap("Token").SetMaxSize(26)
|
||||
table.ColMap("RemoteToken").SetMaxSize(26)
|
||||
table.ColMap("Topics").SetMaxSize(512)
|
||||
table.ColMap("CreatorId").SetMaxSize(26)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) Save(remoteCluster *model.RemoteCluster) (*model.RemoteCluster, error) {
|
||||
remoteCluster.PreSave()
|
||||
if err := remoteCluster.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(remoteCluster); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to save RemoteCluster")
|
||||
}
|
||||
return remoteCluster, nil
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) Update(remoteCluster *model.RemoteCluster) (*model.RemoteCluster, error) {
|
||||
remoteCluster.PreUpdate()
|
||||
if err := remoteCluster.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := s.GetMaster().Update(remoteCluster); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to update RemoteCluster")
|
||||
}
|
||||
return remoteCluster, nil
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) Delete(remoteId string) (bool, error) {
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Delete("RemoteClusters").
|
||||
Where(sq.Eq{"RemoteId": remoteId}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "delete_remote_cluster_tosql")
|
||||
}
|
||||
|
||||
result, err := s.GetMaster().Exec(squery, args...)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to delete RemoteCluster")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to determine rows affected")
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) Get(remoteId string) (*model.RemoteCluster, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("RemoteClusters").
|
||||
Where(sq.Eq{"RemoteId": remoteId})
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "remote_cluster_get_tosql")
|
||||
}
|
||||
|
||||
var rc model.RemoteCluster
|
||||
if err := s.GetReplica().SelectOne(&rc, queryString, args...); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to find RemoteCluster")
|
||||
}
|
||||
return &rc, nil
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("rc.*").
|
||||
From("RemoteClusters rc")
|
||||
|
||||
if filter.InChannel != "" {
|
||||
query = query.Where("rc.RemoteId IN (SELECT scr.RemoteId FROM SharedChannelRemotes scr WHERE scr.ChannelId = ?)", filter.InChannel)
|
||||
}
|
||||
|
||||
if filter.NotInChannel != "" {
|
||||
query = query.Where("rc.RemoteId NOT IN (SELECT scr.RemoteId FROM SharedChannelRemotes scr WHERE scr.ChannelId = ?)", filter.NotInChannel)
|
||||
}
|
||||
|
||||
if filter.ExcludeOffline {
|
||||
query = query.Where(sq.Gt{"rc.LastPingAt": model.GetMillis() - model.RemoteOfflineAfterMillis})
|
||||
}
|
||||
|
||||
if filter.CreatorId != "" {
|
||||
query = query.Where(sq.Eq{"rc.CreatorId": filter.CreatorId})
|
||||
}
|
||||
|
||||
if filter.OnlyConfirmed {
|
||||
query = query.Where(sq.NotEq{"rc.SiteURL": ""})
|
||||
}
|
||||
|
||||
if filter.Topic != "" {
|
||||
trimmed := strings.TrimSpace(filter.Topic)
|
||||
if trimmed == "" || trimmed == "*" {
|
||||
return nil, errors.New("invalid topic")
|
||||
}
|
||||
queryTopic := fmt.Sprintf("%% %s %%", trimmed)
|
||||
query = query.Where(sq.Or{sq.Like{"rc.Topics": queryTopic}, sq.Eq{"rc.Topics": "*"}})
|
||||
}
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "remote_cluster_getall_tosql")
|
||||
}
|
||||
|
||||
var list []*model.RemoteCluster
|
||||
if _, err := s.GetReplica().Select(&list, queryString, args...); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to find RemoteClusters")
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) UpdateTopics(remoteClusterid string, topics string) (*model.RemoteCluster, error) {
|
||||
rc, err := s.Get(remoteClusterid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rc.Topics = topics
|
||||
|
||||
rc.PreUpdate()
|
||||
|
||||
if _, err = s.GetMaster().Update(rc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) SetLastPingAt(remoteClusterId string) error {
|
||||
query := s.getQueryBuilder().
|
||||
Update("RemoteClusters").
|
||||
Set("LastPingAt", model.GetMillis()).
|
||||
Where(sq.Eq{"RemoteId": remoteClusterId})
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "remote_cluster_tosql")
|
||||
}
|
||||
|
||||
if _, err := s.GetMaster().Exec(queryString, args...); err != nil {
|
||||
return errors.Wrap(err, "failed to update RemoteCluster")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sqlRemoteClusterStore) createIndexesIfNotExists() {
|
||||
uniquenessColumns := []string{"SiteUrl", "RemoteTeamId"}
|
||||
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||
uniquenessColumns = []string{"RemoteTeamId", "SiteUrl(168)"}
|
||||
}
|
||||
s.CreateUniqueCompositeIndexIfNotExists(RemoteClusterSiteURLUniqueIndex, "RemoteClusters", uniquenessColumns)
|
||||
}
|
||||
14
store/sqlstore/remote_cluster_store_test.go
Обычный файл
14
store/sqlstore/remote_cluster_store_test.go
Обычный файл
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/store/storetest"
|
||||
)
|
||||
|
||||
func TestRemoteClusterStore(t *testing.T) {
|
||||
StoreTest(t, storetest.TestRemoteClusterStore)
|
||||
}
|
||||
712
store/sqlstore/shared_channel_store.go
Обычный файл
712
store/sqlstore/shared_channel_store.go
Обычный файл
@@ -0,0 +1,712 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
"github.com/mattermost/mattermost-server/v5/store"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type SqlSharedChannelStore struct {
|
||||
*SqlStore
|
||||
}
|
||||
|
||||
func newSqlSharedChannelStore(sqlStore *SqlStore) store.SharedChannelStore {
|
||||
s := &SqlSharedChannelStore{
|
||||
SqlStore: sqlStore,
|
||||
}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
tableSharedChannels := db.AddTableWithName(model.SharedChannel{}, "SharedChannels").SetKeys(false, "ChannelId")
|
||||
tableSharedChannels.ColMap("ChannelId").SetMaxSize(26)
|
||||
tableSharedChannels.ColMap("TeamId").SetMaxSize(26)
|
||||
tableSharedChannels.ColMap("CreatorId").SetMaxSize(26)
|
||||
tableSharedChannels.ColMap("ShareName").SetMaxSize(64)
|
||||
tableSharedChannels.SetUniqueTogether("ShareName", "TeamId")
|
||||
tableSharedChannels.ColMap("ShareDisplayName").SetMaxSize(64)
|
||||
tableSharedChannels.ColMap("SharePurpose").SetMaxSize(250)
|
||||
tableSharedChannels.ColMap("ShareHeader").SetMaxSize(1024)
|
||||
tableSharedChannels.ColMap("RemoteId").SetMaxSize(26)
|
||||
|
||||
tableSharedChannelRemotes := db.AddTableWithName(model.SharedChannelRemote{}, "SharedChannelRemotes").SetKeys(false, "Id", "ChannelId")
|
||||
tableSharedChannelRemotes.ColMap("Id").SetMaxSize(26)
|
||||
tableSharedChannelRemotes.ColMap("ChannelId").SetMaxSize(26)
|
||||
tableSharedChannelRemotes.ColMap("Description").SetMaxSize(64)
|
||||
tableSharedChannelRemotes.ColMap("CreatorId").SetMaxSize(26)
|
||||
tableSharedChannelRemotes.ColMap("RemoteId").SetMaxSize(26)
|
||||
tableSharedChannelRemotes.SetUniqueTogether("ChannelId", "RemoteId")
|
||||
|
||||
tableSharedChannelUsers := db.AddTableWithName(model.SharedChannelUser{}, "SharedChannelUsers").SetKeys(false, "Id")
|
||||
tableSharedChannelUsers.ColMap("Id").SetMaxSize(26)
|
||||
tableSharedChannelUsers.ColMap("UserId").SetMaxSize(26)
|
||||
tableSharedChannelUsers.ColMap("RemoteId").SetMaxSize(26)
|
||||
tableSharedChannelUsers.SetUniqueTogether("UserId", "RemoteId")
|
||||
|
||||
tableSharedChannelFiles := db.AddTableWithName(model.SharedChannelAttachment{}, "SharedChannelAttachments").SetKeys(false, "Id")
|
||||
tableSharedChannelFiles.ColMap("Id").SetMaxSize(26)
|
||||
tableSharedChannelFiles.ColMap("FileId").SetMaxSize(26)
|
||||
tableSharedChannelFiles.ColMap("RemoteId").SetMaxSize(26)
|
||||
tableSharedChannelFiles.SetUniqueTogether("FileId", "RemoteId")
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s SqlSharedChannelStore) createIndexesIfNotExists() {
|
||||
s.CreateIndexIfNotExists("idx_sharedchannelusers_user_id", "SharedChannelUsers", "UserId")
|
||||
s.CreateIndexIfNotExists("idx_sharedchannelusers_remote_id", "SharedChannelUsers", "RemoteId")
|
||||
}
|
||||
|
||||
// Save inserts a new shared channel record.
|
||||
func (s SqlSharedChannelStore) Save(sc *model.SharedChannel) (*model.SharedChannel, error) {
|
||||
sc.PreSave()
|
||||
if err := sc.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// make sure the shared channel is associated with a real channel.
|
||||
channel, err := s.stores.channel.Get(sc.ChannelId, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid channel: %w", err)
|
||||
}
|
||||
|
||||
transaction, err := s.GetMaster().Begin()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "begin_transaction")
|
||||
}
|
||||
defer finalizeTransaction(transaction)
|
||||
|
||||
if err := transaction.Insert(sc); err != nil {
|
||||
return nil, errors.Wrapf(err, "save_shared_channel: ChannelId=%s", sc.ChannelId)
|
||||
}
|
||||
|
||||
// set `Shared` flag in Channels table if needed
|
||||
if channel.Shared == nil || !*channel.Shared {
|
||||
if err := s.stores.channel.SetShared(channel.Id, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := transaction.Commit(); err != nil {
|
||||
return nil, errors.Wrap(err, "commit_transaction")
|
||||
}
|
||||
return sc, nil
|
||||
}
|
||||
|
||||
// Get fetches a shared channel by channel_id.
|
||||
func (s SqlSharedChannelStore) Get(channelId string) (*model.SharedChannel, error) {
|
||||
var sc model.SharedChannel
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("SharedChannels").
|
||||
Where(sq.Eq{"SharedChannels.ChannelId": channelId})
|
||||
|
||||
squery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getsharedchannel_tosql")
|
||||
}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&sc, squery, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("SharedChannel", channelId)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to find shared channel with ChannelId=%s", channelId)
|
||||
}
|
||||
return &sc, nil
|
||||
}
|
||||
|
||||
// HasChannel returns whether a given channelID is a shared channel or not.
|
||||
func (s SqlSharedChannelStore) HasChannel(channelID string) (bool, error) {
|
||||
builder := s.getQueryBuilder().
|
||||
Select("1").
|
||||
Prefix("SELECT EXISTS (").
|
||||
From("SharedChannels").
|
||||
Where(sq.Eq{"SharedChannels.ChannelId": channelID}).
|
||||
Suffix(")")
|
||||
|
||||
query, args, err := builder.ToSql()
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "get_shared_channel_exists_tosql")
|
||||
}
|
||||
|
||||
var exists bool
|
||||
if err := s.GetReplica().SelectOne(&exists, query, args...); err != nil {
|
||||
return exists, errors.Wrapf(err, "failed to get shared channel for channel_id=%s", channelID)
|
||||
}
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
// GetAll fetches a paginated list of shared channels filtered by SharedChannelSearchOpts.
|
||||
func (s SqlSharedChannelStore) GetAll(offset, limit int, opts model.SharedChannelFilterOpts) ([]*model.SharedChannel, error) {
|
||||
if opts.ExcludeHome && opts.ExcludeRemote {
|
||||
return nil, errors.New("cannot exclude home and remote shared channels")
|
||||
}
|
||||
|
||||
safeConv := func(offset, limit int) (uint64, uint64, error) {
|
||||
if offset < 0 {
|
||||
return 0, 0, errors.New("offset must be positive integer")
|
||||
}
|
||||
if limit < 0 {
|
||||
return 0, 0, errors.New("limit must be positive integer")
|
||||
}
|
||||
return uint64(offset), uint64(limit), nil
|
||||
}
|
||||
|
||||
safeOffset, safeLimit, err := safeConv(offset, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := s.getSharedChannelsQuery(opts, false)
|
||||
query = query.OrderBy("sc.ShareDisplayName, sc.ShareName").Limit(safeLimit).Offset(safeOffset)
|
||||
|
||||
squery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create query")
|
||||
}
|
||||
|
||||
var channels []*model.SharedChannel
|
||||
_, err = s.GetReplica().Select(&channels, squery, args...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get shared channels")
|
||||
}
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
// GetAllCount returns the number of shared channels that would be fetched using SharedChannelSearchOpts.
|
||||
func (s SqlSharedChannelStore) GetAllCount(opts model.SharedChannelFilterOpts) (int64, error) {
|
||||
if opts.ExcludeHome && opts.ExcludeRemote {
|
||||
return 0, errors.New("cannot exclude home and remote shared channels")
|
||||
}
|
||||
|
||||
query := s.getSharedChannelsQuery(opts, true)
|
||||
squery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to create query")
|
||||
}
|
||||
|
||||
count, err := s.GetReplica().SelectInt(squery, args...)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count channels")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s SqlSharedChannelStore) getSharedChannelsQuery(opts model.SharedChannelFilterOpts, forCount bool) sq.SelectBuilder {
|
||||
var selectStr string
|
||||
if forCount {
|
||||
selectStr = "count(sc.ChannelId)"
|
||||
} else {
|
||||
selectStr = "sc.*"
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select(selectStr).
|
||||
From("SharedChannels AS sc")
|
||||
|
||||
if opts.TeamId != "" {
|
||||
query = query.Where(sq.Eq{"sc.TeamId": opts.TeamId})
|
||||
}
|
||||
|
||||
if opts.CreatorId != "" {
|
||||
query = query.Where(sq.Eq{"sc.CreatorId": opts.CreatorId})
|
||||
}
|
||||
|
||||
if opts.ExcludeHome {
|
||||
query = query.Where(sq.NotEq{"sc.Home": true})
|
||||
}
|
||||
|
||||
if opts.ExcludeRemote {
|
||||
query = query.Where(sq.Eq{"sc.Home": true})
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
// Update updates the shared channel.
|
||||
func (s SqlSharedChannelStore) Update(sc *model.SharedChannel) (*model.SharedChannel, error) {
|
||||
if err := sc.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count, err := s.GetMaster().Update(sc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to update shared channel with channelId=%s", sc.ChannelId)
|
||||
}
|
||||
|
||||
if count != 1 {
|
||||
return nil, fmt.Errorf("expected number of shared channels to be updated is 1 but was %d", count)
|
||||
}
|
||||
return sc, nil
|
||||
}
|
||||
|
||||
// Delete deletes a single shared channel plus associated SharedChannelRemotes.
|
||||
// Returns true if shared channel found and deleted, false if not found.
|
||||
func (s SqlSharedChannelStore) Delete(channelId string) (bool, error) {
|
||||
transaction, err := s.GetMaster().Begin()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "DeleteSharedChannel: begin_transaction")
|
||||
}
|
||||
defer finalizeTransaction(transaction)
|
||||
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Delete("SharedChannels").
|
||||
Where(sq.Eq{"SharedChannels.ChannelId": channelId}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "delete_shared_channel_tosql")
|
||||
}
|
||||
|
||||
result, err := transaction.Exec(squery, args...)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to delete SharedChannel")
|
||||
}
|
||||
|
||||
// Also remove remotes from SharedChannelRemotes (if any).
|
||||
squery, args, err = s.getQueryBuilder().
|
||||
Delete("SharedChannelRemotes").
|
||||
Where(sq.Eq{"ChannelId": channelId}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "delete_shared_channel_remotes_tosql")
|
||||
}
|
||||
|
||||
_, err = transaction.Exec(squery, args...)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to delete SharedChannelRemotes")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to determine rows affected")
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
// unset the channel's Shared flag
|
||||
if err = s.Channel().SetShared(channelId, false); err != nil {
|
||||
return false, errors.Wrap(err, "error unsetting channel share flag")
|
||||
}
|
||||
}
|
||||
|
||||
if err = transaction.Commit(); err != nil {
|
||||
return false, errors.Wrap(err, "commit_transaction")
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// SaveRemote inserts a new shared channel remote record.
|
||||
func (s SqlSharedChannelStore) SaveRemote(remote *model.SharedChannelRemote) (*model.SharedChannelRemote, error) {
|
||||
remote.PreSave()
|
||||
if err := remote.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// make sure the shared channel remote is associated with a real channel.
|
||||
if _, err := s.stores.channel.Get(remote.ChannelId, true); err != nil {
|
||||
return nil, fmt.Errorf("invalid channel: %w", err)
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(remote); err != nil {
|
||||
return nil, errors.Wrapf(err, "save_shared_channel_remote: channel_id=%s, id=%s", remote.ChannelId, remote.Id)
|
||||
}
|
||||
return remote, nil
|
||||
}
|
||||
|
||||
// Update updates the shared channel remote.
|
||||
func (s SqlSharedChannelStore) UpdateRemote(remote *model.SharedChannelRemote) (*model.SharedChannelRemote, error) {
|
||||
if err := remote.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count, err := s.GetMaster().Update(remote)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to update shared channel remote with remoteId=%s", remote.Id)
|
||||
}
|
||||
|
||||
if count != 1 {
|
||||
return nil, fmt.Errorf("expected number of shared channel remotes to be updated is 1 but was %d", count)
|
||||
}
|
||||
return remote, nil
|
||||
}
|
||||
|
||||
// GetRemote fetches a shared channel remote by id.
|
||||
func (s SqlSharedChannelStore) GetRemote(id string) (*model.SharedChannelRemote, error) {
|
||||
var remote model.SharedChannelRemote
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("SharedChannelRemotes").
|
||||
Where(sq.Eq{"SharedChannelRemotes.Id": id})
|
||||
|
||||
squery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get_shared_channel_remote_tosql")
|
||||
}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&remote, squery, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("SharedChannelRemote", id)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to find shared channel remote with id=%s", id)
|
||||
}
|
||||
return &remote, nil
|
||||
}
|
||||
|
||||
// GetRemoteByIds fetches a shared channel remote by channel id and remote cluster id.
|
||||
func (s SqlSharedChannelStore) GetRemoteByIds(channelId string, remoteId string) (*model.SharedChannelRemote, error) {
|
||||
var remote model.SharedChannelRemote
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("SharedChannelRemotes").
|
||||
Where(sq.Eq{"SharedChannelRemotes.ChannelId": channelId}).
|
||||
Where(sq.Eq{"SharedChannelRemotes.RemoteId": remoteId})
|
||||
|
||||
squery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get_shared_channel_remote_by_ids_tosql")
|
||||
}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&remote, squery, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("SharedChannelRemote", fmt.Sprintf("channelId=%s, remoteId=%s", channelId, remoteId))
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to find shared channel remote with channelId=%s, remoteId=%s", channelId, remoteId)
|
||||
}
|
||||
return &remote, nil
|
||||
}
|
||||
|
||||
// GetRemotes fetches all shared channel remotes associated with channel_id.
|
||||
func (s SqlSharedChannelStore) GetRemotes(opts model.SharedChannelRemoteFilterOpts) ([]*model.SharedChannelRemote, error) {
|
||||
var remotes []*model.SharedChannelRemote
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("SharedChannelRemotes")
|
||||
|
||||
if opts.ChannelId != "" {
|
||||
query = query.Where(sq.Eq{"ChannelId": opts.ChannelId})
|
||||
}
|
||||
|
||||
if opts.RemoteId != "" {
|
||||
query = query.Where(sq.Eq{"RemoteId": opts.RemoteId})
|
||||
}
|
||||
|
||||
if !opts.InclUnconfirmed {
|
||||
query = query.Where(sq.Eq{"IsInviteConfirmed": true})
|
||||
}
|
||||
|
||||
squery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get_shared_channel_remotes_tosql")
|
||||
}
|
||||
|
||||
if _, err := s.GetReplica().Select(&remotes, squery, args...); err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return nil, errors.Wrapf(err, "failed to get shared channel remotes for channel_id=%s; remote_id=%s",
|
||||
opts.ChannelId, opts.RemoteId)
|
||||
}
|
||||
}
|
||||
return remotes, nil
|
||||
}
|
||||
|
||||
// HasRemote returns whether a given remoteId and channelId are present in the shared channel remotes or not.
|
||||
func (s SqlSharedChannelStore) HasRemote(channelID string, remoteId string) (bool, error) {
|
||||
builder := s.getQueryBuilder().
|
||||
Select("1").
|
||||
Prefix("SELECT EXISTS (").
|
||||
From("SharedChannelRemotes").
|
||||
Where(sq.Eq{"RemoteId": remoteId}).
|
||||
Where(sq.Eq{"ChannelId": channelID}).
|
||||
Suffix(")")
|
||||
|
||||
query, args, err := builder.ToSql()
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "get_shared_channel_hasremote_tosql")
|
||||
}
|
||||
|
||||
var hasRemote bool
|
||||
if err := s.GetReplica().SelectOne(&hasRemote, query, args...); err != nil {
|
||||
return hasRemote, errors.Wrapf(err, "failed to get channel remotes for channel_id=%s", channelID)
|
||||
}
|
||||
return hasRemote, nil
|
||||
}
|
||||
|
||||
// GetRemoteForUser returns a remote cluster for the given userId only if the user belongs to at least one channel
|
||||
// shared with the remote.
|
||||
func (s SqlSharedChannelStore) GetRemoteForUser(remoteId string, userId string) (*model.RemoteCluster, error) {
|
||||
builder := s.getQueryBuilder().
|
||||
Select("rc.*").
|
||||
From("RemoteClusters AS rc").
|
||||
Join("SharedChannelRemotes AS scr ON rc.RemoteId = scr.RemoteId").
|
||||
Join("ChannelMembers AS cm ON scr.ChannelId = cm.ChannelId").
|
||||
Where(sq.Eq{"rc.RemoteId": remoteId}).
|
||||
Where(sq.Eq{"cm.UserId": userId})
|
||||
|
||||
query, args, err := builder.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get_remote_for_user_tosql")
|
||||
}
|
||||
|
||||
var rc model.RemoteCluster
|
||||
if err := s.GetReplica().SelectOne(&rc, query, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("RemoteCluster", remoteId)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to get remote for user_id=%s", userId)
|
||||
}
|
||||
return &rc, nil
|
||||
}
|
||||
|
||||
// UpdateRemoteNextSyncAt updates the NextSyncAt timestamp for the specified SharedChannelRemote.
|
||||
func (s SqlSharedChannelStore) UpdateRemoteNextSyncAt(id string, syncTime int64) error {
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Update("SharedChannelRemotes").
|
||||
Set("NextSyncAt", syncTime).
|
||||
Where(sq.Eq{"Id": id}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "update_shared_channel_remote_next_sync_at_tosql")
|
||||
}
|
||||
|
||||
result, err := s.GetMaster().Exec(squery, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to update NextSyncAt for SharedChannelRemote")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to determine rows affected")
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("id not found: %s", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteRemote deletes a single shared channel remote.
|
||||
// Returns true if remote found and deleted, false if not found.
|
||||
func (s SqlSharedChannelStore) DeleteRemote(id string) (bool, error) {
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Delete("SharedChannelRemotes").
|
||||
Where(sq.Eq{"Id": id}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "delete_shared_channel_remote_tosql")
|
||||
}
|
||||
|
||||
result, err := s.GetMaster().Exec(squery, args...)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to delete SharedChannelRemote")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to determine rows affected")
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// GetRemotesStatus returns the status for each remote invited to the
|
||||
// specified shared channel.
|
||||
func (s SqlSharedChannelStore) GetRemotesStatus(channelId string) ([]*model.SharedChannelRemoteStatus, error) {
|
||||
var status []*model.SharedChannelRemoteStatus
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("scr.ChannelId, rc.DisplayName, rc.SiteURL, rc.LastPingAt, scr.NextSyncAt, scr.Description, sc.ReadOnly, scr.IsInviteAccepted").
|
||||
From("SharedChannelRemotes scr, RemoteClusters rc, SharedChannels sc").
|
||||
Where("scr.RemoteId = rc.RemoteId").
|
||||
Where("scr.ChannelId = sc.ChannelId").
|
||||
Where(sq.Eq{"scr.ChannelId": channelId})
|
||||
|
||||
squery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get_shared_channel_remotes_status_tosql")
|
||||
}
|
||||
|
||||
if _, err := s.GetReplica().Select(&status, squery, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("SharedChannelRemoteStatus", channelId)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to get shared channel remote status for channel_id=%s", channelId)
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// SaveUser inserts a new shared channel user record to the SharedChannelUsers table.
|
||||
func (s SqlSharedChannelStore) SaveUser(scUser *model.SharedChannelUser) (*model.SharedChannelUser, error) {
|
||||
scUser.PreSave()
|
||||
if err := scUser.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(scUser); err != nil {
|
||||
return nil, errors.Wrapf(err, "save_shared_channel_user: user_id=%s, remote_id=%s", scUser.UserId, scUser.RemoteId)
|
||||
}
|
||||
return scUser, nil
|
||||
}
|
||||
|
||||
// GetUser fetches a shared channel user based on user_id and remoteId.
|
||||
func (s SqlSharedChannelStore) GetUser(userId string, remoteId string) (*model.SharedChannelUser, error) {
|
||||
var scu model.SharedChannelUser
|
||||
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("SharedChannelUsers").
|
||||
Where(sq.Eq{"SharedChannelUsers.UserId": userId}).
|
||||
Where(sq.Eq{"SharedChannelUsers.RemoteId": remoteId}).
|
||||
ToSql()
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getsharedchanneluser_tosql")
|
||||
}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&scu, squery, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("SharedChannelUser", userId)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to find shared channel user with UserId=%s, RemoteId=%s", userId, remoteId)
|
||||
}
|
||||
return &scu, nil
|
||||
}
|
||||
|
||||
// UpdateUserLastSyncAt updates the LastSyncAt timestamp for the specified SharedChannelUser.
|
||||
func (s SqlSharedChannelStore) UpdateUserLastSyncAt(id string, syncTime int64) error {
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Update("SharedChannelUsers").
|
||||
Set("LastSyncAt", syncTime).
|
||||
Where(sq.Eq{"Id": id}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "update_shared_channel_user_last_sync_at_tosql")
|
||||
}
|
||||
|
||||
result, err := s.GetMaster().Exec(squery, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to update LastSycnAt for SharedChannelUser")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to determine rows affected")
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("id not found: %s", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveAttachment inserts a new shared channel file attachment record to the SharedChannelFiles table.
|
||||
func (s SqlSharedChannelStore) SaveAttachment(attachment *model.SharedChannelAttachment) (*model.SharedChannelAttachment, error) {
|
||||
attachment.PreSave()
|
||||
if err := attachment.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(attachment); err != nil {
|
||||
return nil, errors.Wrapf(err, "save_shared_channel_attachment: file_id=%s, remote_id=%s", attachment.FileId, attachment.RemoteId)
|
||||
}
|
||||
return attachment, nil
|
||||
}
|
||||
|
||||
// UpsertAttachment inserts a new shared channel file attachment record to the SharedChannelFiles table or updates its
|
||||
// LastSyncAt.
|
||||
func (s SqlSharedChannelStore) UpsertAttachment(attachment *model.SharedChannelAttachment) (string, error) {
|
||||
attachment.PreSave()
|
||||
if err := attachment.IsValid(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
params := map[string]interface{}{
|
||||
"Id": attachment.Id,
|
||||
"FileId": attachment.FileId,
|
||||
"RemoteId": attachment.RemoteId,
|
||||
"CreateAt": attachment.CreateAt,
|
||||
"LastSyncAt": attachment.LastSyncAt,
|
||||
}
|
||||
|
||||
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||
if _, err := s.GetMaster().Exec(
|
||||
`INSERT INTO
|
||||
SharedChannelAttachments
|
||||
(Id, FileId, RemoteId, CreateAt, LastSyncAt)
|
||||
VALUES
|
||||
(:Id, :FileId, :RemoteId, :CreateAt, :LastSyncAt)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
LastSyncAt = :LastSyncAt`, params); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
||||
if _, err := s.GetMaster().Exec(
|
||||
`INSERT INTO
|
||||
SharedChannelAttachments
|
||||
(Id, FileId, RemoteId, CreateAt, LastSyncAt)
|
||||
VALUES
|
||||
(:Id, :FileId, :RemoteId, :CreateAt, :LastSyncAt)
|
||||
ON CONFLICT (Id)
|
||||
DO UPDATE SET LastSyncAt = :LastSyncAt`, params); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return attachment.Id, nil
|
||||
}
|
||||
|
||||
// GetAttachment fetches a shared channel file attachment record based on file_id and remoteId.
|
||||
func (s SqlSharedChannelStore) GetAttachment(fileId string, remoteId string) (*model.SharedChannelAttachment, error) {
|
||||
var attachment model.SharedChannelAttachment
|
||||
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Select("*").
|
||||
From("SharedChannelAttachments").
|
||||
Where(sq.Eq{"SharedChannelAttachments.FileId": fileId}).
|
||||
Where(sq.Eq{"SharedChannelAttachments.RemoteId": remoteId}).
|
||||
ToSql()
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getsharedchannelattachment_tosql")
|
||||
}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&attachment, squery, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("SharedChannelAttachment", fileId)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "failed to find shared channel attachment with FileId=%s, RemoteId=%s", fileId, remoteId)
|
||||
}
|
||||
return &attachment, nil
|
||||
}
|
||||
|
||||
// UpdateAttachmentLastSyncAt updates the LastSyncAt timestamp for the specified SharedChannelAttachment.
|
||||
func (s SqlSharedChannelStore) UpdateAttachmentLastSyncAt(id string, syncTime int64) error {
|
||||
squery, args, err := s.getQueryBuilder().
|
||||
Update("SharedChannelAttachments").
|
||||
Set("LastSyncAt", syncTime).
|
||||
Where(sq.Eq{"Id": id}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "update_shared_channel_attachment_last_sync_at_tosql")
|
||||
}
|
||||
|
||||
result, err := s.GetMaster().Exec(squery, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to update LastSycnAt for SharedChannelAttachment")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to determine rows affected")
|
||||
}
|
||||
if count == 0 {
|
||||
return fmt.Errorf("id not found: %s", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
14
store/sqlstore/shared_channel_store_test.go
Обычный файл
14
store/sqlstore/shared_channel_store_test.go
Обычный файл
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/store/storetest"
|
||||
)
|
||||
|
||||
func TestSharedChannelStore(t *testing.T) {
|
||||
StoreTestWithSqlStore(t, storetest.TestSharedChannelStore)
|
||||
}
|
||||
@@ -101,6 +101,7 @@ type SqlStoreStores struct {
|
||||
bot store.BotStore
|
||||
audit store.AuditStore
|
||||
cluster store.ClusterDiscoveryStore
|
||||
remoteCluster store.RemoteClusterStore
|
||||
compliance store.ComplianceStore
|
||||
session store.SessionStore
|
||||
oauth store.OAuthStore
|
||||
@@ -127,6 +128,7 @@ type SqlStoreStores struct {
|
||||
group store.GroupStore
|
||||
UserTermsOfService store.UserTermsOfServiceStore
|
||||
linkMetadata store.LinkMetadataStore
|
||||
sharedchannel store.SharedChannelStore
|
||||
}
|
||||
|
||||
type SqlStore struct {
|
||||
@@ -186,6 +188,7 @@ func New(settings model.SqlSettings, metrics einterfaces.MetricsInterface) *SqlS
|
||||
store.stores.bot = newSqlBotStore(store, metrics)
|
||||
store.stores.audit = newSqlAuditStore(store)
|
||||
store.stores.cluster = newSqlClusterDiscoveryStore(store)
|
||||
store.stores.remoteCluster = newSqlRemoteClusterStore(store)
|
||||
store.stores.compliance = newSqlComplianceStore(store)
|
||||
store.stores.session = newSqlSessionStore(store)
|
||||
store.stores.oauth = newSqlOAuthStore(store)
|
||||
@@ -208,6 +211,7 @@ func New(settings model.SqlSettings, metrics einterfaces.MetricsInterface) *SqlS
|
||||
store.stores.TermsOfService = newSqlTermsOfServiceStore(store, metrics)
|
||||
store.stores.UserTermsOfService = newSqlUserTermsOfServiceStore(store)
|
||||
store.stores.linkMetadata = newSqlLinkMetadataStore(store)
|
||||
store.stores.sharedchannel = newSqlSharedChannelStore(store)
|
||||
store.stores.reaction = newSqlReactionStore(store)
|
||||
store.stores.role = newSqlRoleStore(store)
|
||||
store.stores.scheme = newSqlSchemeStore(store)
|
||||
@@ -258,8 +262,10 @@ func New(settings model.SqlSettings, metrics einterfaces.MetricsInterface) *SqlS
|
||||
store.stores.productNotices.(SqlProductNoticesStore).createIndexesIfNotExists()
|
||||
store.stores.UserTermsOfService.(SqlUserTermsOfServiceStore).createIndexesIfNotExists()
|
||||
store.stores.linkMetadata.(*SqlLinkMetadataStore).createIndexesIfNotExists()
|
||||
store.stores.sharedchannel.(*SqlSharedChannelStore).createIndexesIfNotExists()
|
||||
store.stores.group.(*SqlGroupStore).createIndexesIfNotExists()
|
||||
store.stores.scheme.(*SqlSchemeStore).createIndexesIfNotExists()
|
||||
store.stores.remoteCluster.(*sqlRemoteClusterStore).createIndexesIfNotExists()
|
||||
store.stores.preference.(*SqlPreferenceStore).deleteUnusedFeatures()
|
||||
|
||||
return store
|
||||
@@ -1212,6 +1218,10 @@ func (ss *SqlStore) ClusterDiscovery() store.ClusterDiscoveryStore {
|
||||
return ss.stores.cluster
|
||||
}
|
||||
|
||||
func (ss *SqlStore) RemoteCluster() store.RemoteClusterStore {
|
||||
return ss.stores.remoteCluster
|
||||
}
|
||||
|
||||
func (ss *SqlStore) Compliance() store.ComplianceStore {
|
||||
return ss.stores.compliance
|
||||
}
|
||||
@@ -1316,6 +1326,10 @@ func (ss *SqlStore) LinkMetadata() store.LinkMetadataStore {
|
||||
return ss.stores.linkMetadata
|
||||
}
|
||||
|
||||
func (ss *SqlStore) SharedChannel() store.SharedChannelStore {
|
||||
return ss.stores.sharedchannel
|
||||
}
|
||||
|
||||
func (ss *SqlStore) DropAllTables() {
|
||||
ss.master.TruncateTables()
|
||||
}
|
||||
|
||||
@@ -961,6 +961,8 @@ func upgradeDatabaseToVersion531(sqlStore *SqlStore) {
|
||||
}
|
||||
}
|
||||
|
||||
const RemoteClusterSiteURLUniqueIndex = "remote_clusters_site_url_unique"
|
||||
|
||||
func hasMissingMigrationsVersion532(sqlStore *SqlStore) bool {
|
||||
scIdInfo, err := sqlStore.GetColumnInfo("Posts", "FileIds")
|
||||
if err != nil {
|
||||
@@ -987,6 +989,7 @@ func upgradeDatabaseToVersion532(sqlStore *SqlStore) {
|
||||
}
|
||||
if shouldPerformUpgrade(sqlStore, Version5310, Version5320) {
|
||||
sqlStore.CreateColumnIfNotExists("ThreadMemberships", "UnreadMentions", "bigint", "bigint", "0")
|
||||
// Shared channels support
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "Shared", "tinyint(1)", "boolean")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Reactions", "UpdateAt", "bigint", "bigint")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Reactions", "DeleteAt", "bigint", "bigint")
|
||||
@@ -1011,6 +1014,24 @@ func upgradeDatabaseToVersion535(sqlStore *SqlStore) {
|
||||
|
||||
sqlStore.CreateColumnIfNotExists("SidebarCategories", "Collapsed", "tinyint(1)", "boolean", "0")
|
||||
|
||||
// Shared channels support
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Reactions", "RemoteId", "VARCHAR(26)", "VARCHAR(26)")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Users", "RemoteId", "VARCHAR(26)", "VARCHAR(26)")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Posts", "RemoteId", "VARCHAR(26)", "VARCHAR(26)")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("FileInfo", "RemoteId", "VARCHAR(26)", "VARCHAR(26)")
|
||||
sqlStore.CreateColumnIfNotExists("UploadSessions", "RemoteId", "VARCHAR(26)", "VARCHAR(26)", "")
|
||||
sqlStore.CreateColumnIfNotExists("UploadSessions", "ReqFileId", "VARCHAR(26)", "VARCHAR(26)", "")
|
||||
if _, err := sqlStore.GetMaster().Exec("UPDATE UploadSessions SET RemoteId='', ReqFileId='' WHERE RemoteId IS NULL"); err != nil {
|
||||
mlog.Error("Error updating RemoteId,ReqFileId in UploadsSession table", mlog.Err(err))
|
||||
}
|
||||
uniquenessColumns := []string{"SiteUrl", "RemoteTeamId"}
|
||||
if sqlStore.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||
uniquenessColumns = []string{"RemoteTeamId", "SiteUrl(168)"}
|
||||
}
|
||||
sqlStore.CreateUniqueCompositeIndexIfNotExists(RemoteClusterSiteURLUniqueIndex, "RemoteClusters", uniquenessColumns)
|
||||
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "TotalMsgCountRoot", "bigint", "bigint")
|
||||
|
||||
// note: setting default 0 on pre-5.0 tables causes test-db-migration script to fail, so this column will be added to ignore list
|
||||
sqlStore.CreateColumnIfNotExists("ChannelMembers", "MentionCountRoot", "bigint", "bigint", "0")
|
||||
sqlStore.AlterColumnDefaultIfExists("ChannelMembers", "MentionCountRoot", model.NewString("0"), model.NewString("0"))
|
||||
|
||||
@@ -29,6 +29,8 @@ func newSqlUploadSessionStore(sqlStore *SqlStore) store.UploadSessionStore {
|
||||
table.ColMap("ChannelId").SetMaxSize(26)
|
||||
table.ColMap("Filename").SetMaxSize(256)
|
||||
table.ColMap("Path").SetMaxSize(512)
|
||||
table.ColMap("RemoteId").SetMaxSize(26)
|
||||
table.ColMap("ReqFileId").SetMaxSize(26)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func newSqlUserStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) s
|
||||
// note: we are providing field names explicitly here to maintain order of columns (needed when using raw queries)
|
||||
us.usersQuery = us.getQueryBuilder().
|
||||
Select("u.Id", "u.CreateAt", "u.UpdateAt", "u.DeleteAt", "u.Username", "u.Password", "u.AuthData", "u.AuthService", "u.Email", "u.EmailVerified", "u.Nickname", "u.FirstName", "u.LastName", "u.Position", "u.Roles", "u.AllowMarketing", "u.Props", "u.NotifyProps", "u.LastPasswordUpdate", "u.LastPictureUpdate", "u.FailedAttempts", "u.Locale", "u.Timezone", "u.MfaActive", "u.MfaSecret",
|
||||
"b.UserId IS NOT NULL AS IsBot", "COALESCE(b.Description, '') AS BotDescription", "COALESCE(b.LastIconUpdate, 0) AS BotLastIconUpdate").
|
||||
"b.UserId IS NOT NULL AS IsBot", "COALESCE(b.Description, '') AS BotDescription", "COALESCE(b.LastIconUpdate, 0) AS BotLastIconUpdate", "u.RemoteId").
|
||||
From("Users u").
|
||||
LeftJoin("Bots b ON ( b.UserId = u.Id )")
|
||||
|
||||
@@ -73,6 +73,7 @@ func newSqlUserStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) s
|
||||
table.ColMap("NotifyProps").SetMaxSize(2000)
|
||||
table.ColMap("Locale").SetMaxSize(5)
|
||||
table.ColMap("MfaSecret").SetMaxSize(128)
|
||||
table.ColMap("RemoteId").SetMaxSize(26)
|
||||
table.ColMap("Position").SetMaxSize(128)
|
||||
table.ColMap("Timezone").SetMaxSize(256)
|
||||
}
|
||||
@@ -101,7 +102,7 @@ func (us SqlUserStore) createIndexesIfNotExists() {
|
||||
}
|
||||
|
||||
func (us SqlUserStore) Save(user *model.User) (*model.User, error) {
|
||||
if user.Id != "" {
|
||||
if user.Id != "" && !user.IsRemote() {
|
||||
return nil, store.NewErrInvalidInput("User", "id", user.Id)
|
||||
}
|
||||
|
||||
@@ -358,7 +359,7 @@ func (us SqlUserStore) Get(ctx context.Context, id string) (*model.User, error)
|
||||
&user.Nickname, &user.FirstName, &user.LastName, &user.Position, &user.Roles,
|
||||
&user.AllowMarketing, &props, ¬ifyProps, &user.LastPasswordUpdate, &user.LastPictureUpdate,
|
||||
&user.FailedAttempts, &user.Locale, &timezone, &user.MfaActive, &user.MfaSecret,
|
||||
&user.IsBot, &user.BotDescription, &user.BotLastIconUpdate)
|
||||
&user.IsBot, &user.BotDescription, &user.BotLastIconUpdate, &user.RemoteId)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("User", id)
|
||||
@@ -727,7 +728,7 @@ func (us SqlUserStore) GetAllProfilesInChannel(ctx context.Context, channelID st
|
||||
for rows.Next() {
|
||||
var user model.User
|
||||
var props, notifyProps, timezone []byte
|
||||
if err = rows.Scan(&user.Id, &user.CreateAt, &user.UpdateAt, &user.DeleteAt, &user.Username, &user.Password, &user.AuthData, &user.AuthService, &user.Email, &user.EmailVerified, &user.Nickname, &user.FirstName, &user.LastName, &user.Position, &user.Roles, &user.AllowMarketing, &props, ¬ifyProps, &user.LastPasswordUpdate, &user.LastPictureUpdate, &user.FailedAttempts, &user.Locale, &timezone, &user.MfaActive, &user.MfaSecret, &user.IsBot, &user.BotDescription, &user.BotLastIconUpdate); err != nil {
|
||||
if err = rows.Scan(&user.Id, &user.CreateAt, &user.UpdateAt, &user.DeleteAt, &user.Username, &user.Password, &user.AuthData, &user.AuthService, &user.Email, &user.EmailVerified, &user.Nickname, &user.FirstName, &user.LastName, &user.Position, &user.Roles, &user.AllowMarketing, &props, ¬ifyProps, &user.LastPasswordUpdate, &user.LastPictureUpdate, &user.FailedAttempts, &user.Locale, &timezone, &user.MfaActive, &user.MfaSecret, &user.IsBot, &user.BotDescription, &user.BotLastIconUpdate, &user.RemoteId); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to scan values from rows into User entity")
|
||||
}
|
||||
if err = json.Unmarshal(props, &user.Props); err != nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user