github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/store/sqlstore/bot_store.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "database/sql" 8 "fmt" 9 "strings" 10 11 "github.com/pkg/errors" 12 13 "github.com/mattermost/mattermost-server/v5/einterfaces" 14 "github.com/mattermost/mattermost-server/v5/model" 15 "github.com/mattermost/mattermost-server/v5/store" 16 ) 17 18 // bot is a subset of the model.Bot type, omitting the model.User fields. 19 type bot struct { 20 UserId string `json:"user_id"` 21 Description string `json:"description"` 22 OwnerId string `json:"owner_id"` 23 LastIconUpdate int64 `json:"last_icon_update"` 24 CreateAt int64 `json:"create_at"` 25 UpdateAt int64 `json:"update_at"` 26 DeleteAt int64 `json:"delete_at"` 27 } 28 29 func botFromModel(b *model.Bot) *bot { 30 return &bot{ 31 UserId: b.UserId, 32 Description: b.Description, 33 OwnerId: b.OwnerId, 34 LastIconUpdate: b.LastIconUpdate, 35 CreateAt: b.CreateAt, 36 UpdateAt: b.UpdateAt, 37 DeleteAt: b.DeleteAt, 38 } 39 } 40 41 // SqlBotStore is a store for managing bots in the database. 42 // Bots are otherwise normal users with extra metadata record in the Bots table. The primary key 43 // for a bot matches the primary key value for corresponding User record. 44 type SqlBotStore struct { 45 *SqlStore 46 metrics einterfaces.MetricsInterface 47 } 48 49 // newSqlBotStore creates an instance of SqlBotStore, registering the table schema in question. 50 func newSqlBotStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) store.BotStore { 51 us := &SqlBotStore{ 52 SqlStore: sqlStore, 53 metrics: metrics, 54 } 55 56 for _, db := range sqlStore.GetAllConns() { 57 table := db.AddTableWithName(bot{}, "Bots").SetKeys(false, "UserId") 58 table.ColMap("UserId").SetMaxSize(26) 59 table.ColMap("Description").SetMaxSize(1024) 60 table.ColMap("OwnerId").SetMaxSize(model.BOT_CREATOR_ID_MAX_RUNES) 61 } 62 63 return us 64 } 65 66 func (us SqlBotStore) createIndexesIfNotExists() { 67 } 68 69 // Get fetches the given bot in the database. 70 func (us SqlBotStore) Get(botUserId string, includeDeleted bool) (*model.Bot, error) { 71 var excludeDeletedSql = "AND b.DeleteAt = 0" 72 if includeDeleted { 73 excludeDeletedSql = "" 74 } 75 76 query := ` 77 SELECT 78 b.UserId, 79 u.Username, 80 u.FirstName AS DisplayName, 81 b.Description, 82 b.OwnerId, 83 COALESCE(b.LastIconUpdate, 0) AS LastIconUpdate, 84 b.CreateAt, 85 b.UpdateAt, 86 b.DeleteAt 87 FROM 88 Bots b 89 JOIN 90 Users u ON (u.Id = b.UserId) 91 WHERE 92 b.UserId = :user_id 93 ` + excludeDeletedSql + ` 94 ` 95 96 var bot *model.Bot 97 if err := us.GetReplica().SelectOne(&bot, query, map[string]interface{}{"user_id": botUserId}); err == sql.ErrNoRows { 98 return nil, store.NewErrNotFound("Bot", botUserId) 99 } else if err != nil { 100 return nil, errors.Wrapf(err, "selectone: user_id=%s", botUserId) 101 } 102 103 return bot, nil 104 } 105 106 // GetAll fetches from all bots in the database. 107 func (us SqlBotStore) GetAll(options *model.BotGetOptions) ([]*model.Bot, error) { 108 params := map[string]interface{}{ 109 "offset": options.Page * options.PerPage, 110 "limit": options.PerPage, 111 } 112 113 var conditions []string 114 var conditionsSql string 115 var additionalJoin string 116 117 if !options.IncludeDeleted { 118 conditions = append(conditions, "b.DeleteAt = 0") 119 } 120 if options.OwnerId != "" { 121 conditions = append(conditions, "b.OwnerId = :creator_id") 122 params["creator_id"] = options.OwnerId 123 } 124 if options.OnlyOrphaned { 125 additionalJoin = "JOIN Users o ON (o.Id = b.OwnerId)" 126 conditions = append(conditions, "o.DeleteAt != 0") 127 } 128 129 if len(conditions) > 0 { 130 conditionsSql = "WHERE " + strings.Join(conditions, " AND ") 131 } 132 133 sql := ` 134 SELECT 135 b.UserId, 136 u.Username, 137 u.FirstName AS DisplayName, 138 b.Description, 139 b.OwnerId, 140 COALESCE(b.LastIconUpdate, 0) AS LastIconUpdate, 141 b.CreateAt, 142 b.UpdateAt, 143 b.DeleteAt 144 FROM 145 Bots b 146 JOIN 147 Users u ON (u.Id = b.UserId) 148 ` + additionalJoin + ` 149 ` + conditionsSql + ` 150 ORDER BY 151 b.CreateAt ASC, 152 u.Username ASC 153 LIMIT 154 :limit 155 OFFSET 156 :offset 157 ` 158 159 var bots []*model.Bot 160 if _, err := us.GetReplica().Select(&bots, sql, params); err != nil { 161 return nil, errors.Wrap(err, "select") 162 } 163 164 return bots, nil 165 } 166 167 // Save persists a new bot to the database. 168 // It assumes the corresponding user was saved via the user store. 169 func (us SqlBotStore) Save(bot *model.Bot) (*model.Bot, error) { 170 bot = bot.Clone() 171 bot.PreSave() 172 173 if err := bot.IsValid(); err != nil { // TODO: change to return error in v6. 174 return nil, err 175 } 176 177 if err := us.GetMaster().Insert(botFromModel(bot)); err != nil { 178 return nil, errors.Wrapf(err, "insert: user_id=%s", bot.UserId) 179 } 180 181 return bot, nil 182 } 183 184 // Update persists an updated bot to the database. 185 // It assumes the corresponding user was updated via the user store. 186 func (us SqlBotStore) Update(bot *model.Bot) (*model.Bot, error) { 187 bot = bot.Clone() 188 189 bot.PreUpdate() 190 if err := bot.IsValid(); err != nil { // TODO: needs to return error in v6 191 return nil, err 192 } 193 194 oldBot, err := us.Get(bot.UserId, true) 195 if err != nil { 196 return nil, err 197 } 198 199 oldBot.Description = bot.Description 200 oldBot.OwnerId = bot.OwnerId 201 oldBot.LastIconUpdate = bot.LastIconUpdate 202 oldBot.UpdateAt = bot.UpdateAt 203 oldBot.DeleteAt = bot.DeleteAt 204 bot = oldBot 205 206 if count, err := us.GetMaster().Update(botFromModel(bot)); err != nil { 207 return nil, errors.Wrapf(err, "update: user_id=%s", bot.UserId) 208 } else if count > 1 { 209 return nil, fmt.Errorf("unexpected count while updating bot: count=%d, userId=%s", count, bot.UserId) 210 } 211 212 return bot, nil 213 } 214 215 // PermanentDelete removes the bot from the database altogether. 216 // If the corresponding user is to be deleted, it must be done via the user store. 217 func (us SqlBotStore) PermanentDelete(botUserId string) error { 218 query := "DELETE FROM Bots WHERE UserId = :user_id" 219 if _, err := us.GetMaster().Exec(query, map[string]interface{}{"user_id": botUserId}); err != nil { 220 return store.NewErrInvalidInput("Bot", "UserId", botUserId) 221 } 222 return nil 223 }