2017-04-12 08:27:57 -04:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2015-06-14 23:53:32 -08:00
// See License.txt for license information.
2017-09-25 09:11:25 -05:00
package sqlstore
2015-06-14 23:53:32 -08:00
import (
2016-03-24 22:42:03 -04:00
"database/sql"
2016-11-24 09:35:09 -05:00
"fmt"
2017-02-02 09:04:36 -05:00
"net/http"
2018-01-31 08:26:40 -06:00
"sort"
2016-12-23 10:32:30 -05:00
"strconv"
2016-11-24 09:35:09 -05:00
"strings"
2016-09-19 19:30:41 +07:00
2017-05-29 15:46:35 -04:00
"github.com/mattermost/gorp"
2018-10-25 13:25:27 -04:00
"github.com/pkg/errors"
2018-04-20 19:49:13 +01:00
2019-03-15 12:28:43 -03:00
sq "github.com/Masterminds/squirrel"
2017-09-06 23:05:10 -07:00
"github.com/mattermost/mattermost-server/einterfaces"
2018-04-27 12:49:45 -07:00
"github.com/mattermost/mattermost-server/mlog"
2017-09-06 23:05:10 -07:00
"github.com/mattermost/mattermost-server/model"
2017-09-25 09:11:25 -05:00
"github.com/mattermost/mattermost-server/store"
2017-09-06 23:05:10 -07:00
"github.com/mattermost/mattermost-server/utils"
2015-06-14 23:53:32 -08:00
)
2016-03-24 22:42:03 -04:00
const (
2016-10-19 14:49:25 -04:00
ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE = model . SESSION_CACHE_SIZE
ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC = 900 // 15 mins
2016-11-24 05:26:45 -08:00
2017-02-23 11:08:48 -03:00
ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE = model . SESSION_CACHE_SIZE
ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC = 1800 // 30 mins
2017-02-17 08:21:06 -05:00
CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model . CHANNEL_CACHE_SIZE
CHANNEL_MEMBERS_COUNTS_CACHE_SEC = 1800 // 30 mins
2017-01-03 09:53:59 -05:00
2017-02-17 08:21:06 -05:00
CHANNEL_CACHE_SEC = 900 // 15 mins
2016-03-24 22:42:03 -04:00
)
2015-06-14 23:53:32 -08:00
type SqlChannelStore struct {
2017-06-27 08:02:08 -07:00
SqlStore
2017-09-14 12:01:44 -05:00
metrics einterfaces . MetricsInterface
2015-06-14 23:53:32 -08:00
}
2018-04-20 19:49:13 +01:00
type channelMember struct {
ChannelId string
UserId string
Roles string
LastViewedAt int64
MsgCount int64
MentionCount int64
NotifyProps model . StringMap
LastUpdateAt int64
2019-04-30 20:36:21 +02:00
SchemeGuest sql . NullBool
2018-04-20 19:49:13 +01:00
SchemeUser sql . NullBool
SchemeAdmin sql . NullBool
}
func NewChannelMemberFromModel ( cm * model . ChannelMember ) * channelMember {
return & channelMember {
ChannelId : cm . ChannelId ,
UserId : cm . UserId ,
Roles : cm . ExplicitRoles ,
LastViewedAt : cm . LastViewedAt ,
MsgCount : cm . MsgCount ,
MentionCount : cm . MentionCount ,
NotifyProps : cm . NotifyProps ,
LastUpdateAt : cm . LastUpdateAt ,
2019-04-30 20:36:21 +02:00
SchemeGuest : sql . NullBool { Valid : true , Bool : cm . SchemeGuest } ,
2018-04-20 19:49:13 +01:00
SchemeUser : sql . NullBool { Valid : true , Bool : cm . SchemeUser } ,
SchemeAdmin : sql . NullBool { Valid : true , Bool : cm . SchemeAdmin } ,
}
}
type channelMemberWithSchemeRoles struct {
ChannelId string
UserId string
Roles string
LastViewedAt int64
MsgCount int64
MentionCount int64
NotifyProps model . StringMap
LastUpdateAt int64
2019-04-30 20:36:21 +02:00
SchemeGuest sql . NullBool
2018-04-20 19:49:13 +01:00
SchemeUser sql . NullBool
SchemeAdmin sql . NullBool
2019-04-30 20:36:21 +02:00
TeamSchemeDefaultGuestRole sql . NullString
2018-04-20 19:49:13 +01:00
TeamSchemeDefaultUserRole sql . NullString
TeamSchemeDefaultAdminRole sql . NullString
2019-04-30 20:36:21 +02:00
ChannelSchemeDefaultGuestRole sql . NullString
2018-04-20 19:49:13 +01:00
ChannelSchemeDefaultUserRole sql . NullString
ChannelSchemeDefaultAdminRole sql . NullString
}
type channelMemberWithSchemeRolesList [ ] channelMemberWithSchemeRoles
func ( db channelMemberWithSchemeRoles ) ToModel ( ) * model . ChannelMember {
var roles [ ] string
var explicitRoles [ ] string
// Identify any system-wide scheme derived roles that are in "Roles" field due to not yet being migrated,
// and exclude them from ExplicitRoles field.
2019-04-30 20:36:21 +02:00
schemeGuest := db . SchemeGuest . Valid && db . SchemeGuest . Bool
2018-04-20 19:49:13 +01:00
schemeUser := db . SchemeUser . Valid && db . SchemeUser . Bool
schemeAdmin := db . SchemeAdmin . Valid && db . SchemeAdmin . Bool
for _ , role := range strings . Fields ( db . Roles ) {
isImplicit := false
2019-04-30 20:36:21 +02:00
if role == model . CHANNEL_GUEST_ROLE_ID {
// We have an implicit role via the system scheme. Override the "schemeGuest" field to true.
schemeGuest = true
isImplicit = true
} else if role == model . CHANNEL_USER_ROLE_ID {
2018-04-20 19:49:13 +01:00
// We have an implicit role via the system scheme. Override the "schemeUser" field to true.
schemeUser = true
isImplicit = true
} else if role == model . CHANNEL_ADMIN_ROLE_ID {
// We have an implicit role via the system scheme.
schemeAdmin = true
isImplicit = true
}
if ! isImplicit {
explicitRoles = append ( explicitRoles , role )
}
roles = append ( roles , role )
}
// Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add
// them to the Roles field for backwards compatibility reasons.
var schemeImpliedRoles [ ] string
2019-04-30 20:36:21 +02:00
if db . SchemeGuest . Valid && db . SchemeGuest . Bool {
if db . ChannelSchemeDefaultGuestRole . Valid && db . ChannelSchemeDefaultGuestRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . ChannelSchemeDefaultGuestRole . String )
} else if db . TeamSchemeDefaultGuestRole . Valid && db . TeamSchemeDefaultGuestRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . TeamSchemeDefaultGuestRole . String )
} else {
schemeImpliedRoles = append ( schemeImpliedRoles , model . CHANNEL_GUEST_ROLE_ID )
}
}
2018-04-20 19:49:13 +01:00
if db . SchemeUser . Valid && db . SchemeUser . Bool {
if db . ChannelSchemeDefaultUserRole . Valid && db . ChannelSchemeDefaultUserRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . ChannelSchemeDefaultUserRole . String )
} else if db . TeamSchemeDefaultUserRole . Valid && db . TeamSchemeDefaultUserRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . TeamSchemeDefaultUserRole . String )
} else {
schemeImpliedRoles = append ( schemeImpliedRoles , model . CHANNEL_USER_ROLE_ID )
}
}
if db . SchemeAdmin . Valid && db . SchemeAdmin . Bool {
if db . ChannelSchemeDefaultAdminRole . Valid && db . ChannelSchemeDefaultAdminRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . ChannelSchemeDefaultAdminRole . String )
} else if db . TeamSchemeDefaultAdminRole . Valid && db . TeamSchemeDefaultAdminRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . TeamSchemeDefaultAdminRole . String )
} else {
schemeImpliedRoles = append ( schemeImpliedRoles , model . CHANNEL_ADMIN_ROLE_ID )
}
}
for _ , impliedRole := range schemeImpliedRoles {
alreadyThere := false
for _ , role := range roles {
if role == impliedRole {
alreadyThere = true
}
}
if ! alreadyThere {
roles = append ( roles , impliedRole )
}
}
return & model . ChannelMember {
ChannelId : db . ChannelId ,
UserId : db . UserId ,
Roles : strings . Join ( roles , " " ) ,
LastViewedAt : db . LastViewedAt ,
MsgCount : db . MsgCount ,
MentionCount : db . MentionCount ,
NotifyProps : db . NotifyProps ,
LastUpdateAt : db . LastUpdateAt ,
SchemeAdmin : schemeAdmin ,
SchemeUser : schemeUser ,
2019-04-30 20:36:21 +02:00
SchemeGuest : schemeGuest ,
2018-04-20 19:49:13 +01:00
ExplicitRoles : strings . Join ( explicitRoles , " " ) ,
}
}
func ( db channelMemberWithSchemeRolesList ) ToModel ( ) * model . ChannelMembers {
cms := model . ChannelMembers { }
for _ , cm := range db {
cms = append ( cms , * cm . ToModel ( ) )
}
return & cms
}
type allChannelMember struct {
ChannelId string
Roles string
2019-04-30 20:36:21 +02:00
SchemeGuest sql . NullBool
2018-04-20 19:49:13 +01:00
SchemeUser sql . NullBool
SchemeAdmin sql . NullBool
2019-04-30 20:36:21 +02:00
TeamSchemeDefaultGuestRole sql . NullString
2018-04-20 19:49:13 +01:00
TeamSchemeDefaultUserRole sql . NullString
TeamSchemeDefaultAdminRole sql . NullString
2019-04-30 20:36:21 +02:00
ChannelSchemeDefaultGuestRole sql . NullString
2018-04-20 19:49:13 +01:00
ChannelSchemeDefaultUserRole sql . NullString
ChannelSchemeDefaultAdminRole sql . NullString
}
type allChannelMembers [ ] allChannelMember
func ( db allChannelMember ) Process ( ) ( string , string ) {
roles := strings . Fields ( db . Roles )
// Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add
// them to the Roles field for backwards compatibility reasons.
var schemeImpliedRoles [ ] string
2019-04-30 20:36:21 +02:00
if db . SchemeGuest . Valid && db . SchemeGuest . Bool {
if db . ChannelSchemeDefaultGuestRole . Valid && db . ChannelSchemeDefaultGuestRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . ChannelSchemeDefaultGuestRole . String )
} else if db . TeamSchemeDefaultGuestRole . Valid && db . TeamSchemeDefaultGuestRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . TeamSchemeDefaultGuestRole . String )
} else {
schemeImpliedRoles = append ( schemeImpliedRoles , model . CHANNEL_GUEST_ROLE_ID )
}
}
2018-04-20 19:49:13 +01:00
if db . SchemeUser . Valid && db . SchemeUser . Bool {
if db . ChannelSchemeDefaultUserRole . Valid && db . ChannelSchemeDefaultUserRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . ChannelSchemeDefaultUserRole . String )
} else if db . TeamSchemeDefaultUserRole . Valid && db . TeamSchemeDefaultUserRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . TeamSchemeDefaultUserRole . String )
} else {
schemeImpliedRoles = append ( schemeImpliedRoles , model . CHANNEL_USER_ROLE_ID )
}
}
if db . SchemeAdmin . Valid && db . SchemeAdmin . Bool {
if db . ChannelSchemeDefaultAdminRole . Valid && db . ChannelSchemeDefaultAdminRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . ChannelSchemeDefaultAdminRole . String )
} else if db . TeamSchemeDefaultAdminRole . Valid && db . TeamSchemeDefaultAdminRole . String != "" {
schemeImpliedRoles = append ( schemeImpliedRoles , db . TeamSchemeDefaultAdminRole . String )
} else {
schemeImpliedRoles = append ( schemeImpliedRoles , model . CHANNEL_ADMIN_ROLE_ID )
}
}
for _ , impliedRole := range schemeImpliedRoles {
alreadyThere := false
for _ , role := range roles {
if role == impliedRole {
alreadyThere = true
}
}
if ! alreadyThere {
roles = append ( roles , impliedRole )
}
}
return db . ChannelId , strings . Join ( roles , " " )
}
func ( db allChannelMembers ) ToMapStringString ( ) map [ string ] string {
result := make ( map [ string ] string )
for _ , item := range db {
key , value := item . Process ( )
result [ key ] = value
}
return result
}
2018-10-25 13:25:27 -04:00
// publicChannel is a subset of the metadata corresponding to public channels only.
type publicChannel struct {
Id string ` json:"id" `
DeleteAt int64 ` json:"delete_at" `
TeamId string ` json:"team_id" `
DisplayName string ` json:"display_name" `
Name string ` json:"name" `
Header string ` json:"header" `
Purpose string ` json:"purpose" `
}
2016-11-24 05:26:45 -08:00
var channelMemberCountsCache = utils . NewLru ( CHANNEL_MEMBERS_COUNTS_CACHE_SIZE )
var allChannelMembersForUserCache = utils . NewLru ( ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE )
2017-02-23 11:08:48 -03:00
var allChannelMembersNotifyPropsForChannelCache = utils . NewLru ( ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE )
2017-02-17 08:21:06 -05:00
var channelCache = utils . NewLru ( model . CHANNEL_CACHE_SIZE )
var channelByNameCache = utils . NewLru ( model . CHANNEL_CACHE_SIZE )
2016-10-19 14:49:25 -04:00
2018-03-05 10:35:26 -05:00
func ( s SqlChannelStore ) ClearCaches ( ) {
2016-12-08 07:18:15 -08:00
channelMemberCountsCache . Purge ( )
allChannelMembersForUserCache . Purge ( )
2017-02-23 11:08:48 -03:00
allChannelMembersNotifyPropsForChannelCache . Purge ( )
2017-01-03 09:53:59 -05:00
channelCache . Purge ( )
2017-01-27 14:07:34 -05:00
channelByNameCache . Purge ( )
2018-03-05 10:35:26 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheInvalidationCounter ( "Channel Member Counts - Purge" )
s . metrics . IncrementMemCacheInvalidationCounter ( "All Channel Members for User - Purge" )
s . metrics . IncrementMemCacheInvalidationCounter ( "All Channel Members Notify Props for Channel - Purge" )
s . metrics . IncrementMemCacheInvalidationCounter ( "Channel - Purge" )
s . metrics . IncrementMemCacheInvalidationCounter ( "Channel By Name - Purge" )
}
2016-12-08 07:18:15 -08:00
}
2017-09-25 09:11:25 -05:00
func NewSqlChannelStore ( sqlStore SqlStore , metrics einterfaces . MetricsInterface ) store . ChannelStore {
2017-09-14 12:01:44 -05:00
s := & SqlChannelStore {
SqlStore : sqlStore ,
metrics : metrics ,
}
2015-06-14 23:53:32 -08:00
for _ , db := range sqlStore . GetAllConns ( ) {
table := db . AddTableWithName ( model . Channel { } , "Channels" ) . SetKeys ( false , "Id" )
table . ColMap ( "Id" ) . SetMaxSize ( 26 )
table . ColMap ( "TeamId" ) . SetMaxSize ( 26 )
table . ColMap ( "Type" ) . SetMaxSize ( 1 )
table . ColMap ( "DisplayName" ) . SetMaxSize ( 64 )
table . ColMap ( "Name" ) . SetMaxSize ( 64 )
table . SetUniqueTogether ( "Name" , "TeamId" )
2015-10-26 16:18:28 -04:00
table . ColMap ( "Header" ) . SetMaxSize ( 1024 )
2016-11-04 17:20:21 -04:00
table . ColMap ( "Purpose" ) . SetMaxSize ( 250 )
2015-08-19 08:31:20 -04:00
table . ColMap ( "CreatorId" ) . SetMaxSize ( 26 )
2018-04-20 19:49:13 +01:00
table . ColMap ( "SchemeId" ) . SetMaxSize ( 26 )
2015-06-14 23:53:32 -08:00
2018-04-20 19:49:13 +01:00
tablem := db . AddTableWithName ( channelMember { } , "ChannelMembers" ) . SetKeys ( false , "ChannelId" , "UserId" )
2015-06-14 23:53:32 -08:00
tablem . ColMap ( "ChannelId" ) . SetMaxSize ( 26 )
tablem . ColMap ( "UserId" ) . SetMaxSize ( 26 )
tablem . ColMap ( "Roles" ) . SetMaxSize ( 64 )
2015-09-30 11:08:36 -04:00
tablem . ColMap ( "NotifyProps" ) . SetMaxSize ( 2000 )
2018-10-25 13:25:27 -04:00
tablePublicChannels := db . AddTableWithName ( publicChannel { } , "PublicChannels" ) . SetKeys ( false , "Id" )
tablePublicChannels . ColMap ( "Id" ) . SetMaxSize ( 26 )
tablePublicChannels . ColMap ( "TeamId" ) . SetMaxSize ( 26 )
tablePublicChannels . ColMap ( "DisplayName" ) . SetMaxSize ( 64 )
tablePublicChannels . ColMap ( "Name" ) . SetMaxSize ( 64 )
tablePublicChannels . SetUniqueTogether ( "Name" , "TeamId" )
tablePublicChannels . ColMap ( "Header" ) . SetMaxSize ( 1024 )
tablePublicChannels . ColMap ( "Purpose" ) . SetMaxSize ( 250 )
2015-06-14 23:53:32 -08:00
}
return s
}
func ( s SqlChannelStore ) CreateIndexesIfNotExists ( ) {
2015-07-12 14:56:44 -08:00
s . CreateIndexIfNotExists ( "idx_channels_team_id" , "Channels" , "TeamId" )
s . CreateIndexIfNotExists ( "idx_channels_name" , "Channels" , "Name" )
2016-10-24 17:05:27 -03:00
s . CreateIndexIfNotExists ( "idx_channels_update_at" , "Channels" , "UpdateAt" )
s . CreateIndexIfNotExists ( "idx_channels_create_at" , "Channels" , "CreateAt" )
s . CreateIndexIfNotExists ( "idx_channels_delete_at" , "Channels" , "DeleteAt" )
2015-07-12 14:56:44 -08:00
2017-10-11 17:20:27 +08:00
if s . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
s . CreateIndexIfNotExists ( "idx_channels_name_lower" , "Channels" , "lower(Name)" )
s . CreateIndexIfNotExists ( "idx_channels_displayname_lower" , "Channels" , "lower(DisplayName)" )
}
2015-07-12 14:56:44 -08:00
s . CreateIndexIfNotExists ( "idx_channelmembers_channel_id" , "ChannelMembers" , "ChannelId" )
s . CreateIndexIfNotExists ( "idx_channelmembers_user_id" , "ChannelMembers" , "UserId" )
2016-11-24 09:35:09 -05:00
2018-06-26 10:47:39 -07:00
s . CreateFullTextIndexIfNotExists ( "idx_channel_search_txt" , "Channels" , "Name, DisplayName, Purpose" )
2018-10-25 13:25:27 -04:00
s . CreateIndexIfNotExists ( "idx_publicchannels_team_id" , "PublicChannels" , "TeamId" )
s . CreateIndexIfNotExists ( "idx_publicchannels_name" , "PublicChannels" , "Name" )
s . CreateIndexIfNotExists ( "idx_publicchannels_delete_at" , "PublicChannels" , "DeleteAt" )
if s . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
s . CreateIndexIfNotExists ( "idx_publicchannels_name_lower" , "PublicChannels" , "lower(Name)" )
s . CreateIndexIfNotExists ( "idx_publicchannels_displayname_lower" , "PublicChannels" , "lower(DisplayName)" )
}
s . CreateFullTextIndexIfNotExists ( "idx_publicchannels_search_txt" , "PublicChannels" , "Name, DisplayName, Purpose" )
2015-06-14 23:53:32 -08:00
}
2018-10-25 13:25:27 -04:00
// MigratePublicChannels initializes the PublicChannels table with data created before this version
// of the Mattermost server kept it up-to-date.
2018-09-13 13:47:17 -04:00
func ( s SqlChannelStore ) MigratePublicChannels ( ) error {
2019-02-23 19:44:52 +00:00
if _ , err := s . GetMaster ( ) . Exec ( `
2018-10-25 13:25:27 -04:00
INSERT INTO PublicChannels
( Id , DeleteAt , TeamId , DisplayName , Name , Header , Purpose )
SELECT
c . Id , c . DeleteAt , c . TeamId , c . DisplayName , c . Name , c . Header , c . Purpose
FROM
Channels c
LEFT JOIN
PublicChannels pc ON ( pc . Id = c . Id )
WHERE
c . Type = 'O'
AND pc . Id IS NULL
` ) ; err != nil {
return err
}
2018-09-13 13:47:17 -04:00
return nil
}
2018-10-25 13:25:27 -04:00
func ( s SqlChannelStore ) upsertPublicChannelT ( transaction * gorp . Transaction , channel * model . Channel ) error {
publicChannel := & publicChannel {
Id : channel . Id ,
DeleteAt : channel . DeleteAt ,
TeamId : channel . TeamId ,
DisplayName : channel . DisplayName ,
Name : channel . Name ,
Header : channel . Header ,
Purpose : channel . Purpose ,
}
if channel . Type != model . CHANNEL_OPEN {
if _ , err := transaction . Delete ( publicChannel ) ; err != nil {
return errors . Wrap ( err , "failed to delete public channel" )
}
return nil
}
if s . DriverName ( ) == model . DATABASE_DRIVER_MYSQL {
// Leverage native upsert for MySQL, since RowsAffected returns 0 if the row exists
// but no changes were made, breaking the update-then-insert paradigm below when
// the row already exists. (Postgres 9.4 doesn't support native upsert.)
if _ , err := transaction . Exec ( `
INSERT INTO
PublicChannels ( Id , DeleteAt , TeamId , DisplayName , Name , Header , Purpose )
VALUES
( : Id , : DeleteAt , : TeamId , : DisplayName , : Name , : Header , : Purpose )
ON DUPLICATE KEY UPDATE
DeleteAt = : DeleteAt ,
TeamId = : TeamId ,
DisplayName = : DisplayName ,
Name = : Name ,
Header = : Header ,
Purpose = : Purpose ;
` , map [ string ] interface { } {
"Id" : publicChannel . Id ,
"DeleteAt" : publicChannel . DeleteAt ,
"TeamId" : publicChannel . TeamId ,
"DisplayName" : publicChannel . DisplayName ,
"Name" : publicChannel . Name ,
"Header" : publicChannel . Header ,
"Purpose" : publicChannel . Purpose ,
} ) ; err != nil {
return errors . Wrap ( err , "failed to insert public channel" )
}
} else {
count , err := transaction . Update ( publicChannel )
if err != nil {
return errors . Wrap ( err , "failed to update public channel" )
}
if count > 0 {
return nil
}
if err := transaction . Insert ( publicChannel ) ; err != nil {
return errors . Wrap ( err , "failed to insert public channel" )
}
}
2018-09-13 13:47:17 -04:00
return nil
}
2018-09-17 16:25:19 -04:00
// Save writes the (non-direct) channel channel to the database.
2019-05-27 11:54:04 -04:00
func ( s SqlChannelStore ) Save ( channel * model . Channel , maxChannelsPerTeam int64 ) ( * model . Channel , * model . AppError ) {
2018-07-30 15:06:08 -04:00
2019-05-27 11:54:04 -04:00
if channel . DeleteAt != 0 {
return nil , model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save.archived_channel.app_error" , nil , "" , http . StatusBadRequest )
}
2018-07-20 12:39:48 +02:00
2019-05-27 11:54:04 -04:00
if channel . Type == model . CHANNEL_DIRECT {
return nil , model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save.direct_channel.app_error" , nil , "" , http . StatusBadRequest )
}
2018-07-20 12:39:48 +02:00
2019-05-27 11:54:04 -04:00
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
defer finalizeTransaction ( transaction )
2018-07-20 12:39:48 +02:00
2019-05-27 11:54:04 -04:00
channelResult := s . saveChannelT ( transaction , channel , maxChannelsPerTeam )
var newChannel * model . Channel
if channelResult . Data != nil {
newChannel = channelResult . Data . ( * model . Channel )
}
appErr := channelResult . Err
2018-10-25 13:25:27 -04:00
2019-05-27 11:54:04 -04:00
if appErr != nil {
return newChannel , appErr
}
// Additionally propagate the write to the PublicChannels table.
if err := s . upsertPublicChannelT ( transaction , newChannel ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save.upsert_public_channel.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
if err := transaction . Commit ( ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return newChannel , nil
2015-10-22 09:31:27 -04:00
}
2015-06-14 23:53:32 -08:00
2019-05-17 00:04:58 +04:00
func ( s SqlChannelStore ) CreateDirectChannel ( userId string , otherUserId string ) ( * model . Channel , * model . AppError ) {
2016-10-17 15:12:56 +03:00
channel := new ( model . Channel )
channel . DisplayName = ""
channel . Name = model . GetDMNameFromIds ( otherUserId , userId )
channel . Header = ""
channel . Type = model . CHANNEL_DIRECT
cm1 := & model . ChannelMember {
UserId : userId ,
NotifyProps : model . GetDefaultChannelNotifyProps ( ) ,
2018-04-20 19:49:13 +01:00
SchemeUser : true ,
2016-10-17 15:12:56 +03:00
}
cm2 := & model . ChannelMember {
UserId : otherUserId ,
NotifyProps : model . GetDefaultChannelNotifyProps ( ) ,
2018-04-20 19:49:13 +01:00
SchemeUser : true ,
2016-10-17 15:12:56 +03:00
}
return s . SaveDirectChannel ( channel , cm1 , cm2 )
}
2019-05-17 00:04:58 +04:00
func ( s SqlChannelStore ) SaveDirectChannel ( directchannel * model . Channel , member1 * model . ChannelMember , member2 * model . ChannelMember ) ( * model . Channel , * model . AppError ) {
if directchannel . DeleteAt != 0 {
return nil , model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save.archived_channel.app_error" , nil , "" , http . StatusBadRequest )
}
2018-07-30 15:06:08 -04:00
2019-05-17 00:04:58 +04:00
if directchannel . Type != model . CHANNEL_DIRECT {
return nil , model . NewAppError ( "SqlChannelStore.SaveDirectChannel" , "store.sql_channel.save_direct_channel.not_direct.app_error" , nil , "" , http . StatusBadRequest )
}
2015-10-22 09:31:27 -04:00
2019-05-17 00:04:58 +04:00
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.SaveDirectChannel" , "store.sql_channel.save_direct_channel.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
defer finalizeTransaction ( transaction )
2015-10-22 09:31:27 -04:00
2019-05-17 00:04:58 +04:00
directchannel . TeamId = ""
// After updating saveChannelT() should be:
// newChannel, appErr := s.saveChannelT(transaction, directchannel, 0)
channelResult := s . saveChannelT ( transaction , directchannel , 0 )
var newChannel * model . Channel
if channelResult . Data != nil {
newChannel = channelResult . Data . ( * model . Channel )
}
appErr := channelResult . Err
2018-07-20 12:39:48 +02:00
2019-05-17 00:04:58 +04:00
if appErr != nil {
return newChannel , appErr
}
2018-07-20 12:39:48 +02:00
2019-05-17 00:04:58 +04:00
// Members need new channel ID
member1 . ChannelId = newChannel . Id
member2 . ChannelId = newChannel . Id
2018-07-20 12:39:48 +02:00
2019-05-17 00:04:58 +04:00
member1Result := s . saveMemberT ( transaction , member1 , newChannel )
member2Result := member1Result
if member1 . UserId != member2 . UserId {
member2Result = s . saveMemberT ( transaction , member2 , newChannel )
}
2018-07-20 12:39:48 +02:00
2019-05-17 00:04:58 +04:00
if member1Result . Err != nil || member2Result . Err != nil {
details := ""
if member1Result . Err != nil {
details += "Member1Err: " + member1Result . Err . Message
2018-07-20 12:39:48 +02:00
}
2019-05-17 00:04:58 +04:00
if member2Result . Err != nil {
details += "Member2Err: " + member2Result . Err . Message
2015-06-14 23:53:32 -08:00
}
2019-05-17 00:04:58 +04:00
return nil , model . NewAppError ( "SqlChannelStore.SaveDirectChannel" , "store.sql_channel.save_direct_channel.add_members.app_error" , nil , details , http . StatusInternalServerError )
}
if err := transaction . Commit ( ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.SaveDirectChannel" , "store.sql_channel.save_direct_channel.commit.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return newChannel , nil
2018-07-20 12:39:48 +02:00
2015-06-14 23:53:32 -08:00
}
2017-10-20 17:33:20 -07:00
func ( s SqlChannelStore ) saveChannelT ( transaction * gorp . Transaction , channel * model . Channel , maxChannelsPerTeam int64 ) store . StoreResult {
2017-09-25 09:11:25 -05:00
result := store . StoreResult { }
2015-10-22 09:31:27 -04:00
if len ( channel . Id ) > 0 {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save_channel.existing.app_error" , nil , "id=" + channel . Id , http . StatusBadRequest )
2015-10-22 09:31:27 -04:00
return result
}
channel . PreSave ( )
if result . Err = channel . IsValid ( ) ; result . Err != nil {
return result
}
2017-10-20 17:33:20 -07:00
if channel . Type != model . CHANNEL_DIRECT && channel . Type != model . CHANNEL_GROUP && maxChannelsPerTeam >= 0 {
2015-12-15 11:05:40 -08:00
if count , err := transaction . SelectInt ( "SELECT COUNT(0) FROM Channels WHERE TeamId = :TeamId AND DeleteAt = 0 AND (Type = 'O' OR Type = 'P')" , map [ string ] interface { } { "TeamId" : channel . TeamId } ) ; err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save_channel.current_count.app_error" , nil , "teamId=" + channel . TeamId + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-12-15 11:05:40 -08:00
return result
2017-10-20 17:33:20 -07:00
} else if count >= maxChannelsPerTeam {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save_channel.limit.app_error" , nil , "teamId=" + channel . TeamId , http . StatusBadRequest )
2015-12-15 11:05:40 -08:00
return result
}
2015-10-22 09:31:27 -04:00
}
if err := transaction . Insert ( channel ) ; err != nil {
2017-09-06 14:00:56 -04:00
if IsUniqueConstraintError ( err , [ ] string { "Name" , "channels_name_teamid_key" } ) {
2015-10-22 09:31:27 -04:00
dupChannel := model . Channel { }
2016-12-09 18:43:03 -05:00
s . GetMaster ( ) . SelectOne ( & dupChannel , "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name = :Name" , map [ string ] interface { } { "TeamId" : channel . TeamId , "Name" : channel . Name } )
2015-10-22 09:31:27 -04:00
if dupChannel . DeleteAt > 0 {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save_channel.previously.app_error" , nil , "id=" + channel . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2015-10-22 09:31:27 -04:00
} else {
2017-09-25 09:11:25 -05:00
result . Err = model . NewAppError ( "SqlChannelStore.Save" , store . CHANNEL_EXISTS_ERROR , nil , "id=" + channel . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2016-05-06 08:06:34 -04:00
result . Data = & dupChannel
2015-10-22 09:31:27 -04:00
}
} else {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.Save" , "store.sql_channel.save_channel.save.app_error" , nil , "id=" + channel . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-10-22 09:31:27 -04:00
}
} else {
result . Data = channel
}
return result
}
2018-09-17 16:25:19 -04:00
// Update writes the updated channel to the database.
2019-05-15 01:02:04 +04:00
func ( s SqlChannelStore ) Update ( channel * model . Channel ) ( * model . Channel , * model . AppError ) {
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
defer finalizeTransaction ( transaction )
2015-06-14 23:53:32 -08:00
2019-05-17 00:04:58 +04:00
updatedChannel , appErr := s . updateChannelT ( transaction , channel )
if appErr != nil {
return nil , appErr
2019-05-15 01:02:04 +04:00
}
2018-10-25 13:25:27 -04:00
2019-05-15 01:02:04 +04:00
// Additionally propagate the write to the PublicChannels table.
if err := s . upsertPublicChannelT ( transaction , updatedChannel ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.upsert_public_channel.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2018-10-25 13:25:27 -04:00
2019-05-15 01:02:04 +04:00
if err := transaction . Commit ( ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return updatedChannel , nil
2018-09-17 16:25:19 -04:00
}
2018-07-20 12:39:48 +02:00
2019-05-15 01:02:04 +04:00
func ( s SqlChannelStore ) updateChannelT ( transaction * gorp . Transaction , channel * model . Channel ) ( * model . Channel , * model . AppError ) {
2018-09-17 16:25:19 -04:00
channel . PreUpdate ( )
if channel . DeleteAt != 0 {
2019-05-15 01:02:04 +04:00
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.archived_channel.app_error" , nil , "" , http . StatusBadRequest )
2018-09-17 16:25:19 -04:00
}
2019-05-15 01:02:04 +04:00
if err := channel . IsValid ( ) ; err != nil {
return nil , err
2018-09-17 16:25:19 -04:00
}
count , err := transaction . Update ( channel )
if err != nil {
if IsUniqueConstraintError ( err , [ ] string { "Name" , "channels_name_teamid_key" } ) {
dupChannel := model . Channel { }
s . GetReplica ( ) . SelectOne ( & dupChannel , "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name= :Name AND DeleteAt > 0" , map [ string ] interface { } { "TeamId" : channel . TeamId , "Name" : channel . Name } )
if dupChannel . DeleteAt > 0 {
2019-05-15 01:02:04 +04:00
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.previously.app_error" , nil , "id=" + channel . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2018-09-17 16:25:19 -04:00
}
2019-05-15 01:02:04 +04:00
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.exists.app_error" , nil , "id=" + channel . Id + ", " + err . Error ( ) , http . StatusBadRequest )
2015-06-14 23:53:32 -08:00
}
2019-05-15 01:02:04 +04:00
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.updating.app_error" , nil , "id=" + channel . Id + ", " + err . Error ( ) , http . StatusInternalServerError )
2018-09-17 16:25:19 -04:00
}
2018-07-20 12:39:48 +02:00
2018-09-17 16:25:19 -04:00
if count != 1 {
2019-05-15 01:02:04 +04:00
return nil , model . NewAppError ( "SqlChannelStore.Update" , "store.sql_channel.update.app_error" , nil , "id=" + channel . Id , http . StatusInternalServerError )
2018-09-17 16:25:19 -04:00
}
2019-05-15 01:02:04 +04:00
return channel , nil
2015-06-14 23:53:32 -08:00
}
2019-05-07 09:15:12 -07:00
func ( s SqlChannelStore ) GetChannelUnread ( channelId , userId string ) ( * model . ChannelUnread , * model . AppError ) {
var unreadChannel model . ChannelUnread
err := s . GetReplica ( ) . SelectOne ( & unreadChannel ,
` SELECT
2017-03-16 14:58:33 -04:00
Channels . TeamId TeamId , Channels . Id ChannelId , ( Channels . TotalMsgCount - ChannelMembers . MsgCount ) MsgCount , ChannelMembers . MentionCount MentionCount , ChannelMembers . NotifyProps NotifyProps
FROM
Channels , ChannelMembers
WHERE
Id = ChannelId
AND Id = : ChannelId
AND UserId = : UserId
AND DeleteAt = 0 ` ,
2019-05-07 09:15:12 -07:00
map [ string ] interface { } { "ChannelId" : channelId , "UserId" : userId } )
2017-03-16 14:58:33 -04:00
2019-05-07 09:15:12 -07:00
if err != nil {
if err == sql . ErrNoRows {
return nil , model . NewAppError ( "SqlChannelStore.GetChannelUnread" , "store.sql_channel.get_unread.app_error" , nil , "channelId=" + channelId + " " + err . Error ( ) , http . StatusNotFound )
2017-03-16 14:58:33 -04:00
}
2019-05-07 09:15:12 -07:00
return nil , model . NewAppError ( "SqlChannelStore.GetChannelUnread" , "store.sql_channel.get_unread.app_error" , nil , "channelId=" + channelId + " " + err . Error ( ) , http . StatusInternalServerError )
}
return & unreadChannel , nil
2017-03-16 14:58:33 -04:00
}
2018-03-05 10:35:26 -05:00
func ( s SqlChannelStore ) InvalidateChannel ( id string ) {
2017-01-03 09:53:59 -05:00
channelCache . Remove ( id )
2018-03-05 10:35:26 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheInvalidationCounter ( "Channel - Remove by ChannelId" )
}
2017-01-03 09:53:59 -05:00
}
2018-03-05 10:35:26 -05:00
func ( s SqlChannelStore ) InvalidateChannelByName ( teamId , name string ) {
2017-03-13 14:24:30 +01:00
channelByNameCache . Remove ( teamId + name )
2018-03-05 10:35:26 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheInvalidationCounter ( "Channel by Name - Remove by TeamId and Name" )
}
2017-01-27 14:07:34 -05:00
}
2019-04-24 15:28:06 -04:00
func ( s SqlChannelStore ) Get ( id string , allowFromCache bool ) ( * model . Channel , * model . AppError ) {
2017-01-03 09:53:59 -05:00
return s . get ( id , false , allowFromCache )
2015-12-09 10:48:35 -05:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) GetPinnedPosts ( channelId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2017-07-13 08:12:11 -04:00
pl := model . NewPostList ( )
2017-03-13 13:25:08 +01:00
var posts [ ] * model . Post
if _ , err := s . GetReplica ( ) . Select ( & posts , "SELECT * FROM Posts WHERE IsPinned = true AND ChannelId = :ChannelId AND DeleteAt = 0 ORDER BY CreateAt ASC" , map [ string ] interface { } { "ChannelId" : channelId } ) ; err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlPostStore.GetPinnedPosts" , "store.sql_channel.pinned_posts.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2017-03-13 13:25:08 +01:00
} else {
for _ , post := range posts {
pl . AddPost ( post )
pl . AddOrder ( post . Id )
}
}
result . Data = pl
2017-10-06 08:12:10 -07:00
} )
2017-03-13 13:25:08 +01:00
}
2019-04-24 15:28:06 -04:00
func ( s SqlChannelStore ) GetFromMaster ( id string ) ( * model . Channel , * model . AppError ) {
2017-01-03 09:53:59 -05:00
return s . get ( id , true , false )
2015-12-09 10:48:35 -05:00
}
2019-04-24 15:28:06 -04:00
func ( s SqlChannelStore ) get ( id string , master bool , allowFromCache bool ) ( * model . Channel , * model . AppError ) {
var db * gorp . DbMap
2015-12-09 10:48:35 -05:00
2019-04-24 15:28:06 -04:00
if master {
db = s . GetMaster ( )
} else {
db = s . GetReplica ( )
}
if allowFromCache {
if cacheItem , ok := channelCache . Get ( id ) ; ok {
if s . metrics != nil {
s . metrics . IncrementMemCacheHitCounter ( "Channel" )
2017-01-03 09:53:59 -05:00
}
2019-04-24 15:28:06 -04:00
ch := cacheItem . ( * model . Channel ) . DeepCopy ( )
return ch , nil
2017-01-03 09:53:59 -05:00
}
2019-04-24 15:28:06 -04:00
}
2017-01-03 09:53:59 -05:00
2019-04-24 15:28:06 -04:00
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "Channel" )
}
2018-07-20 12:39:48 +02:00
2019-04-24 15:28:06 -04:00
obj , err := db . Get ( model . Channel { } , id )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.Get" , "store.sql_channel.get.find.app_error" , nil , "id=" + id + ", " + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-04-24 15:28:06 -04:00
if obj == nil {
return nil , model . NewAppError ( "SqlChannelStore.Get" , "store.sql_channel.get.existing.app_error" , nil , "id=" + id , http . StatusNotFound )
}
2018-07-20 12:39:48 +02:00
2019-04-24 15:28:06 -04:00
ch := obj . ( * model . Channel )
channelCache . AddWithExpiresInSecs ( id , ch , CHANNEL_CACHE_SEC )
return ch , nil
2015-06-14 23:53:32 -08:00
}
2018-09-17 16:25:19 -04:00
// Delete records the given deleted timestamp to the channel in question.
2019-05-16 11:31:50 +01:00
func ( s SqlChannelStore ) Delete ( channelId string , time int64 ) * model . AppError {
2016-07-06 10:11:21 -08:00
return s . SetDeleteAt ( channelId , time , time )
}
2018-09-17 16:25:19 -04:00
// Restore reverts a previous deleted timestamp from the channel in question.
2019-05-16 11:31:50 +01:00
func ( s SqlChannelStore ) Restore ( channelId string , time int64 ) * model . AppError {
2017-05-15 22:12:30 +02:00
return s . SetDeleteAt ( channelId , 0 , time )
}
2018-09-17 16:25:19 -04:00
// SetDeleteAt records the given deleted and updated timestamp to the channel in question.
2019-05-16 11:31:50 +01:00
func ( s SqlChannelStore ) SetDeleteAt ( channelId string , deleteAt , updateAt int64 ) * model . AppError {
defer s . InvalidateChannel ( channelId )
2018-10-15 12:58:58 +01:00
2019-05-16 11:31:50 +01:00
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
return model . NewAppError ( "SqlChannelStore.SetDeleteAt" , "store.sql_channel.set_delete_at.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
defer finalizeTransaction ( transaction )
2018-09-17 16:25:19 -04:00
2019-05-16 11:31:50 +01:00
var result = s . setDeleteAtT ( transaction , channelId , deleteAt , updateAt )
if result . Err != nil {
return result . Err
}
2018-09-17 16:25:19 -04:00
2019-05-16 11:31:50 +01:00
// Additionally propagate the write to the PublicChannels table.
if _ , err := transaction . Exec ( `
2018-10-25 13:25:27 -04:00
UPDATE
2019-03-15 17:53:53 +00:00
PublicChannels
SET
2018-10-25 13:25:27 -04:00
DeleteAt = : DeleteAt
2019-03-15 17:53:53 +00:00
WHERE
2018-10-25 13:25:27 -04:00
Id = : ChannelId
` , map [ string ] interface { } {
2019-05-16 11:31:50 +01:00
"DeleteAt" : deleteAt ,
"ChannelId" : channelId ,
} ) ; err != nil {
return model . NewAppError ( "SqlChannelStore.SetDeleteAt" , "store.sql_channel.set_delete_at.update_public_channel.app_error" , nil , "channel_id=" + channelId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
2018-10-25 13:25:27 -04:00
2019-05-16 11:31:50 +01:00
if err := transaction . Commit ( ) ; err != nil {
return model . NewAppError ( "SqlChannelStore.SetDeleteAt" , "store.sql_channel.set_delete_at.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return nil
2015-06-14 23:53:32 -08:00
}
2018-09-17 16:25:19 -04:00
func ( s SqlChannelStore ) setDeleteAtT ( transaction * gorp . Transaction , channelId string , deleteAt , updateAt int64 ) store . StoreResult {
result := store . StoreResult { }
_ , err := transaction . Exec ( "Update Channels SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :ChannelId" , map [ string ] interface { } { "DeleteAt" : deleteAt , "UpdateAt" : updateAt , "ChannelId" : channelId } )
if err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.Delete" , "store.sql_channel.delete.channel.app_error" , nil , "id=" + channelId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
return result
}
return result
}
// PermanentDeleteByTeam removes all channels for the given team from the database.
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) PermanentDeleteByTeam ( teamId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2018-09-17 16:25:19 -04:00
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDeleteByTeam" , "store.sql_channel.permanent_delete_by_team.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
}
2019-02-23 19:44:52 +00:00
defer finalizeTransaction ( transaction )
2018-09-17 16:25:19 -04:00
* result = s . permanentDeleteByTeamtT ( transaction , teamId )
if result . Err != nil {
return
}
2018-10-25 13:25:27 -04:00
// Additionally propagate the deletions to the PublicChannels table.
if _ , err := transaction . Exec ( `
DELETE FROM
2019-03-15 17:53:53 +00:00
PublicChannels
2018-10-25 13:25:27 -04:00
WHERE
TeamId = : TeamId
` , map [ string ] interface { } {
"TeamId" : teamId ,
} ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDeleteByTeamt" , "store.sql_channel.permanent_delete_by_team.delete_public_channels.app_error" , nil , "team_id=" + teamId + ", " + err . Error ( ) , http . StatusInternalServerError )
return
}
2018-09-17 16:25:19 -04:00
if err := transaction . Commit ( ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDeleteByTeam" , "store.sql_channel.permanent_delete_by_team.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
2015-11-16 18:18:37 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-11-16 18:18:37 -08:00
}
2018-09-17 16:25:19 -04:00
func ( s SqlChannelStore ) permanentDeleteByTeamtT ( transaction * gorp . Transaction , teamId string ) store . StoreResult {
result := store . StoreResult { }
if _ , err := transaction . Exec ( "DELETE FROM Channels WHERE TeamId = :TeamId" , map [ string ] interface { } { "TeamId" : teamId } ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDeleteByTeam" , "store.sql_channel.permanent_delete_by_team.app_error" , nil , "teamId=" + teamId + ", " + err . Error ( ) , http . StatusInternalServerError )
return result
}
return result
}
// PermanentDelete removes the given channel from the database.
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) PermanentDelete ( channelId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2018-09-17 16:25:19 -04:00
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDelete" , "store.sql_channel.permanent_delete.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
}
2019-02-23 19:44:52 +00:00
defer finalizeTransaction ( transaction )
2018-09-17 16:25:19 -04:00
* result = s . permanentDeleteT ( transaction , channelId )
if result . Err != nil {
return
}
2018-10-25 13:25:27 -04:00
// Additionally propagate the deletion to the PublicChannels table.
if _ , err := transaction . Exec ( `
DELETE FROM
2019-03-15 17:53:53 +00:00
PublicChannels
2018-10-25 13:25:27 -04:00
WHERE
Id = : ChannelId
` , map [ string ] interface { } {
"ChannelId" : channelId ,
} ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDelete" , "store.sql_channel.permanent_delete.delete_public_channel.app_error" , nil , "channel_id=" + channelId + ", " + err . Error ( ) , http . StatusInternalServerError )
return
}
2018-09-17 16:25:19 -04:00
if err := transaction . Commit ( ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDelete" , "store.sql_channel.permanent_delete.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
2017-02-02 11:46:42 -05:00
}
2017-10-06 08:12:10 -07:00
} )
2017-02-02 11:46:42 -05:00
}
2018-09-17 16:25:19 -04:00
func ( s SqlChannelStore ) permanentDeleteT ( transaction * gorp . Transaction , channelId string ) store . StoreResult {
result := store . StoreResult { }
if _ , err := transaction . Exec ( "DELETE FROM Channels WHERE Id = :ChannelId" , map [ string ] interface { } { "ChannelId" : channelId } ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.PermanentDelete" , "store.sql_channel.permanent_delete.app_error" , nil , "channel_id=" + channelId + ", " + err . Error ( ) , http . StatusInternalServerError )
return result
}
return result
}
2019-06-18 12:33:42 -04:00
func ( s SqlChannelStore ) PermanentDeleteMembersByChannel ( channelId string ) * model . AppError {
_ , err := s . GetMaster ( ) . Exec ( "DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId" , map [ string ] interface { } { "ChannelId" : channelId } )
if err != nil {
return model . NewAppError ( "SqlChannelStore.RemoveAllMembersByChannel" , "store.sql_channel.remove_member.app_error" , nil , "channel_id=" + channelId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
return nil
2017-02-02 11:46:42 -05:00
}
2019-06-20 03:31:40 -04:00
func ( s SqlChannelStore ) GetChannels ( teamId string , userId string , includeDeleted bool ) ( * model . ChannelList , * model . AppError ) {
query := "SELECT Channels.* FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND DeleteAt = 0 AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName"
if includeDeleted {
query = "SELECT Channels.* FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName"
}
channels := & model . ChannelList { }
_ , err := s . GetReplica ( ) . Select ( channels , query , map [ string ] interface { } { "TeamId" : teamId , "UserId" : userId } )
2015-06-14 23:53:32 -08:00
2019-06-20 03:31:40 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetChannels" , "store.sql_channel.get_channels.get.app_error" , nil , "teamId=" + teamId + ", userId=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-20 03:31:40 -04:00
if len ( * channels ) == 0 {
return nil , model . NewAppError ( "SqlChannelStore.GetChannels" , "store.sql_channel.get_channels.not_found.app_error" , nil , "teamId=" + teamId + ", userId=" + userId , http . StatusBadRequest )
}
2018-07-20 12:39:48 +02:00
2019-06-20 03:31:40 -04:00
return channels , nil
2015-06-14 23:53:32 -08:00
}
2019-06-20 10:48:51 -04:00
func ( s SqlChannelStore ) GetAllChannels ( offset int , limit int , opts store . ChannelSearchOpts ) ( * model . ChannelListWithTeamData , * model . AppError ) {
query := s . getQueryBuilder ( ) .
Select ( "c.*, Teams.DisplayName AS TeamDisplayName, Teams.Name AS TeamName, Teams.UpdateAt AS TeamUpdateAt" ) .
From ( "Channels AS c" ) .
Join ( "Teams ON Teams.Id = c.TeamId" ) .
Where ( sq . Eq { "c.Type" : [ ] string { model . CHANNEL_PRIVATE , model . CHANNEL_OPEN } } ) .
OrderBy ( "c.DisplayName, Teams.DisplayName" ) .
Limit ( uint64 ( limit ) ) .
Offset ( uint64 ( offset ) )
2019-05-24 11:28:42 -04:00
2019-06-20 10:48:51 -04:00
if ! opts . IncludeDeleted {
query = query . Where ( sq . Eq { "c.DeleteAt" : int ( 0 ) } )
}
2019-01-10 15:17:31 -05:00
2019-06-20 10:48:51 -04:00
if len ( opts . NotAssociatedToGroup ) > 0 {
query = query . Where ( "c.Id NOT IN (SELECT ChannelId FROM GroupChannels WHERE GroupChannels.GroupId = ? AND GroupChannels.DeleteAt = 0)" , opts . NotAssociatedToGroup )
}
2019-05-24 11:28:42 -04:00
2019-06-20 10:48:51 -04:00
if len ( opts . ExcludeChannelNames ) > 0 {
query = query . Where ( fmt . Sprintf ( "c.Name NOT IN ('%s')" , strings . Join ( opts . ExcludeChannelNames , "', '" ) ) )
}
2019-01-10 15:17:31 -05:00
2019-06-20 10:48:51 -04:00
queryString , args , err := query . ToSql ( )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllChannels" , "store.sql.build_query.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2019-01-10 15:17:31 -05:00
2019-06-20 10:48:51 -04:00
data := & model . ChannelListWithTeamData { }
_ , err = s . GetReplica ( ) . Select ( data , queryString , args ... )
2019-01-10 15:17:31 -05:00
2019-06-20 10:48:51 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllChannels" , "store.sql_channel.get_all_channels.get.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return data , nil
2019-01-10 15:17:31 -05:00
}
2019-06-17 10:27:19 -04:00
func ( s SqlChannelStore ) GetMoreChannels ( teamId string , userId string , offset int , limit int ) ( * model . ChannelList , * model . AppError ) {
channels := & model . ChannelList { }
_ , err := s . GetReplica ( ) . Select ( channels , `
SELECT
Channels . *
FROM
Channels
JOIN
PublicChannels c ON ( c . Id = Channels . Id )
WHERE
c . TeamId = : TeamId
AND c . DeleteAt = 0
AND c . Id NOT IN (
2018-10-25 13:25:27 -04:00
SELECT
2019-06-17 10:27:19 -04:00
c . Id
2015-06-14 23:53:32 -08:00
FROM
2019-06-17 10:27:19 -04:00
PublicChannels c
2018-10-25 13:25:27 -04:00
JOIN
2019-06-17 10:27:19 -04:00
ChannelMembers cm ON ( cm . ChannelId = c . Id )
2015-06-14 23:53:32 -08:00
WHERE
2019-06-17 10:27:19 -04:00
c . TeamId = : TeamId
AND cm . UserId = : UserId
2018-10-25 13:25:27 -04:00
AND c . DeleteAt = 0
2019-06-17 10:27:19 -04:00
)
ORDER BY
c . DisplayName
LIMIT : Limit
OFFSET : Offset
2018-10-25 13:25:27 -04:00
` , map [ string ] interface { } {
2019-06-17 10:27:19 -04:00
"TeamId" : teamId ,
"UserId" : userId ,
"Limit" : limit ,
"Offset" : offset ,
} )
2015-06-14 23:53:32 -08:00
2019-06-17 10:27:19 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetMoreChannels" , "store.sql_channel.get_more_channels.get.app_error" , nil , "teamId=" + teamId + ", userId=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-17 10:27:19 -04:00
return channels , nil
2017-03-13 21:26:51 +09:00
}
2019-06-20 08:36:47 -04:00
func ( s SqlChannelStore ) GetPublicChannelsForTeam ( teamId string , offset int , limit int ) ( * model . ChannelList , * model . AppError ) {
channels := & model . ChannelList { }
_ , err := s . GetReplica ( ) . Select ( channels , `
SELECT
Channels . *
FROM
Channels
JOIN
PublicChannels pc ON ( pc . Id = Channels . Id )
WHERE
pc . TeamId = : TeamId
AND pc . DeleteAt = 0
ORDER BY pc . DisplayName
LIMIT : Limit
OFFSET : Offset
2018-10-25 13:25:27 -04:00
` , map [ string ] interface { } {
2019-06-20 08:36:47 -04:00
"TeamId" : teamId ,
"Limit" : limit ,
"Offset" : offset ,
} )
2017-03-13 21:26:51 +09:00
2019-06-20 08:36:47 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetPublicChannelsForTeam" , "store.sql_channel.get_public_channels.get.app_error" , nil , "teamId=" + teamId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-20 08:36:47 -04:00
return channels , nil
2017-03-27 20:41:40 +09:00
}
2019-06-18 17:14:09 -04:00
func ( s SqlChannelStore ) GetPublicChannelsByIdsForTeam ( teamId string , channelIds [ ] string ) ( * model . ChannelList , * model . AppError ) {
props := make ( map [ string ] interface { } )
props [ "teamId" ] = teamId
2017-03-27 20:41:40 +09:00
2019-06-18 17:14:09 -04:00
idQuery := ""
2017-03-27 20:41:40 +09:00
2019-06-18 17:14:09 -04:00
for index , channelId := range channelIds {
if len ( idQuery ) > 0 {
idQuery += ", "
2017-03-27 20:41:40 +09:00
}
2019-06-18 17:14:09 -04:00
props [ "channelId" + strconv . Itoa ( index ) ] = channelId
idQuery += ":channelId" + strconv . Itoa ( index )
}
data := & model . ChannelList { }
_ , err := s . GetReplica ( ) . Select ( data , `
SELECT
Channels . *
FROM
Channels
JOIN
PublicChannels pc ON ( pc . Id = Channels . Id )
WHERE
pc . TeamId = : teamId
AND pc . DeleteAt = 0
AND pc . Id IN ( ` +idQuery+ ` )
ORDER BY pc . DisplayName
2018-10-25 13:25:27 -04:00
` , props )
2017-03-27 20:41:40 +09:00
2019-06-18 17:14:09 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetPublicChannelsByIdsForTeam" , "store.sql_channel.get_channels_by_ids.get.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2017-03-27 20:41:40 +09:00
2019-06-18 17:14:09 -04:00
if len ( * data ) == 0 {
return nil , model . NewAppError ( "SqlChannelStore.GetPublicChannelsByIdsForTeam" , "store.sql_channel.get_channels_by_ids.not_found.app_error" , nil , "" , http . StatusNotFound )
}
2017-03-27 20:41:40 +09:00
2019-06-18 17:14:09 -04:00
return data , nil
2015-06-14 23:53:32 -08:00
}
2015-08-11 09:39:54 -04:00
type channelIdWithCountAndUpdateAt struct {
2015-08-10 14:47:45 -04:00
Id string
TotalMsgCount int64
2015-08-11 08:20:17 -04:00
UpdateAt int64
2015-08-10 14:47:45 -04:00
}
2019-06-17 10:47:34 -04:00
func ( s SqlChannelStore ) GetChannelCounts ( teamId string , userId string ) ( * model . ChannelCounts , * model . AppError ) {
var data [ ] channelIdWithCountAndUpdateAt
_ , err := s . GetReplica ( ) . Select ( & data , "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND (TeamId = :TeamId OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName" , map [ string ] interface { } { "TeamId" : teamId , "UserId" : userId } )
2015-08-10 14:47:45 -04:00
2019-06-17 10:47:34 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetChannelCounts" , "store.sql_channel.get_channel_counts.get.app_error" , nil , "teamId=" + teamId + ", userId=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2015-08-10 14:47:45 -04:00
2019-06-17 10:47:34 -04:00
counts := & model . ChannelCounts { Counts : make ( map [ string ] int64 ) , UpdateTimes : make ( map [ string ] int64 ) }
for i := range data {
v := data [ i ]
counts . Counts [ v . Id ] = v . TotalMsgCount
counts . UpdateTimes [ v . Id ] = v . UpdateAt
}
2018-07-20 12:39:48 +02:00
2019-06-17 10:47:34 -04:00
return counts , nil
2015-08-10 14:47:45 -04:00
}
2019-06-18 01:22:37 -04:00
func ( s SqlChannelStore ) GetTeamChannels ( teamId string ) ( * model . ChannelList , * model . AppError ) {
data := & model . ChannelList { }
_ , err := s . GetReplica ( ) . Select ( data , "SELECT * FROM Channels WHERE TeamId = :TeamId And Type != 'D' ORDER BY DisplayName" , map [ string ] interface { } { "TeamId" : teamId } )
2016-11-10 11:23:55 -03:00
2019-06-18 01:22:37 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetTeamChannels" , "store.sql_channel.get_channels.get.app_error" , nil , "teamId=" + teamId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-18 01:22:37 -04:00
if len ( * data ) == 0 {
return nil , model . NewAppError ( "SqlChannelStore.GetTeamChannels" , "store.sql_channel.get_channels.not_found.app_error" , nil , "teamId=" + teamId , http . StatusNotFound )
}
2018-07-20 12:39:48 +02:00
2019-06-18 01:22:37 -04:00
return data , nil
2016-11-10 11:23:55 -03:00
}
2019-06-20 09:21:36 -04:00
func ( s SqlChannelStore ) GetByName ( teamId string , name string , allowFromCache bool ) ( * model . Channel , * model . AppError ) {
2017-01-27 14:07:34 -05:00
return s . getByName ( teamId , name , false , allowFromCache )
2016-12-06 10:49:34 -05:00
}
2019-06-17 11:03:04 -04:00
func ( s SqlChannelStore ) GetByNames ( teamId string , names [ ] string , allowFromCache bool ) ( [ ] * model . Channel , * model . AppError ) {
var channels [ ] * model . Channel
if allowFromCache {
var misses [ ] string
visited := make ( map [ string ] struct { } )
for _ , name := range names {
if _ , ok := visited [ name ] ; ok {
continue
}
visited [ name ] = struct { } { }
if cacheItem , ok := channelByNameCache . Get ( teamId + name ) ; ok {
if s . metrics != nil {
s . metrics . IncrementMemCacheHitCounter ( "Channel By Name" )
2017-11-28 15:02:56 -06:00
}
2019-06-17 11:03:04 -04:00
channels = append ( channels , cacheItem . ( * model . Channel ) )
} else {
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "Channel By Name" )
2017-11-28 15:02:56 -06:00
}
2019-06-17 11:03:04 -04:00
misses = append ( misses , name )
2017-11-28 15:02:56 -06:00
}
}
2019-06-17 11:03:04 -04:00
names = misses
}
2017-11-28 15:02:56 -06:00
2019-06-17 11:03:04 -04:00
if len ( names ) > 0 {
props := map [ string ] interface { } { }
var namePlaceholders [ ] string
for _ , name := range names {
key := fmt . Sprintf ( "Name%v" , len ( namePlaceholders ) )
props [ key ] = name
namePlaceholders = append ( namePlaceholders , ":" + key )
}
2017-11-28 15:02:56 -06:00
2019-06-17 11:03:04 -04:00
var query string
if teamId == "" {
query = ` SELECT * FROM Channels WHERE Name IN ( ` + strings . Join ( namePlaceholders , ", " ) + ` ) AND DeleteAt = 0 `
} else {
props [ "TeamId" ] = teamId
query = ` SELECT * FROM Channels WHERE Name IN ( ` + strings . Join ( namePlaceholders , ", " ) + ` ) AND TeamId = :TeamId AND DeleteAt = 0 `
}
2017-11-28 15:02:56 -06:00
2019-06-17 11:03:04 -04:00
var dbChannels [ ] * model . Channel
if _ , err := s . GetReplica ( ) . Select ( & dbChannels , query , props ) ; err != nil && err != sql . ErrNoRows {
return nil , model . NewAppError ( "SqlChannelStore.GetByName" , "store.sql_channel.get_by_name.existing.app_error" , nil , "teamId=" + teamId + ", " + err . Error ( ) , http . StatusInternalServerError )
2017-11-28 15:02:56 -06:00
}
2019-06-17 11:03:04 -04:00
for _ , channel := range dbChannels {
channelByNameCache . AddWithExpiresInSecs ( teamId + channel . Name , channel , CHANNEL_CACHE_SEC )
channels = append ( channels , channel )
}
}
2017-11-28 15:02:56 -06:00
2019-06-17 11:03:04 -04:00
return channels , nil
2017-11-28 15:02:56 -06:00
}
2019-06-20 09:21:36 -04:00
func ( s SqlChannelStore ) GetByNameIncludeDeleted ( teamId string , name string , allowFromCache bool ) ( * model . Channel , * model . AppError ) {
2017-01-27 14:07:34 -05:00
return s . getByName ( teamId , name , true , allowFromCache )
2016-12-06 10:49:34 -05:00
}
2019-06-20 09:21:36 -04:00
func ( s SqlChannelStore ) getByName ( teamId string , name string , includeDeleted bool , allowFromCache bool ) ( * model . Channel , * model . AppError ) {
2016-12-06 10:49:34 -05:00
var query string
if includeDeleted {
query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name"
} else {
query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0"
}
2019-06-20 09:21:36 -04:00
channel := model . Channel { }
2015-06-14 23:53:32 -08:00
2019-06-20 09:21:36 -04:00
if allowFromCache {
if cacheItem , ok := channelByNameCache . Get ( teamId + name ) ; ok {
2018-07-20 12:39:48 +02:00
if s . metrics != nil {
2019-06-20 09:21:36 -04:00
s . metrics . IncrementMemCacheHitCounter ( "Channel By Name" )
2017-01-27 14:07:34 -05:00
}
2019-06-20 09:21:36 -04:00
return cacheItem . ( * model . Channel ) , nil
2017-01-27 14:07:34 -05:00
}
2019-06-20 09:21:36 -04:00
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "Channel By Name" )
}
}
2018-07-20 12:39:48 +02:00
2019-06-20 09:21:36 -04:00
if err := s . GetReplica ( ) . SelectOne ( & channel , query , map [ string ] interface { } { "TeamId" : teamId , "Name" : name } ) ; err != nil {
if err == sql . ErrNoRows {
return nil , model . NewAppError ( "SqlChannelStore.GetByName" , store . MISSING_CHANNEL_ERROR , nil , "teamId=" + teamId + ", " + "name=" + name + ", " + err . Error ( ) , http . StatusNotFound )
2015-06-14 23:53:32 -08:00
}
2019-06-20 09:21:36 -04:00
return nil , model . NewAppError ( "SqlChannelStore.GetByName" , "store.sql_channel.get_by_name.existing.app_error" , nil , "teamId=" + teamId + ", " + "name=" + name + ", " + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-20 09:21:36 -04:00
channelByNameCache . AddWithExpiresInSecs ( teamId + name , & channel , CHANNEL_CACHE_SEC )
return & channel , nil
2015-06-14 23:53:32 -08:00
}
2019-06-21 02:32:14 -04:00
func ( s SqlChannelStore ) GetDeletedByName ( teamId string , name string ) ( * model . Channel , * model . AppError ) {
channel := model . Channel { }
2017-01-26 02:14:12 +00:00
2019-06-21 02:32:14 -04:00
if err := s . GetReplica ( ) . SelectOne ( & channel , "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt != 0" , map [ string ] interface { } { "TeamId" : teamId , "Name" : name } ) ; err != nil {
if err == sql . ErrNoRows {
return nil , model . NewAppError ( "SqlChannelStore.GetDeletedByName" , "store.sql_channel.get_deleted_by_name.missing.app_error" , nil , "teamId=" + teamId + ", " + "name=" + name + ", " + err . Error ( ) , http . StatusNotFound )
2017-01-26 02:14:12 +00:00
}
2019-06-21 02:32:14 -04:00
return nil , model . NewAppError ( "SqlChannelStore.GetDeletedByName" , "store.sql_channel.get_deleted_by_name.existing.app_error" , nil , "teamId=" + teamId + ", " + "name=" + name + ", " + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-21 02:32:14 -04:00
return & channel , nil
2017-01-26 02:14:12 +00:00
}
2019-06-17 13:46:37 -04:00
func ( s SqlChannelStore ) GetDeleted ( teamId string , offset int , limit int ) ( * model . ChannelList , * model . AppError ) {
channels := & model . ChannelList { }
2017-05-09 14:52:46 +02:00
2019-06-17 13:46:37 -04:00
if _ , err := s . GetReplica ( ) . Select ( channels , "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND DeleteAt != 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset" , map [ string ] interface { } { "TeamId" : teamId , "Limit" : limit , "Offset" : offset } ) ; err != nil {
if err == sql . ErrNoRows {
return nil , model . NewAppError ( "SqlChannelStore.GetDeleted" , "store.sql_channel.get_deleted.missing.app_error" , nil , "teamId=" + teamId + ", " + err . Error ( ) , http . StatusNotFound )
2017-05-09 14:52:46 +02:00
}
2019-06-17 13:46:37 -04:00
return nil , model . NewAppError ( "SqlChannelStore.GetDeleted" , "store.sql_channel.get_deleted.existing.app_error" , nil , "teamId=" + teamId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-17 13:46:37 -04:00
return channels , nil
2017-05-09 14:52:46 +02:00
}
2018-04-20 19:49:13 +01:00
var CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY = `
SELECT
ChannelMembers . * ,
2019-04-30 20:36:21 +02:00
TeamScheme . DefaultChannelGuestRole TeamSchemeDefaultGuestRole ,
2018-04-20 19:49:13 +01:00
TeamScheme . DefaultChannelUserRole TeamSchemeDefaultUserRole ,
TeamScheme . DefaultChannelAdminRole TeamSchemeDefaultAdminRole ,
2019-04-30 20:36:21 +02:00
ChannelScheme . DefaultChannelGuestRole ChannelSchemeDefaultGuestRole ,
2018-04-20 19:49:13 +01:00
ChannelScheme . DefaultChannelUserRole ChannelSchemeDefaultUserRole ,
ChannelScheme . DefaultChannelAdminRole ChannelSchemeDefaultAdminRole
2018-09-13 13:47:17 -04:00
FROM
2018-04-20 19:49:13 +01:00
ChannelMembers
2018-09-13 13:47:17 -04:00
INNER JOIN
2018-04-20 19:49:13 +01:00
Channels ON ChannelMembers . ChannelId = Channels . Id
LEFT JOIN
Schemes ChannelScheme ON Channels . SchemeId = ChannelScheme . Id
LEFT JOIN
Teams ON Channels . TeamId = Teams . Id
LEFT JOIN
2018-09-13 13:47:17 -04:00
Schemes TeamScheme ON Teams . SchemeId = TeamScheme . Id
2018-04-20 19:49:13 +01:00
`
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) SaveMember ( member * model . ChannelMember ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2018-07-20 12:39:48 +02:00
defer s . InvalidateAllChannelMembersForUser ( member . UserId )
2015-07-29 11:30:56 -04:00
// Grab the channel we are saving this member to
2019-04-24 15:28:06 -04:00
channel , errCh := s . GetFromMaster ( member . ChannelId )
if errCh != nil {
result . Err = errCh
2018-07-20 12:39:48 +02:00
return
}
2015-07-29 11:30:56 -04:00
2018-07-20 12:39:48 +02:00
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.SaveMember" , "store.sql_channel.save_member.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
2015-06-14 23:53:32 -08:00
}
2019-02-23 19:44:52 +00:00
defer finalizeTransaction ( transaction )
2015-06-14 23:53:32 -08:00
2018-07-20 12:39:48 +02:00
* result = s . saveMemberT ( transaction , member , channel )
if result . Err != nil {
return
}
if err := transaction . Commit ( ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.SaveMember" , "store.sql_channel.save_member.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) saveMemberT ( transaction * gorp . Transaction , member * model . ChannelMember , channel * model . Channel ) store . StoreResult {
result := store . StoreResult { }
2015-10-22 09:31:27 -04:00
member . PreSave ( )
if result . Err = member . IsValid ( ) ; result . Err != nil {
return result
}
2018-04-20 19:49:13 +01:00
dbMember := NewChannelMemberFromModel ( member )
if err := transaction . Insert ( dbMember ) ; err != nil {
2017-09-06 14:00:56 -04:00
if IsUniqueConstraintError ( err , [ ] string { "ChannelId" , "channelmembers_pkey" } ) {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.SaveMember" , "store.sql_channel.save_member.exists.app_error" , nil , "channel_id=" + member . ChannelId + ", user_id=" + member . UserId + ", " + err . Error ( ) , http . StatusBadRequest )
2018-07-20 12:39:48 +02:00
return result
2015-10-22 09:31:27 -04:00
}
2018-07-20 12:39:48 +02:00
result . Err = model . NewAppError ( "SqlChannelStore.SaveMember" , "store.sql_channel.save_member.save.app_error" , nil , "channel_id=" + member . ChannelId + ", user_id=" + member . UserId + ", " + err . Error ( ) , http . StatusInternalServerError )
return result
}
var retrievedMember channelMemberWithSchemeRoles
if err := transaction . SelectOne ( & retrievedMember , CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY + "WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId" , map [ string ] interface { } { "ChannelId" : dbMember . ChannelId , "UserId" : dbMember . UserId } ) ; err != nil {
if err == sql . ErrNoRows {
result . Err = model . NewAppError ( "SqlChannelStore.GetMember" , store . MISSING_CHANNEL_MEMBER_ERROR , nil , "channel_id=" + dbMember . ChannelId + "user_id=" + dbMember . UserId + "," + err . Error ( ) , http . StatusNotFound )
return result
2018-04-20 19:49:13 +01:00
}
2018-07-20 12:39:48 +02:00
result . Err = model . NewAppError ( "SqlChannelStore.GetMember" , "store.sql_channel.get_member.app_error" , nil , "channel_id=" + dbMember . ChannelId + "user_id=" + dbMember . UserId + "," + err . Error ( ) , http . StatusInternalServerError )
return result
2015-10-22 09:31:27 -04:00
}
2018-07-20 12:39:48 +02:00
result . Data = retrievedMember . ToModel ( )
2015-10-22 09:31:27 -04:00
return result
}
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) UpdateMember ( member * model . ChannelMember ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-09-30 11:08:36 -04:00
member . PreUpdate ( )
if result . Err = member . IsValid ( ) ; result . Err != nil {
return
}
2018-04-20 19:49:13 +01:00
if _ , err := s . GetMaster ( ) . Update ( NewChannelMemberFromModel ( member ) ) ; err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.UpdateMember" , "store.sql_channel.update_member.app_error" , nil , "channel_id=" + member . ChannelId + ", " + "user_id=" + member . UserId + ", " + err . Error ( ) , http . StatusInternalServerError )
2018-07-20 12:39:48 +02:00
return
}
2018-04-20 19:49:13 +01:00
2018-07-20 12:39:48 +02:00
var dbMember channelMemberWithSchemeRoles
if err := s . GetReplica ( ) . SelectOne ( & dbMember , CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY + "WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId" , map [ string ] interface { } { "ChannelId" : member . ChannelId , "UserId" : member . UserId } ) ; err != nil {
if err == sql . ErrNoRows {
result . Err = model . NewAppError ( "SqlChannelStore.GetMember" , store . MISSING_CHANNEL_MEMBER_ERROR , nil , "channel_id=" + member . ChannelId + "user_id=" + member . UserId + "," + err . Error ( ) , http . StatusNotFound )
return
2018-04-20 19:49:13 +01:00
}
2018-07-20 12:39:48 +02:00
result . Err = model . NewAppError ( "SqlChannelStore.GetMember" , "store.sql_channel.get_member.app_error" , nil , "channel_id=" + member . ChannelId + "user_id=" + member . UserId + "," + err . Error ( ) , http . StatusInternalServerError )
return
2015-09-30 11:08:36 -04:00
}
2018-07-20 12:39:48 +02:00
result . Data = dbMember . ToModel ( )
2017-10-06 08:12:10 -07:00
} )
2015-09-30 11:08:36 -04:00
}
2019-06-19 23:24:02 +04:00
func ( s SqlChannelStore ) GetMembers ( channelId string , offset , limit int ) ( * model . ChannelMembers , * model . AppError ) {
var dbMembers channelMemberWithSchemeRolesList
_ , err := s . GetReplica ( ) . Select ( & dbMembers , CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY + "WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset" , map [ string ] interface { } { "ChannelId" : channelId , "Limit" : limit , "Offset" : offset } )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetMembers" , "store.sql_channel.get_members.app_error" , nil , "channel_id=" + channelId + "," + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-19 23:24:02 +04:00
return dbMembers . ToModel ( ) , nil
2015-06-14 23:53:32 -08:00
}
2019-06-19 08:23:08 +00:00
func ( s SqlChannelStore ) GetChannelMembersTimezones ( channelId string ) ( [ ] model . StringMap , * model . AppError ) {
var dbMembersTimezone [ ] model . StringMap
_ , err := s . GetReplica ( ) . Select ( & dbMembersTimezone , `
SELECT
Users . Timezone
FROM
ChannelMembers
LEFT JOIN
Users ON ChannelMembers . UserId = Id
WHERE ChannelId = : ChannelId
` , map [ string ] interface { } { "ChannelId" : channelId } )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetChannelMembersTimezones" , "store.sql_channel.get_members.app_error" , nil , "channel_id=" + channelId + "," + err . Error ( ) , http . StatusInternalServerError )
}
return dbMembersTimezone , nil
2018-10-13 12:35:57 +02:00
}
2019-04-15 22:53:52 +02:00
func ( s SqlChannelStore ) GetMember ( channelId string , userId string ) ( * model . ChannelMember , * model . AppError ) {
var dbMember channelMemberWithSchemeRoles
2016-04-28 10:56:19 -04:00
2019-04-15 22:53:52 +02:00
if err := s . GetReplica ( ) . SelectOne ( & dbMember , CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY + "WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId" , map [ string ] interface { } { "ChannelId" : channelId , "UserId" : userId } ) ; err != nil {
if err == sql . ErrNoRows {
return nil , model . NewAppError ( "SqlChannelStore.GetMember" , store . MISSING_CHANNEL_MEMBER_ERROR , nil , "channel_id=" + channelId + "user_id=" + userId + "," + err . Error ( ) , http . StatusNotFound )
2015-06-14 23:53:32 -08:00
}
2019-04-15 22:53:52 +02:00
return nil , model . NewAppError ( "SqlChannelStore.GetMember" , "store.sql_channel.get_member.app_error" , nil , "channel_id=" + channelId + "user_id=" + userId + "," + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-04-15 22:53:52 +02:00
return dbMember . ToModel ( ) , nil
2015-06-14 23:53:32 -08:00
}
2018-03-05 10:35:26 -05:00
func ( s SqlChannelStore ) InvalidateAllChannelMembersForUser ( userId string ) {
2016-10-19 14:49:25 -04:00
allChannelMembersForUserCache . Remove ( userId )
2018-08-14 19:30:27 +02:00
allChannelMembersForUserCache . Remove ( userId + "_deleted" )
2018-03-05 10:35:26 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheInvalidationCounter ( "All Channel Members for User - Remove by UserId" )
}
2016-10-19 14:49:25 -04:00
}
2018-03-05 10:35:26 -05:00
func ( s SqlChannelStore ) IsUserInChannelUseCache ( userId string , channelId string ) bool {
2016-10-19 14:49:25 -04:00
if cacheItem , ok := allChannelMembersForUserCache . Get ( userId ) ; ok {
2018-03-05 10:35:26 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheHitCounter ( "All Channel Members for User" )
2016-12-19 10:16:22 -05:00
}
2016-10-19 14:49:25 -04:00
ids := cacheItem . ( map [ string ] string )
if _ , ok := ids [ channelId ] ; ok {
return true
2016-12-19 10:16:22 -05:00
}
2018-07-20 12:39:48 +02:00
return false
2016-10-19 14:49:25 -04:00
}
2018-07-20 12:39:48 +02:00
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "All Channel Members for User" )
}
2018-07-30 15:06:08 -04:00
result := <- s . GetAllChannelMembersForUser ( userId , true , false )
2018-07-20 12:39:48 +02:00
if result . Err != nil {
2018-04-27 12:49:45 -07:00
mlog . Error ( "SqlChannelStore.IsUserInChannelUseCache: " + result . Err . Error ( ) )
2016-10-19 14:49:25 -04:00
return false
}
2018-07-20 12:39:48 +02:00
ids := result . Data . ( map [ string ] string )
if _ , ok := ids [ channelId ] ; ok {
return true
}
return false
2016-10-19 14:49:25 -04:00
}
2019-06-20 13:07:26 +05:30
func ( s SqlChannelStore ) GetMemberForPost ( postId string , userId string ) ( * model . ChannelMember , * model . AppError ) {
var dbMember channelMemberWithSchemeRoles
query := `
SELECT
ChannelMembers . * ,
TeamScheme . DefaultChannelGuestRole TeamSchemeDefaultGuestRole ,
TeamScheme . DefaultChannelUserRole TeamSchemeDefaultUserRole ,
TeamScheme . DefaultChannelAdminRole TeamSchemeDefaultAdminRole ,
ChannelScheme . DefaultChannelGuestRole ChannelSchemeDefaultGuestRole ,
ChannelScheme . DefaultChannelUserRole ChannelSchemeDefaultUserRole ,
ChannelScheme . DefaultChannelAdminRole ChannelSchemeDefaultAdminRole
FROM
ChannelMembers
INNER JOIN
Posts ON ChannelMembers . ChannelId = Posts . ChannelId
INNER JOIN
Channels ON ChannelMembers . ChannelId = Channels . Id
LEFT JOIN
Schemes ChannelScheme ON Channels . SchemeId = ChannelScheme . Id
LEFT JOIN
Teams ON Channels . TeamId = Teams . Id
LEFT JOIN
Schemes TeamScheme ON Teams . SchemeId = TeamScheme . Id
WHERE
ChannelMembers . UserId = : UserId
AND
Posts . Id = : PostId `
if err := s . GetReplica ( ) . SelectOne ( & dbMember , query , map [ string ] interface { } { "UserId" : userId , "PostId" : postId } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetMemberForPost" , "store.sql_channel.get_member_for_post.app_error" , nil , "postId=" + postId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
return dbMember . ToModel ( ) , nil
2016-09-30 11:06:30 -04:00
}
2018-07-30 15:06:08 -04:00
func ( s SqlChannelStore ) GetAllChannelMembersForUser ( userId string , allowFromCache bool , includeDeleted bool ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2018-08-14 19:30:27 +02:00
cache_key := userId
if includeDeleted {
cache_key += "_deleted"
}
2016-10-19 14:49:25 -04:00
if allowFromCache {
2018-08-14 19:30:27 +02:00
if cacheItem , ok := allChannelMembersForUserCache . Get ( cache_key ) ; ok {
2017-09-14 12:01:44 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheHitCounter ( "All Channel Members for User" )
2016-12-19 10:16:22 -05:00
}
2016-10-19 14:49:25 -04:00
result . Data = cacheItem . ( map [ string ] string )
return
}
}
2018-07-20 12:39:48 +02:00
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "All Channel Members for User" )
}
2018-07-30 15:06:08 -04:00
var deletedClause string
if ! includeDeleted {
deletedClause = "Channels.DeleteAt = 0 AND"
}
2018-04-20 19:49:13 +01:00
var data allChannelMembers
_ , err := s . GetReplica ( ) . Select ( & data , `
SELECT
2019-04-30 20:36:21 +02:00
ChannelMembers . ChannelId , ChannelMembers . Roles ,
ChannelMembers . SchemeGuest , ChannelMembers . SchemeUser , ChannelMembers . SchemeAdmin ,
TeamScheme . DefaultChannelGuestRole TeamSchemeDefaultGuestRole ,
2018-04-20 19:49:13 +01:00
TeamScheme . DefaultChannelUserRole TeamSchemeDefaultUserRole ,
TeamScheme . DefaultChannelAdminRole TeamSchemeDefaultAdminRole ,
2019-04-30 20:36:21 +02:00
ChannelScheme . DefaultChannelGuestRole ChannelSchemeDefaultGuestRole ,
2018-04-20 19:49:13 +01:00
ChannelScheme . DefaultChannelUserRole ChannelSchemeDefaultUserRole ,
ChannelScheme . DefaultChannelAdminRole ChannelSchemeDefaultAdminRole
2018-07-20 12:39:48 +02:00
FROM
2018-04-20 19:49:13 +01:00
ChannelMembers
2018-07-20 12:39:48 +02:00
INNER JOIN
2018-04-20 19:49:13 +01:00
Channels ON ChannelMembers . ChannelId = Channels . Id
LEFT JOIN
Schemes ChannelScheme ON Channels . SchemeId = ChannelScheme . Id
LEFT JOIN
Teams ON Channels . TeamId = Teams . Id
LEFT JOIN
Schemes TeamScheme ON Teams . SchemeId = TeamScheme . Id
WHERE
2018-07-30 15:06:08 -04:00
` +deletedClause+ `
ChannelMembers . UserId = : UserId ` , map [ string ] interface { } { "UserId" : userId } )
2016-10-19 14:49:25 -04:00
2015-11-12 11:25:46 -05:00
if err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.GetAllChannelMembersForUser" , "store.sql_channel.get_channels.get.app_error" , nil , "userId=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2018-07-20 12:39:48 +02:00
return
}
2016-10-19 14:49:25 -04:00
2018-07-20 12:39:48 +02:00
ids := data . ToMapStringString ( )
result . Data = ids
2016-10-19 14:49:25 -04:00
2018-07-20 12:39:48 +02:00
if allowFromCache {
2018-08-14 19:30:27 +02:00
allChannelMembersForUserCache . AddWithExpiresInSecs ( cache_key , ids , ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC )
2015-11-12 11:25:46 -05:00
}
2017-10-06 08:12:10 -07:00
} )
2015-11-12 11:25:46 -05:00
}
2018-03-05 10:35:26 -05:00
func ( s SqlChannelStore ) InvalidateCacheForChannelMembersNotifyProps ( channelId string ) {
2017-02-23 11:08:48 -03:00
allChannelMembersNotifyPropsForChannelCache . Remove ( channelId )
2018-03-05 10:35:26 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheInvalidationCounter ( "All Channel Members Notify Props for Channel - Remove by ChannelId" )
}
2017-02-23 11:08:48 -03:00
}
type allChannelMemberNotifyProps struct {
UserId string
NotifyProps model . StringMap
}
2019-06-18 17:56:29 +04:00
func ( s SqlChannelStore ) GetAllChannelMembersNotifyPropsForChannel ( channelId string , allowFromCache bool ) ( map [ string ] model . StringMap , * model . AppError ) {
if allowFromCache {
if cacheItem , ok := allChannelMembersNotifyPropsForChannelCache . Get ( channelId ) ; ok {
if s . metrics != nil {
s . metrics . IncrementMemCacheHitCounter ( "All Channel Members Notify Props for Channel" )
2017-02-23 11:08:48 -03:00
}
2019-06-18 17:56:29 +04:00
return cacheItem . ( map [ string ] model . StringMap ) , nil
2017-02-23 11:08:48 -03:00
}
2019-06-18 17:56:29 +04:00
}
2017-02-23 11:08:48 -03:00
2019-06-18 17:56:29 +04:00
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "All Channel Members Notify Props for Channel" )
}
2018-07-20 12:39:48 +02:00
2019-06-18 17:56:29 +04:00
var data [ ] allChannelMemberNotifyProps
_ , err := s . GetReplica ( ) . Select ( & data , `
SELECT UserId , NotifyProps
FROM ChannelMembers
WHERE ChannelId = : ChannelId ` , map [ string ] interface { } { "ChannelId" : channelId } )
2017-02-23 11:08:48 -03:00
2019-06-18 17:56:29 +04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllChannelMembersPropsForChannel" , "store.sql_channel.get_members.app_error" , nil , "channelId=" + channelId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2017-02-23 11:08:48 -03:00
2019-06-18 17:56:29 +04:00
props := make ( map [ string ] model . StringMap )
for i := range data {
props [ data [ i ] . UserId ] = data [ i ] . NotifyProps
}
2017-02-23 11:08:48 -03:00
2019-06-18 17:56:29 +04:00
allChannelMembersNotifyPropsForChannelCache . AddWithExpiresInSecs ( channelId , props , ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC )
2017-02-23 11:08:48 -03:00
2019-06-18 17:56:29 +04:00
return props , nil
2017-02-23 11:08:48 -03:00
}
2018-03-05 10:35:26 -05:00
func ( s SqlChannelStore ) InvalidateMemberCount ( channelId string ) {
2016-11-24 05:26:45 -08:00
channelMemberCountsCache . Remove ( channelId )
2018-03-05 10:35:26 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheInvalidationCounter ( "Channel Member Counts - Remove by ChannelId" )
}
2016-11-24 05:26:45 -08:00
}
2017-01-03 11:45:45 -05:00
func ( s SqlChannelStore ) GetMemberCountFromCache ( channelId string ) int64 {
if cacheItem , ok := channelMemberCountsCache . Get ( channelId ) ; ok {
2017-09-14 12:01:44 -05:00
if s . metrics != nil {
s . metrics . IncrementMemCacheHitCounter ( "Channel Member Counts" )
2017-01-03 11:45:45 -05:00
}
return cacheItem . ( int64 )
}
2018-07-20 12:39:48 +02:00
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "Channel Member Counts" )
}
2019-06-20 18:25:53 +04:00
count , err := s . GetMemberCount ( channelId , true )
if err != nil {
2017-01-03 11:45:45 -05:00
return 0
}
2018-07-20 12:39:48 +02:00
2019-06-20 18:25:53 +04:00
return count
2017-01-03 11:45:45 -05:00
}
2019-06-20 18:25:53 +04:00
func ( s SqlChannelStore ) GetMemberCount ( channelId string , allowFromCache bool ) ( int64 , * model . AppError ) {
if allowFromCache {
if cacheItem , ok := channelMemberCountsCache . Get ( channelId ) ; ok {
if s . metrics != nil {
s . metrics . IncrementMemCacheHitCounter ( "Channel Member Counts" )
2016-11-24 05:26:45 -08:00
}
2019-06-20 18:25:53 +04:00
return cacheItem . ( int64 ) , nil
2016-11-24 05:26:45 -08:00
}
2019-06-20 18:25:53 +04:00
}
2016-11-24 05:26:45 -08:00
2019-06-20 18:25:53 +04:00
if s . metrics != nil {
s . metrics . IncrementMemCacheMissCounter ( "Channel Member Counts" )
}
2018-07-20 12:39:48 +02:00
2019-06-20 18:25:53 +04:00
count , err := s . GetReplica ( ) . SelectInt ( `
SELECT
count ( * )
FROM
ChannelMembers ,
Users
WHERE
ChannelMembers . UserId = Users . Id
AND ChannelMembers . ChannelId = : ChannelId
AND Users . DeleteAt = 0 ` , map [ string ] interface { } { "ChannelId" : channelId } )
if err != nil {
return 0 , model . NewAppError ( "SqlChannelStore.GetMemberCount" , "store.sql_channel.get_member_count.app_error" , nil , "channel_id=" + channelId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
2016-11-24 05:26:45 -08:00
2019-06-20 18:25:53 +04:00
if allowFromCache {
channelMemberCountsCache . AddWithExpiresInSecs ( channelId , count , CHANNEL_MEMBERS_COUNTS_CACHE_SEC )
}
return count , nil
2015-06-14 23:53:32 -08:00
}
2019-06-18 12:28:47 -07:00
func ( s SqlChannelStore ) RemoveMember ( channelId string , userId string ) * model . AppError {
_ , err := s . GetMaster ( ) . Exec ( "DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId" , map [ string ] interface { } { "ChannelId" : channelId , "UserId" : userId } )
if err != nil {
return model . NewAppError ( "SqlChannelStore.RemoveMember" , "store.sql_channel.remove_member.app_error" , nil , "channel_id=" + channelId + ", user_id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
return nil
2015-11-15 18:18:02 -08:00
}
2019-06-18 14:09:15 -07:00
func ( s SqlChannelStore ) RemoveAllDeactivatedMembers ( channelId string ) * model . AppError {
query := `
DELETE
FROM
ChannelMembers
WHERE
UserId IN (
SELECT
Id
FROM
Users
WHERE
Users . DeleteAt != 0
)
AND
ChannelMembers . ChannelId = : ChannelId
`
_ , err := s . GetMaster ( ) . Exec ( query , map [ string ] interface { } { "ChannelId" : channelId } )
if err != nil {
return model . NewAppError ( "SqlChannelStore.RemoveAllDeactivatedMembers" , "store.sql_channel.remove_all_deactivated_members.app_error" , nil , "channel_id=" + channelId + ", " + err . Error ( ) , http . StatusInternalServerError )
}
return nil
2018-10-08 16:39:03 +01:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) PermanentDeleteMembersByUser ( userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-11-15 18:18:02 -08:00
if _ , err := s . GetMaster ( ) . Exec ( "DELETE FROM ChannelMembers WHERE UserId = :UserId" , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.RemoveMember" , "store.sql_channel.permanent_delete_members_by_user.app_error" , nil , "user_id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-11-15 18:18:02 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) UpdateLastViewedAt ( channelIds [ ] string , userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2016-12-23 10:32:30 -05:00
props := make ( map [ string ] interface { } )
2017-09-29 11:45:59 -04:00
updateIdQuery := ""
2016-12-23 10:32:30 -05:00
for index , channelId := range channelIds {
2017-09-29 11:45:59 -04:00
if len ( updateIdQuery ) > 0 {
updateIdQuery += " OR "
2016-12-23 10:32:30 -05:00
}
props [ "channelId" + strconv . Itoa ( index ) ] = channelId
2017-09-29 11:45:59 -04:00
updateIdQuery += "ChannelId = :channelId" + strconv . Itoa ( index )
}
selectIdQuery := strings . Replace ( updateIdQuery , "ChannelId" , "Id" , - 1 )
var lastPostAtTimes [ ] struct {
Id string
LastPostAt int64
TotalMsgCount int64
}
selectQuery := "SELECT Id, LastPostAt, TotalMsgCount FROM Channels WHERE (" + selectIdQuery + ")"
2018-12-12 10:08:55 -08:00
if _ , err := s . GetMaster ( ) . Select ( & lastPostAtTimes , selectQuery , props ) ; err != nil || len ( lastPostAtTimes ) <= 0 {
var extra string
status := http . StatusInternalServerError
if err == nil {
status = http . StatusBadRequest
extra = "No channels found"
} else {
extra = err . Error ( )
}
result . Err = model . NewAppError ( "SqlChannelStore.UpdateLastViewedAt" , "store.sql_channel.update_last_viewed_at.app_error" , nil , "channel_ids=" + strings . Join ( channelIds , "," ) + ", user_id=" + userId + ", " + extra , status )
2017-09-29 11:45:59 -04:00
return
2016-12-23 10:32:30 -05:00
}
2015-07-12 19:12:23 -08:00
2017-09-29 11:45:59 -04:00
times := map [ string ] int64 { }
msgCountQuery := ""
lastViewedQuery := ""
for index , t := range lastPostAtTimes {
times [ t . Id ] = t . LastPostAt
props [ "msgCount" + strconv . Itoa ( index ) ] = t . TotalMsgCount
msgCountQuery += fmt . Sprintf ( "WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) " , index , index )
props [ "lastViewed" + strconv . Itoa ( index ) ] = t . LastPostAt
lastViewedQuery += fmt . Sprintf ( "WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) " , index , index )
props [ "channelId" + strconv . Itoa ( index ) ] = t . Id
}
var updateQuery string
2017-10-09 10:16:14 -07:00
if s . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
2017-09-29 11:45:59 -04:00
updateQuery = ` UPDATE
2015-07-12 14:56:44 -08:00
ChannelMembers
2015-06-14 23:53:32 -08:00
SET
2015-07-12 14:56:44 -08:00
MentionCount = 0 ,
2017-09-29 11:45:59 -04:00
MsgCount = CAST ( CASE ChannelId ` + msgCountQuery + ` END AS BIGINT ) ,
LastViewedAt = CAST ( CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT ) ,
LastUpdateAt = CAST ( CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT )
2015-06-14 23:53:32 -08:00
WHERE
2017-09-29 11:45:59 -04:00
UserId = : UserId
AND ( ` + updateIdQuery + ` ) `
2017-10-09 10:16:14 -07:00
} else if s . DriverName ( ) == model . DATABASE_DRIVER_MYSQL {
2017-09-29 11:45:59 -04:00
updateQuery = ` UPDATE
ChannelMembers
2015-07-12 19:12:23 -08:00
SET
2017-09-29 11:45:59 -04:00
MentionCount = 0 ,
MsgCount = CASE ChannelId ` + msgCountQuery + ` END ,
LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END ,
LastUpdateAt = CASE ChannelId ` + lastViewedQuery + ` END
2015-07-12 19:12:23 -08:00
WHERE
2017-09-29 11:45:59 -04:00
UserId = : UserId
AND ( ` + updateIdQuery + ` ) `
2015-07-12 19:12:23 -08:00
}
2016-12-23 10:32:30 -05:00
props [ "UserId" ] = userId
2017-09-29 11:45:59 -04:00
if _ , err := s . GetMaster ( ) . Exec ( updateQuery , props ) ; err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.UpdateLastViewedAt" , "store.sql_channel.update_last_viewed_at.app_error" , nil , "channel_ids=" + strings . Join ( channelIds , "," ) + ", user_id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2018-07-20 12:39:48 +02:00
return
2015-06-14 23:53:32 -08:00
}
2018-07-20 12:39:48 +02:00
result . Data = times
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) IncrementMentionCount ( channelId string , userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2015-06-14 23:53:32 -08:00
_ , err := s . GetMaster ( ) . Exec (
` UPDATE
ChannelMembers
SET
2016-10-27 12:24:30 -03:00
MentionCount = MentionCount + 1 ,
LastUpdateAt = : LastUpdateAt
2015-06-14 23:53:32 -08:00
WHERE
2015-07-12 14:56:44 -08:00
UserId = : UserId
AND ChannelId = : ChannelId ` ,
2016-10-27 12:24:30 -03:00
map [ string ] interface { } { "ChannelId" : channelId , "UserId" : userId , "LastUpdateAt" : model . GetMillis ( ) } )
2015-06-14 23:53:32 -08:00
if err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.IncrementMentionCount" , "store.sql_channel.increment_mention_count.app_error" , nil , "channel_id=" + channelId + ", user_id=" + userId + ", " + err . Error ( ) , http . StatusInternalServerError )
2015-06-14 23:53:32 -08:00
}
2017-10-06 08:12:10 -07:00
} )
2015-06-14 23:53:32 -08:00
}
2019-06-19 03:40:05 -06:00
func ( s SqlChannelStore ) GetAll ( teamId string ) ( [ ] * model . Channel , * model . AppError ) {
var data [ ] * model . Channel
_ , err := s . GetReplica ( ) . Select ( & data , "SELECT * FROM Channels WHERE TeamId = :TeamId AND Type != 'D' ORDER BY Name" , map [ string ] interface { } { "TeamId" : teamId } )
2016-07-06 10:11:21 -08:00
2019-06-19 03:40:05 -06:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAll" , "store.sql_channel.get_all.app_error" , nil , "teamId=" + teamId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-19 03:40:05 -06:00
return data , nil
2016-07-06 10:11:21 -08:00
}
2019-06-18 00:15:51 +05:30
func ( s SqlChannelStore ) GetChannelsByIds ( channelIds [ ] string ) ( [ ] * model . Channel , * model . AppError ) {
keys , params := MapStringsToQueryParams ( channelIds , "Channel" )
query := ` SELECT * FROM Channels WHERE Id IN ` + keys + ` ORDER BY Name `
2019-03-15 17:53:53 +00:00
2019-06-18 00:15:51 +05:30
var channels [ ] * model . Channel
_ , err := s . GetReplica ( ) . Select ( & channels , query , params )
2019-03-15 17:53:53 +00:00
2019-06-18 00:15:51 +05:30
if err != nil {
mlog . Error ( fmt . Sprint ( err ) )
return nil , model . NewAppError ( "SqlChannelStore.GetChannelsByIds" , "store.sql_channel.get_channels_by_ids.app_error" , nil , "" , http . StatusInternalServerError )
}
return channels , nil
2019-03-15 17:53:53 +00:00
}
2019-06-19 02:27:09 -06:00
func ( s SqlChannelStore ) GetForPost ( postId string ) ( * model . Channel , * model . AppError ) {
channel := & model . Channel { }
if err := s . GetReplica ( ) . SelectOne (
channel ,
` SELECT
Channels . *
FROM
Channels ,
Posts
WHERE
Channels . Id = Posts . ChannelId
AND Posts . Id = : PostId ` , map [ string ] interface { } { "PostId" : postId } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetForPost" , "store.sql_channel.get_for_post.app_error" , nil , "postId=" + postId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2018-07-20 12:39:48 +02:00
2019-06-19 02:27:09 -06:00
}
return channel , nil
2016-09-30 11:06:30 -04:00
}
2019-06-14 19:06:30 +02:00
func ( s SqlChannelStore ) AnalyticsTypeCount ( teamId string , channelType string ) ( int64 , * model . AppError ) {
query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType"
2016-01-21 12:14:17 -05:00
2019-06-14 19:06:30 +02:00
if len ( teamId ) > 0 {
query += " AND TeamId = :TeamId"
}
2018-07-20 12:39:48 +02:00
2019-06-14 19:06:30 +02:00
value , err := s . GetReplica ( ) . SelectInt ( query , map [ string ] interface { } { "TeamId" : teamId , "ChannelType" : channelType } )
if err != nil {
return int64 ( 0 ) , model . NewAppError ( "SqlChannelStore.AnalyticsTypeCount" , "store.sql_channel.analytics_type_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return value , nil
2015-10-22 18:04:06 -07:00
}
2016-02-25 04:24:03 -03:00
2019-06-19 15:23:16 +00:00
func ( s SqlChannelStore ) AnalyticsDeletedTypeCount ( teamId string , channelType string ) ( int64 , * model . AppError ) {
query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType AND DeleteAt > 0"
2017-02-24 17:33:59 +00:00
2019-06-19 15:23:16 +00:00
if len ( teamId ) > 0 {
query += " AND TeamId = :TeamId"
}
2017-02-24 17:33:59 +00:00
2019-06-19 15:23:16 +00:00
v , err := s . GetReplica ( ) . SelectInt ( query , map [ string ] interface { } { "TeamId" : teamId , "ChannelType" : channelType } )
if err != nil {
return 0 , model . NewAppError ( "SqlChannelStore.AnalyticsDeletedTypeCount" , "store.sql_channel.analytics_deleted_type_count.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2018-07-20 12:39:48 +02:00
2019-06-19 15:23:16 +00:00
return v , nil
2017-02-24 17:33:59 +00:00
}
2017-09-25 09:11:25 -05:00
func ( s SqlChannelStore ) GetMembersForUser ( teamId string , userId string ) store . StoreChannel {
2017-10-06 08:12:10 -07:00
return store . Do ( func ( result * store . StoreResult ) {
2018-04-20 19:49:13 +01:00
var dbMembers channelMemberWithSchemeRolesList
_ , err := s . GetReplica ( ) . Select ( & dbMembers , CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY + "WHERE ChannelMembers.UserId = :UserId" , map [ string ] interface { } { "TeamId" : teamId , "UserId" : userId } )
2016-10-27 12:24:30 -03:00
if err != nil {
2017-09-04 16:37:13 +01:00
result . Err = model . NewAppError ( "SqlChannelStore.GetMembersForUser" , "store.sql_channel.get_members.app_error" , nil , "teamId=" + teamId + ", userId=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
2018-07-20 12:39:48 +02:00
return
2016-10-27 12:24:30 -03:00
}
2018-07-20 12:39:48 +02:00
result . Data = dbMembers . ToModel ( )
2017-10-06 08:12:10 -07:00
} )
2016-10-27 12:24:30 -03:00
}
2016-11-24 09:35:09 -05:00
2019-02-23 11:41:19 -08:00
func ( s SqlChannelStore ) GetMembersForUserWithPagination ( teamId , userId string , page , perPage int ) store . StoreChannel {
return store . Do ( func ( result * store . StoreResult ) {
var dbMembers channelMemberWithSchemeRolesList
offset := page * perPage
_ , err := s . GetReplica ( ) . Select ( & dbMembers , CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY + "WHERE ChannelMembers.UserId = :UserId Limit :Limit Offset :Offset" , map [ string ] interface { } { "TeamId" : teamId , "UserId" : userId , "Limit" : perPage , "Offset" : offset } )
if err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.GetMembersForUserWithPagination" , "store.sql_channel.get_members.app_error" , nil , "teamId=" + teamId + ", userId=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
return
}
result . Data = dbMembers . ToModel ( )
} )
}
2019-06-17 14:32:37 -04:00
func ( s SqlChannelStore ) AutocompleteInTeam ( teamId string , term string , includeDeleted bool ) ( * model . ChannelList , * model . AppError ) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
}
2018-07-30 15:06:08 -04:00
2019-06-17 14:32:37 -04:00
queryFormat := `
SELECT
Channels . *
FROM
Channels
JOIN
PublicChannels c ON ( c . Id = Channels . Id )
WHERE
c . TeamId = : TeamId
` + deleteFilter + `
% v
LIMIT ` + strconv . Itoa ( model . CHANNEL_SEARCH_DEFAULT_LIMIT )
2018-01-31 08:26:40 -06:00
2019-06-17 14:32:37 -04:00
var channels model . ChannelList
2018-01-31 08:26:40 -06:00
2019-06-17 14:32:37 -04:00
if likeClause , likeTerm := s . buildLIKEClause ( term , "c.Name, c.DisplayName, c.Purpose" ) ; likeClause == "" {
if _ , err := s . GetReplica ( ) . Select ( & channels , fmt . Sprintf ( queryFormat , "" ) , map [ string ] interface { } { "TeamId" : teamId } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.AutocompleteInTeam" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
}
} else {
// Using a UNION results in index_merge and fulltext queries and is much faster than the ref
// query you would get using an OR of the LIKE and full-text clauses.
fulltextClause , fulltextTerm := s . buildFulltextClause ( term , "c.Name, c.DisplayName, c.Purpose" )
likeQuery := fmt . Sprintf ( queryFormat , "AND " + likeClause )
fulltextQuery := fmt . Sprintf ( queryFormat , "AND " + fulltextClause )
query := fmt . Sprintf ( "(%v) UNION (%v) LIMIT 50" , likeQuery , fulltextQuery )
2018-01-31 08:26:40 -06:00
2019-06-17 14:32:37 -04:00
if _ , err := s . GetReplica ( ) . Select ( & channels , query , map [ string ] interface { } { "TeamId" : teamId , "LikeTerm" : likeTerm , "FulltextTerm" : fulltextTerm } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.AutocompleteInTeam" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
2018-09-11 22:45:31 +02:00
}
2019-06-17 14:32:37 -04:00
}
2018-09-11 22:45:31 +02:00
2019-06-17 14:32:37 -04:00
sort . Slice ( channels , func ( a , b int ) bool {
return strings . ToLower ( channels [ a ] . DisplayName ) < strings . ToLower ( channels [ b ] . DisplayName )
2018-09-11 22:45:31 +02:00
} )
2019-06-17 14:32:37 -04:00
return & channels , nil
2018-09-11 22:45:31 +02:00
}
func ( s SqlChannelStore ) AutocompleteInTeamForSearch ( teamId string , userId string , term string , includeDeleted bool ) store . StoreChannel {
return store . Do ( func ( result * store . StoreResult ) {
deleteFilter := "AND DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
}
queryFormat := `
SELECT
C . *
FROM
Channels AS C
JOIN
ChannelMembers AS CM ON CM . ChannelId = C . Id
WHERE
2018-09-27 16:15:41 +02:00
( C . TeamId = : TeamId OR ( C . TeamId = ' ' AND C . Type = 'G' ) )
2018-09-11 22:45:31 +02:00
AND CM . UserId = : UserId
` + deleteFilter + `
% v
LIMIT 50 `
var channels model . ChannelList
2018-09-27 16:15:41 +02:00
if likeClause , likeTerm := s . buildLIKEClause ( term , "Name, DisplayName, Purpose" ) ; likeClause == "" {
2018-09-11 22:45:31 +02:00
if _ , err := s . GetReplica ( ) . Select ( & channels , fmt . Sprintf ( queryFormat , "" ) , map [ string ] interface { } { "TeamId" : teamId , "UserId" : userId } ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.AutocompleteInTeamForSearch" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
}
} else {
// Using a UNION results in index_merge and fulltext queries and is much faster than the ref
// query you would get using an OR of the LIKE and full-text clauses.
2018-09-27 16:15:41 +02:00
fulltextClause , fulltextTerm := s . buildFulltextClause ( term , "Name, DisplayName, Purpose" )
2018-09-11 22:45:31 +02:00
likeQuery := fmt . Sprintf ( queryFormat , "AND " + likeClause )
fulltextQuery := fmt . Sprintf ( queryFormat , "AND " + fulltextClause )
query := fmt . Sprintf ( "(%v) UNION (%v) LIMIT 50" , likeQuery , fulltextQuery )
if _ , err := s . GetReplica ( ) . Select ( & channels , query , map [ string ] interface { } { "TeamId" : teamId , "UserId" : userId , "LikeTerm" : likeTerm , "FulltextTerm" : fulltextTerm } ) ; err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.AutocompleteInTeamForSearch" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
2018-01-31 08:26:40 -06:00
}
}
2018-09-27 16:15:41 +02:00
directChannels , err := s . autocompleteInTeamForSearchDirectMessages ( userId , term )
if err != nil {
result . Err = err
return
}
channels = append ( channels , directChannels ... )
2018-01-31 08:26:40 -06:00
sort . Slice ( channels , func ( a , b int ) bool {
2018-01-31 13:57:08 -06:00
return strings . ToLower ( channels [ a ] . DisplayName ) < strings . ToLower ( channels [ b ] . DisplayName )
2018-01-31 08:26:40 -06:00
} )
result . Data = & channels
} )
}
2018-09-27 16:15:41 +02:00
func ( s SqlChannelStore ) autocompleteInTeamForSearchDirectMessages ( userId string , term string ) ( [ ] * model . Channel , * model . AppError ) {
queryFormat := `
SELECT
C . * ,
OtherUsers . Username as DisplayName
FROM
Channels AS C
JOIN
ChannelMembers AS CM ON CM . ChannelId = C . Id
INNER JOIN (
SELECT
ICM . ChannelId AS ChannelId , IU . Username AS Username
FROM
Users as IU
JOIN
ChannelMembers AS ICM ON ICM . UserId = IU . Id
WHERE
IU . Id != : UserId
% v
) AS OtherUsers ON OtherUsers . ChannelId = C . Id
WHERE
C . Type = 'D'
AND CM . UserId = : UserId
LIMIT 50 `
var channels model . ChannelList
if likeClause , likeTerm := s . buildLIKEClause ( term , "IU.Username, IU.Nickname" ) ; likeClause == "" {
if _ , err := s . GetReplica ( ) . Select ( & channels , fmt . Sprintf ( queryFormat , "" ) , map [ string ] interface { } { "UserId" : userId } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.AutocompleteInTeamForSearch" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
}
} else {
query := fmt . Sprintf ( queryFormat , "AND " + likeClause )
if _ , err := s . GetReplica ( ) . Select ( & channels , query , map [ string ] interface { } { "UserId" : userId , "LikeTerm" : likeTerm } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.AutocompleteInTeamForSearch" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
}
}
return channels , nil
}
2019-06-17 14:32:37 -04:00
func ( s SqlChannelStore ) SearchInTeam ( teamId string , term string , includeDeleted bool ) ( * model . ChannelList , * model . AppError ) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
}
2018-10-25 13:25:27 -04:00
2019-06-17 14:32:37 -04:00
return s . performSearch ( `
SELECT
Channels . *
FROM
Channels
JOIN
PublicChannels c ON ( c . Id = Channels . Id )
WHERE
c . TeamId = : TeamId
` +deleteFilter+ `
SEARCH_CLAUSE
ORDER BY c . DisplayName
LIMIT 100
2018-10-25 13:25:27 -04:00
` , term , map [ string ] interface { } {
2019-06-17 14:32:37 -04:00
"TeamId" : teamId ,
2017-10-06 08:12:10 -07:00
} )
2016-11-24 09:35:09 -05:00
}
2019-05-24 11:28:42 -04:00
func ( s SqlChannelStore ) SearchAllChannels ( term string , opts store . ChannelSearchOpts ) store . StoreChannel {
2019-01-10 15:17:31 -05:00
return store . Do ( func ( result * store . StoreResult ) {
2019-05-24 11:28:42 -04:00
query := s . getQueryBuilder ( ) .
Select ( "c.*, t.DisplayName AS TeamDisplayName, t.Name AS TeamName, t.UpdateAt as TeamUpdateAt" ) .
From ( "Channels AS c" ) .
Join ( "Teams AS t ON t.Id = c.TeamId" ) .
Where ( sq . Eq { "c.Type" : [ ] string { model . CHANNEL_PRIVATE , model . CHANNEL_OPEN } } ) .
OrderBy ( "c.DisplayName, t.DisplayName" ) .
Limit ( uint64 ( 100 ) )
if ! opts . IncludeDeleted {
query = query . Where ( sq . Eq { "c.DeleteAt" : int ( 0 ) } )
2019-01-10 15:17:31 -05:00
}
likeClause , likeTerm := s . buildLIKEClause ( term , "c.Name, c.DisplayName, c.Purpose" )
2019-05-24 11:28:42 -04:00
if len ( likeTerm ) > 0 {
likeClause = strings . ReplaceAll ( likeClause , ":LikeTerm" , "'" + likeTerm + "'" )
2019-01-10 15:17:31 -05:00
fulltextClause , fulltextTerm := s . buildFulltextClause ( term , "c.Name, c.DisplayName, c.Purpose" )
2019-05-24 11:28:42 -04:00
fulltextClause = strings . ReplaceAll ( fulltextClause , ":FulltextTerm" , "'" + fulltextTerm + "'" )
query = query . Where ( "(" + likeClause + " OR " + fulltextClause + ")" )
}
if len ( opts . ExcludeChannelNames ) > 0 {
query = query . Where ( fmt . Sprintf ( "c.Name NOT IN ('%s')" , strings . Join ( opts . ExcludeChannelNames , "', '" ) ) )
}
if len ( opts . NotAssociatedToGroup ) > 0 {
query = query . Where ( "c.Id NOT IN (SELECT ChannelId FROM GroupChannels WHERE GroupChannels.GroupId = ? AND GroupChannels.DeleteAt = 0)" , opts . NotAssociatedToGroup )
}
queryString , args , err := query . ToSql ( )
if err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.SearchAllChannels" , "store.sql.build_query.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
return
2019-01-10 15:17:31 -05:00
}
var channels model . ChannelListWithTeamData
2019-05-24 11:28:42 -04:00
if _ , err := s . GetReplica ( ) . Select ( & channels , queryString , args ... ) ; err != nil {
2019-01-10 15:17:31 -05:00
result . Err = model . NewAppError ( "SqlChannelStore.Search" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
}
result . Data = & channels
} )
}
2019-06-17 14:32:37 -04:00
func ( s SqlChannelStore ) SearchMore ( userId string , teamId string , term string ) ( * model . ChannelList , * model . AppError ) {
return s . performSearch ( `
SELECT
Channels . *
FROM
Channels
JOIN
PublicChannels c ON ( c . Id = Channels . Id )
WHERE
c . TeamId = : TeamId
AND c . DeleteAt = 0
AND c . Id NOT IN (
2016-11-24 09:35:09 -05:00
SELECT
2019-06-17 14:32:37 -04:00
c . Id
2016-11-24 09:35:09 -05:00
FROM
2019-06-17 14:32:37 -04:00
PublicChannels c
2018-10-25 13:25:27 -04:00
JOIN
2019-06-17 14:32:37 -04:00
ChannelMembers cm ON ( cm . ChannelId = c . Id )
2016-11-24 09:35:09 -05:00
WHERE
2019-06-17 14:32:37 -04:00
c . TeamId = : TeamId
AND cm . UserId = : UserId
2018-10-25 13:25:27 -04:00
AND c . DeleteAt = 0
2019-06-17 14:32:37 -04:00
)
SEARCH_CLAUSE
ORDER BY c . DisplayName
LIMIT 100
2018-10-25 13:25:27 -04:00
` , term , map [ string ] interface { } {
2019-06-17 14:32:37 -04:00
"TeamId" : teamId ,
"UserId" : userId ,
2017-10-06 08:12:10 -07:00
} )
2016-11-24 09:35:09 -05:00
}
2018-09-27 16:15:41 +02:00
func ( s SqlChannelStore ) buildLIKEClause ( term string , searchColumns string ) ( likeClause , likeTerm string ) {
2018-01-31 08:26:40 -06:00
likeTerm = term
2018-01-05 15:59:10 +00:00
2017-10-11 17:20:27 +08:00
// These chars must be removed from the like query.
2018-01-05 15:59:10 +00:00
for _ , c := range ignoreLikeSearchChar {
likeTerm = strings . Replace ( likeTerm , c , "" , - 1 )
2017-10-11 17:20:27 +08:00
}
// These chars must be escaped in the like query.
2018-01-05 15:59:10 +00:00
for _ , c := range escapeLikeSearchChar {
likeTerm = strings . Replace ( likeTerm , c , "*" + c , - 1 )
2016-11-24 09:35:09 -05:00
}
2018-01-31 08:26:40 -06:00
if likeTerm == "" {
return
}
// Prepare the LIKE portion of the query.
var searchFields [ ] string
for _ , field := range strings . Split ( searchColumns , ", " ) {
if s . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
searchFields = append ( searchFields , fmt . Sprintf ( "lower(%s) LIKE lower(%s) escape '*'" , field , ":LikeTerm" ) )
} else {
searchFields = append ( searchFields , fmt . Sprintf ( "%s LIKE %s escape '*'" , field , ":LikeTerm" ) )
}
}
likeClause = fmt . Sprintf ( "(%s)" , strings . Join ( searchFields , " OR " ) )
likeTerm += "%"
return
}
2018-09-27 16:15:41 +02:00
func ( s SqlChannelStore ) buildFulltextClause ( term string , searchColumns string ) ( fulltextClause , fulltextTerm string ) {
2018-01-31 08:26:40 -06:00
// Copy the terms as we will need to prepare them differently for each search type.
fulltextTerm = term
2018-01-05 15:59:10 +00:00
// These chars must be treated as spaces in the fulltext query.
for _ , c := range spaceFulltextSearchChar {
fulltextTerm = strings . Replace ( fulltextTerm , c , " " , - 1 )
}
2018-01-31 08:26:40 -06:00
// Prepare the FULLTEXT portion of the query.
if s . DriverName ( ) == model . DATABASE_DRIVER_POSTGRES {
2018-06-29 18:13:13 -04:00
fulltextTerm = strings . Replace ( fulltextTerm , "|" , "" , - 1 )
2018-01-31 08:26:40 -06:00
splitTerm := strings . Fields ( fulltextTerm )
for i , t := range strings . Fields ( fulltextTerm ) {
if i == len ( splitTerm ) - 1 {
splitTerm [ i ] = t + ":*"
2018-01-05 15:59:10 +00:00
} else {
2018-01-31 08:26:40 -06:00
splitTerm [ i ] = t + ":* &"
2018-01-05 15:59:10 +00:00
}
}
2018-01-31 08:26:40 -06:00
fulltextTerm = strings . Join ( splitTerm , " " )
2018-01-05 15:59:10 +00:00
2018-01-31 08:26:40 -06:00
fulltextClause = fmt . Sprintf ( "((%s) @@ to_tsquery(:FulltextTerm))" , convertMySQLFullTextColumnsToPostgres ( searchColumns ) )
} else if s . DriverName ( ) == model . DATABASE_DRIVER_MYSQL {
splitTerm := strings . Fields ( fulltextTerm )
for i , t := range strings . Fields ( fulltextTerm ) {
splitTerm [ i ] = "+" + t + "*"
}
2018-01-05 15:59:10 +00:00
2018-01-31 08:26:40 -06:00
fulltextTerm = strings . Join ( splitTerm , " " )
2018-01-05 15:59:10 +00:00
2018-01-31 08:26:40 -06:00
fulltextClause = fmt . Sprintf ( "MATCH(%s) AGAINST (:FulltextTerm IN BOOLEAN MODE)" , searchColumns )
2016-11-24 09:35:09 -05:00
}
2018-01-31 08:26:40 -06:00
return
}
2019-06-17 14:32:37 -04:00
func ( s SqlChannelStore ) performSearch ( searchQuery string , term string , parameters map [ string ] interface { } ) ( * model . ChannelList , * model . AppError ) {
2018-10-25 13:25:27 -04:00
likeClause , likeTerm := s . buildLIKEClause ( term , "c.Name, c.DisplayName, c.Purpose" )
2018-01-31 08:26:40 -06:00
if likeTerm == "" {
// If the likeTerm is empty after preparing, then don't bother searching.
searchQuery = strings . Replace ( searchQuery , "SEARCH_CLAUSE" , "" , 1 )
} else {
parameters [ "LikeTerm" ] = likeTerm
2018-10-25 13:25:27 -04:00
fulltextClause , fulltextTerm := s . buildFulltextClause ( term , "c.Name, c.DisplayName, c.Purpose" )
2018-01-31 08:26:40 -06:00
parameters [ "FulltextTerm" ] = fulltextTerm
searchQuery = strings . Replace ( searchQuery , "SEARCH_CLAUSE" , "AND (" + likeClause + " OR " + fulltextClause + ")" , 1 )
}
2018-01-05 15:59:10 +00:00
2016-11-24 09:35:09 -05:00
var channels model . ChannelList
if _ , err := s . GetReplica ( ) . Select ( & channels , searchQuery , parameters ) ; err != nil {
2019-06-17 14:32:37 -04:00
return nil , model . NewAppError ( "SqlChannelStore.Search" , "store.sql_channel.search.app_error" , nil , "term=" + term + ", " + ", " + err . Error ( ) , http . StatusInternalServerError )
2016-11-24 09:35:09 -05:00
}
2019-06-17 14:32:37 -04:00
return & channels , nil
2016-11-24 09:35:09 -05:00
}
2016-12-22 18:21:05 +00:00
2019-06-19 20:20:19 +04:00
func ( s SqlChannelStore ) GetMembersByIds ( channelId string , userIds [ ] string ) ( * model . ChannelMembers , * model . AppError ) {
var dbMembers channelMemberWithSchemeRolesList
props := make ( map [ string ] interface { } )
idQuery := ""
2016-12-22 18:21:05 +00:00
2019-06-19 20:20:19 +04:00
for index , userId := range userIds {
if len ( idQuery ) > 0 {
idQuery += ", "
2016-12-22 18:21:05 +00:00
}
2019-06-19 20:20:19 +04:00
props [ "userId" + strconv . Itoa ( index ) ] = userId
idQuery += ":userId" + strconv . Itoa ( index )
}
2016-12-22 18:21:05 +00:00
2019-06-19 20:20:19 +04:00
props [ "ChannelId" ] = channelId
2018-07-20 12:39:48 +02:00
2019-06-19 20:20:19 +04:00
if _ , err := s . GetReplica ( ) . Select ( & dbMembers , CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY + "WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId IN (" + idQuery + ")" , props ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetMembersByIds" , "store.sql_channel.get_members_by_ids.app_error" , nil , "channelId=" + channelId + " " + err . Error ( ) , http . StatusInternalServerError )
}
return dbMembers . ToModel ( ) , nil
2018-04-20 19:49:13 +01:00
}
2017-02-24 17:33:59 +00:00
2018-04-20 19:49:13 +01:00
func ( s SqlChannelStore ) GetChannelsByScheme ( schemeId string , offset int , limit int ) store . StoreChannel {
return store . Do ( func ( result * store . StoreResult ) {
2018-05-03 14:00:26 +01:00
var channels model . ChannelList
2018-04-20 19:49:13 +01:00
_ , err := s . GetReplica ( ) . Select ( & channels , "SELECT * FROM Channels WHERE SchemeId = :SchemeId ORDER BY DisplayName LIMIT :Limit OFFSET :Offset" , map [ string ] interface { } { "SchemeId" : schemeId , "Offset" : offset , "Limit" : limit } )
if err != nil {
result . Err = model . NewAppError ( "SqlChannelStore.GetChannelsByScheme" , "store.sql_channel.get_by_scheme.app_error" , nil , "schemeId=" + schemeId + " " + err . Error ( ) , http . StatusInternalServerError )
2018-07-20 12:39:48 +02:00
return
2016-12-22 18:21:05 +00:00
}
2018-07-20 12:39:48 +02:00
result . Data = channels
2017-10-06 08:12:10 -07:00
} )
2016-12-22 18:21:05 +00:00
}
2018-05-14 15:59:04 +01:00
// This function does the Advanced Permissions Phase 2 migration for ChannelMember objects. It performs the migration
// in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid
// causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function
// *after* the new Schemes functionality has been used on an installation will have unintended consequences.
2019-06-20 05:37:06 -07:00
func ( s SqlChannelStore ) MigrateChannelMembers ( fromChannelId string , fromUserId string ) ( map [ string ] string , * model . AppError ) {
var transaction * gorp . Transaction
var err error
2018-05-14 15:59:04 +01:00
2019-06-20 05:37:06 -07:00
if transaction , err = s . GetMaster ( ) . Begin ( ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.MigrateChannelMembers" , "store.sql_channel.migrate_channel_members.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
defer finalizeTransaction ( transaction )
2018-05-14 15:59:04 +01:00
2019-06-20 05:37:06 -07:00
var channelMembers [ ] channelMember
if _ , err := transaction . Select ( & channelMembers , "SELECT * from ChannelMembers WHERE (ChannelId, UserId) > (:FromChannelId, :FromUserId) ORDER BY ChannelId, UserId LIMIT 100" , map [ string ] interface { } { "FromChannelId" : fromChannelId , "FromUserId" : fromUserId } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.MigrateChannelMembers" , "store.sql_channel.migrate_channel_members.select.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2018-05-14 15:59:04 +01:00
2019-06-20 05:37:06 -07:00
if len ( channelMembers ) == 0 {
// No more channel members in query result means that the migration has finished.
return nil , nil
}
2018-05-14 15:59:04 +01:00
2019-06-20 05:37:06 -07:00
for _ , member := range channelMembers {
roles := strings . Fields ( member . Roles )
var newRoles [ ] string
if ! member . SchemeAdmin . Valid {
member . SchemeAdmin = sql . NullBool { Bool : false , Valid : true }
}
if ! member . SchemeUser . Valid {
member . SchemeUser = sql . NullBool { Bool : false , Valid : true }
}
if ! member . SchemeGuest . Valid {
member . SchemeGuest = sql . NullBool { Bool : false , Valid : true }
}
for _ , role := range roles {
if role == model . CHANNEL_ADMIN_ROLE_ID {
member . SchemeAdmin = sql . NullBool { Bool : true , Valid : true }
} else if role == model . CHANNEL_USER_ROLE_ID {
member . SchemeUser = sql . NullBool { Bool : true , Valid : true }
} else if role == model . CHANNEL_GUEST_ROLE_ID {
member . SchemeGuest = sql . NullBool { Bool : true , Valid : true }
} else {
newRoles = append ( newRoles , role )
2018-05-14 15:59:04 +01:00
}
}
2019-06-20 05:37:06 -07:00
member . Roles = strings . Join ( newRoles , " " )
2018-05-14 15:59:04 +01:00
2019-06-20 05:37:06 -07:00
if _ , err := transaction . Update ( & member ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.MigrateChannelMembers" , "store.sql_channel.migrate_channel_members.update.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2018-05-14 15:59:04 +01:00
}
2019-06-20 05:37:06 -07:00
}
if err := transaction . Commit ( ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.MigrateChannelMembers" , "store.sql_channel.migrate_channel_members.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
data := make ( map [ string ] string )
data [ "ChannelId" ] = channelMembers [ len ( channelMembers ) - 1 ] . ChannelId
data [ "UserId" ] = channelMembers [ len ( channelMembers ) - 1 ] . UserId
return data , nil
2018-05-14 15:59:04 +01:00
}
2018-05-17 16:28:14 +01:00
2019-06-20 16:52:24 -04:00
func ( s SqlChannelStore ) ResetAllChannelSchemes ( ) * model . AppError {
transaction , err := s . GetMaster ( ) . Begin ( )
if err != nil {
return model . NewAppError ( "SqlChannelStore.ResetAllChannelSchemes" , "store.sql_channel.reset_all_channel_schemes.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
defer finalizeTransaction ( transaction )
2018-09-17 16:25:19 -04:00
2019-06-20 16:52:24 -04:00
resetErr := s . resetAllChannelSchemesT ( transaction )
if resetErr != nil {
return resetErr
}
2018-09-17 16:25:19 -04:00
2019-06-20 16:52:24 -04:00
if err := transaction . Commit ( ) ; err != nil {
return model . NewAppError ( "SqlChannelStore.ResetAllChannelSchemes" , "store.sql_channel.reset_all_channel_schemes.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2018-06-25 14:34:59 +01:00
2019-06-20 16:52:24 -04:00
return nil
}
2018-09-17 16:25:19 -04:00
2019-06-20 16:52:24 -04:00
func ( s SqlChannelStore ) resetAllChannelSchemesT ( transaction * gorp . Transaction ) * model . AppError {
2018-09-17 16:25:19 -04:00
if _ , err := transaction . Exec ( "UPDATE Channels SET SchemeId=''" ) ; err != nil {
2019-06-20 16:52:24 -04:00
return model . NewAppError ( "SqlChannelStore.ResetAllChannelSchemes" , "store.sql_channel.reset_all_channel_schemes.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2018-09-17 16:25:19 -04:00
}
2019-06-20 16:52:24 -04:00
return nil
2018-09-17 16:25:19 -04:00
}
2019-06-19 05:10:58 -04:00
func ( s SqlChannelStore ) ClearAllCustomRoleAssignments ( ) * model . AppError {
builtInRoles := model . MakeDefaultRoles ( )
lastUserId := strings . Repeat ( "0" , 26 )
lastChannelId := strings . Repeat ( "0" , 26 )
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
for {
var transaction * gorp . Transaction
var err error
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
if transaction , err = s . GetMaster ( ) . Begin ( ) ; err != nil {
return model . NewAppError ( "SqlChannelStore.ClearAllCustomRoleAssignments" , "store.sql_channel.clear_all_custom_role_assignments.open_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
var channelMembers [ ] * channelMember
if _ , err := transaction . Select ( & channelMembers , "SELECT * from ChannelMembers WHERE (ChannelId, UserId) > (:ChannelId, :UserId) ORDER BY ChannelId, UserId LIMIT 1000" , map [ string ] interface { } { "ChannelId" : lastChannelId , "UserId" : lastUserId } ) ; err != nil {
finalizeTransaction ( transaction )
return model . NewAppError ( "SqlChannelStore.ClearAllCustomRoleAssignments" , "store.sql_channel.clear_all_custom_role_assignments.select.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
if len ( channelMembers ) == 0 {
finalizeTransaction ( transaction )
break
}
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
for _ , member := range channelMembers {
lastUserId = member . UserId
lastChannelId = member . ChannelId
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
var newRoles [ ] string
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
for _ , role := range strings . Fields ( member . Roles ) {
for name := range builtInRoles {
if name == role {
newRoles = append ( newRoles , role )
break
2018-06-25 14:34:59 +01:00
}
}
2019-06-19 05:10:58 -04:00
}
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
newRolesString := strings . Join ( newRoles , " " )
if newRolesString != member . Roles {
if _ , err := transaction . Exec ( "UPDATE ChannelMembers SET Roles = :Roles WHERE UserId = :UserId AND ChannelId = :ChannelId" , map [ string ] interface { } { "Roles" : newRolesString , "ChannelId" : member . ChannelId , "UserId" : member . UserId } ) ; err != nil {
finalizeTransaction ( transaction )
return model . NewAppError ( "SqlChannelStore.ClearAllCustomRoleAssignments" , "store.sql_channel.clear_all_custom_role_assignments.update.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2018-06-25 14:34:59 +01:00
}
}
2019-06-19 05:10:58 -04:00
}
2018-06-25 14:34:59 +01:00
2019-06-19 05:10:58 -04:00
if err := transaction . Commit ( ) ; err != nil {
finalizeTransaction ( transaction )
return model . NewAppError ( "SqlChannelStore.ClearAllCustomRoleAssignments" , "store.sql_channel.clear_all_custom_role_assignments.commit_transaction.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
2018-06-25 14:34:59 +01:00
}
2019-06-19 05:10:58 -04:00
}
return nil
2018-06-25 14:34:59 +01:00
}
2018-08-24 09:53:44 +02:00
2019-06-19 07:31:51 -04:00
func ( s SqlChannelStore ) GetAllChannelsForExportAfter ( limit int , afterId string ) ( [ ] * model . ChannelForExport , * model . AppError ) {
var channels [ ] * model . ChannelForExport
if _ , err := s . GetReplica ( ) . Select ( & channels , `
SELECT
Channels . * ,
Teams . Name as TeamName ,
Schemes . Name as SchemeName
FROM Channels
INNER JOIN
Teams ON Channels . TeamId = Teams . Id
LEFT JOIN
Schemes ON Channels . SchemeId = Schemes . Id
WHERE
Channels . Id > : AfterId
AND Channels . Type IN ( 'O' , 'P' )
ORDER BY
Id
LIMIT : Limit ` ,
map [ string ] interface { } { "AfterId" : afterId , "Limit" : limit } ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllChannelsForExportAfter" , "store.sql_channel.get_all.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2018-09-17 15:51:26 +01:00
2019-06-19 07:31:51 -04:00
return channels , nil
2018-09-17 15:51:26 +01:00
}
2019-06-18 15:08:36 -04:00
func ( s SqlChannelStore ) GetChannelMembersForExport ( userId string , teamId string ) ( [ ] * model . ChannelMemberForExport , * model . AppError ) {
var members [ ] * model . ChannelMemberForExport
_ , err := s . GetReplica ( ) . Select ( & members , `
SELECT
ChannelMembers . ChannelId ,
ChannelMembers . UserId ,
ChannelMembers . Roles ,
ChannelMembers . LastViewedAt ,
ChannelMembers . MsgCount ,
ChannelMembers . MentionCount ,
ChannelMembers . NotifyProps ,
ChannelMembers . LastUpdateAt ,
ChannelMembers . SchemeUser ,
ChannelMembers . SchemeAdmin ,
( ChannelMembers . SchemeGuest IS NOT NULL AND ChannelMembers . SchemeGuest ) as SchemeGuest ,
Channels . Name as ChannelName
FROM
ChannelMembers
INNER JOIN
Channels ON ChannelMembers . ChannelId = Channels . Id
WHERE
ChannelMembers . UserId = : UserId
AND Channels . TeamId = : TeamId
AND Channels . DeleteAt = 0 ` ,
map [ string ] interface { } { "TeamId" : teamId , "UserId" : userId } )
2018-09-17 15:51:26 +01:00
2019-06-18 15:08:36 -04:00
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetChannelMembersForExport" , "store.sql_channel.get_members.app_error" , nil , "teamId=" + teamId + ", userId=" + userId + ", err=" + err . Error ( ) , http . StatusInternalServerError )
}
2018-09-17 15:51:26 +01:00
2019-06-18 15:08:36 -04:00
return members , nil
2018-09-17 15:51:26 +01:00
}
2019-03-15 12:28:43 -03:00
2019-06-20 11:01:49 -04:00
func ( s SqlChannelStore ) GetAllDirectChannelsForExportAfter ( limit int , afterId string ) ( [ ] * model . DirectChannelForExport , * model . AppError ) {
var directChannelsForExport [ ] * model . DirectChannelForExport
query := s . getQueryBuilder ( ) .
Select ( "Channels.*" ) .
From ( "Channels" ) .
Where ( sq . And {
sq . Gt { "Channels.Id" : afterId } ,
sq . Eq { "Channels.DeleteAt" : int ( 0 ) } ,
sq . Eq { "Channels.Type" : [ ] string { "D" , "G" } } ,
} ) .
OrderBy ( "Channels.Id" ) .
Limit ( uint64 ( limit ) )
2019-03-15 12:28:43 -03:00
2019-06-20 11:01:49 -04:00
queryString , args , err := query . ToSql ( )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllDirectChannelsForExportAfter" , "store.sql_channel.get_all_direct.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2019-03-15 12:28:43 -03:00
2019-06-20 11:01:49 -04:00
if _ , err = s . GetReplica ( ) . Select ( & directChannelsForExport , queryString , args ... ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllDirectChannelsForExportAfter" , "store.sql_channel.get_all_direct.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2019-03-15 12:28:43 -03:00
2019-06-20 11:01:49 -04:00
var channelIds [ ] string
for _ , channel := range directChannelsForExport {
channelIds = append ( channelIds , channel . Id )
}
query = s . getQueryBuilder ( ) .
Select ( "u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest" ) .
From ( "ChannelMembers cm" ) .
Join ( "Users u ON ( u.Id = cm.UserId )" ) .
Where ( sq . And {
sq . Eq { "cm.ChannelId" : channelIds } ,
sq . Eq { "u.DeleteAt" : int ( 0 ) } ,
} )
2019-03-15 12:28:43 -03:00
2019-06-20 11:01:49 -04:00
queryString , args , err = query . ToSql ( )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllDirectChannelsForExportAfter" , "store.sql_channel.get_all_direct.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2019-03-15 12:28:43 -03:00
2019-06-20 11:01:49 -04:00
var channelMembers [ ] * model . ChannelMemberForExport
if _ , err := s . GetReplica ( ) . Select ( & channelMembers , queryString , args ... ) ; err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetAllDirectChannelsForExportAfter" , "store.sql_channel.get_all_direct.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
2019-03-15 12:28:43 -03:00
2019-06-20 11:01:49 -04:00
// Populate each channel with its members
dmChannelsMap := make ( map [ string ] * model . DirectChannelForExport )
for _ , channel := range directChannelsForExport {
channel . Members = & [ ] string { }
dmChannelsMap [ channel . Id ] = channel
}
for _ , member := range channelMembers {
members := dmChannelsMap [ member . ChannelId ] . Members
* members = append ( * members , member . Username )
}
return directChannelsForExport , nil
2019-03-15 12:28:43 -03:00
}
2019-03-19 12:42:08 +00:00
2019-06-18 18:55:03 +02:00
func ( s SqlChannelStore ) GetChannelsBatchForIndexing ( startTime , endTime int64 , limit int ) ( [ ] * model . Channel , * model . AppError ) {
query :=
` SELECT
*
FROM
Channels
WHERE
Type = 'O'
AND
CreateAt >= : StartTime
AND
CreateAt < : EndTime
ORDER BY
CreateAt
LIMIT
: NumChannels `
2019-03-19 12:42:08 +00:00
2019-06-18 18:55:03 +02:00
var channels [ ] * model . Channel
_ , err := s . GetSearchReplica ( ) . Select ( & channels , query , map [ string ] interface { } { "StartTime" : startTime , "EndTime" : endTime , "NumChannels" : limit } )
if err != nil {
return nil , model . NewAppError ( "SqlChannelStore.GetChannelsBatchForIndexing" , "store.sql_channel.get_channels_batch_for_indexing.get.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return channels , nil
2019-03-19 12:42:08 +00:00
}
2019-04-29 16:56:56 +02:00
2019-06-18 12:02:09 -07:00
func ( s SqlChannelStore ) UserBelongsToChannels ( userId string , channelIds [ ] string ) ( bool , * model . AppError ) {
query := s . getQueryBuilder ( ) .
Select ( "Count(*)" ) .
From ( "ChannelMembers" ) .
Where ( sq . And {
sq . Eq { "UserId" : userId } ,
sq . Eq { "ChannelId" : channelIds } ,
} )
2019-04-29 16:56:56 +02:00
2019-06-18 12:02:09 -07:00
queryString , args , err := query . ToSql ( )
if err != nil {
return false , model . NewAppError ( "SqlChannelStore.UserBelongsToChannels" , "store.sql_channel.user_belongs_to_channels.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
c , err := s . GetReplica ( ) . SelectInt ( queryString , args ... )
if err != nil {
return false , model . NewAppError ( "SqlChannelStore.UserBelongsToChannels" , "store.sql_channel.user_belongs_to_channels.app_error" , nil , err . Error ( ) , http . StatusInternalServerError )
}
return c > 0 , nil
2019-04-29 16:56:56 +02:00
}