github.com/mad-app/mattermost-server@v5.11.1+incompatible/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 "net/http" 9 "strings" 10 11 "github.com/mattermost/mattermost-server/einterfaces" 12 "github.com/mattermost/mattermost-server/model" 13 "github.com/mattermost/mattermost-server/store" 14 ) 15 16 // bot is a subset of the model.Bot type, omitting the model.User fields. 17 type bot struct { 18 UserId string `json:"user_id"` 19 Description string `json:"description"` 20 OwnerId string `json:"owner_id"` 21 CreateAt int64 `json:"create_at"` 22 UpdateAt int64 `json:"update_at"` 23 DeleteAt int64 `json:"delete_at"` 24 } 25 26 func botFromModel(b *model.Bot) *bot { 27 return &bot{ 28 UserId: b.UserId, 29 Description: b.Description, 30 OwnerId: b.OwnerId, 31 CreateAt: b.CreateAt, 32 UpdateAt: b.UpdateAt, 33 DeleteAt: b.DeleteAt, 34 } 35 } 36 37 // SqlBotStore is a store for managing bots in the database. 38 // Bots are otherwise normal users with extra metadata record in the Bots table. The primary key 39 // for a bot matches the primary key value for corresponding User record. 40 type SqlBotStore struct { 41 SqlStore 42 metrics einterfaces.MetricsInterface 43 } 44 45 // NewSqlBotStore creates an instance of SqlBotStore, registering the table schema in question. 46 func NewSqlBotStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.BotStore { 47 us := &SqlBotStore{ 48 SqlStore: sqlStore, 49 metrics: metrics, 50 } 51 52 for _, db := range sqlStore.GetAllConns() { 53 table := db.AddTableWithName(bot{}, "Bots").SetKeys(false, "UserId") 54 table.ColMap("UserId").SetMaxSize(26) 55 table.ColMap("Description").SetMaxSize(1024) 56 table.ColMap("OwnerId").SetMaxSize(model.BOT_CREATOR_ID_MAX_RUNES) 57 } 58 59 return us 60 } 61 62 func (us SqlBotStore) CreateIndexesIfNotExists() { 63 } 64 65 // traceBot is a helper function for adding to a bot trace when logging. 66 func traceBot(bot *model.Bot, extra map[string]interface{}) map[string]interface{} { 67 trace := make(map[string]interface{}) 68 for key, value := range bot.Trace() { 69 trace[key] = value 70 } 71 for key, value := range extra { 72 trace[key] = value 73 } 74 75 return trace 76 } 77 78 // Get fetches the given bot in the database. 79 func (us SqlBotStore) Get(botUserId string, includeDeleted bool) store.StoreChannel { 80 return store.Do(func(result *store.StoreResult) { 81 var excludeDeletedSql = "AND b.DeleteAt = 0" 82 if includeDeleted { 83 excludeDeletedSql = "" 84 } 85 86 var bot *model.Bot 87 if err := us.GetReplica().SelectOne(&bot, ` 88 SELECT 89 b.UserId, 90 u.Username, 91 u.FirstName AS DisplayName, 92 b.Description, 93 b.OwnerId, 94 b.CreateAt, 95 b.UpdateAt, 96 b.DeleteAt 97 FROM 98 Bots b 99 JOIN 100 Users u ON (u.Id = b.UserId) 101 WHERE 102 b.UserId = :user_id 103 `+excludeDeletedSql+` 104 `, map[string]interface{}{ 105 "user_id": botUserId, 106 }); err == sql.ErrNoRows { 107 result.Err = model.MakeBotNotFoundError(botUserId) 108 } else if err != nil { 109 result.Err = model.NewAppError("SqlBotStore.Get", "store.sql_bot.get.app_error", map[string]interface{}{"user_id": botUserId}, err.Error(), http.StatusInternalServerError) 110 } else { 111 result.Data = bot 112 } 113 }) 114 } 115 116 // GetAll fetches from all bots in the database. 117 func (us SqlBotStore) GetAll(options *model.BotGetOptions) store.StoreChannel { 118 return store.Do(func(result *store.StoreResult) { 119 params := map[string]interface{}{ 120 "offset": options.Page * options.PerPage, 121 "limit": options.PerPage, 122 } 123 124 var conditions []string 125 var conditionsSql string 126 var additionalJoin string 127 128 if !options.IncludeDeleted { 129 conditions = append(conditions, "b.DeleteAt = 0") 130 } 131 if options.OwnerId != "" { 132 conditions = append(conditions, "b.OwnerId = :creator_id") 133 params["creator_id"] = options.OwnerId 134 } 135 if options.OnlyOrphaned { 136 additionalJoin = "JOIN Users o ON (o.Id = b.OwnerId)" 137 conditions = append(conditions, "o.DeleteAt != 0") 138 } 139 140 if len(conditions) > 0 { 141 conditionsSql = "WHERE " + strings.Join(conditions, " AND ") 142 } 143 144 sql := ` 145 SELECT 146 b.UserId, 147 u.Username, 148 u.FirstName AS DisplayName, 149 b.Description, 150 b.OwnerId, 151 b.CreateAt, 152 b.UpdateAt, 153 b.DeleteAt 154 FROM 155 Bots b 156 JOIN 157 Users u ON (u.Id = b.UserId) 158 ` + additionalJoin + ` 159 ` + conditionsSql + ` 160 ORDER BY 161 b.CreateAt ASC, 162 u.Username ASC 163 LIMIT 164 :limit 165 OFFSET 166 :offset 167 ` 168 169 var data []*model.Bot 170 if _, err := us.GetReplica().Select(&data, sql, params); err != nil { 171 result.Err = model.NewAppError("SqlBotStore.GetAll", "store.sql_bot.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 172 } 173 174 result.Data = data 175 }) 176 } 177 178 // Save persists a new bot to the database. 179 // It assumes the corresponding user was saved via the user store. 180 func (us SqlBotStore) Save(bot *model.Bot) store.StoreChannel { 181 bot = bot.Clone() 182 183 return store.Do(func(result *store.StoreResult) { 184 bot.PreSave() 185 if result.Err = bot.IsValid(); result.Err != nil { 186 return 187 } 188 189 if err := us.GetMaster().Insert(botFromModel(bot)); err != nil { 190 result.Err = model.NewAppError("SqlBotStore.Save", "store.sql_bot.save.app_error", bot.Trace(), err.Error(), http.StatusInternalServerError) 191 return 192 } 193 194 result.Data = bot 195 }) 196 } 197 198 // Update persists an updated bot to the database. 199 // It assumes the corresponding user was updated via the user store. 200 func (us SqlBotStore) Update(bot *model.Bot) store.StoreChannel { 201 bot = bot.Clone() 202 203 return store.Do(func(result *store.StoreResult) { 204 bot.PreUpdate() 205 if result.Err = bot.IsValid(); result.Err != nil { 206 return 207 } 208 209 oldBotResult := <-us.Get(bot.UserId, true) 210 if oldBotResult.Err != nil { 211 result.Err = oldBotResult.Err 212 return 213 } 214 oldBot := oldBotResult.Data.(*model.Bot) 215 216 oldBot.Description = bot.Description 217 oldBot.OwnerId = bot.OwnerId 218 oldBot.UpdateAt = bot.UpdateAt 219 oldBot.DeleteAt = bot.DeleteAt 220 bot = oldBot 221 222 if count, err := us.GetMaster().Update(botFromModel(bot)); err != nil { 223 result.Err = model.NewAppError("SqlBotStore.Update", "store.sql_bot.update.updating.app_error", bot.Trace(), err.Error(), http.StatusInternalServerError) 224 } else if count != 1 { 225 result.Err = model.NewAppError("SqlBotStore.Update", "store.sql_bot.update.app_error", traceBot(bot, map[string]interface{}{"count": count}), "", http.StatusInternalServerError) 226 } 227 228 result.Data = bot 229 }) 230 } 231 232 // PermanentDelete removes the bot from the database altogether. 233 // If the corresponding user is to be deleted, it must be done via the user store. 234 func (us SqlBotStore) PermanentDelete(botUserId string) store.StoreChannel { 235 return store.Do(func(result *store.StoreResult) { 236 userResult := <-us.User().PermanentDelete(botUserId) 237 if userResult.Err != nil { 238 result.Err = userResult.Err 239 return 240 } 241 242 if _, err := us.GetMaster().Exec(` 243 DELETE FROM 244 Bots 245 WHERE 246 UserId = :user_id 247 `, map[string]interface{}{ 248 "user_id": botUserId, 249 }); err != nil { 250 result.Err = model.NewAppError("SqlBotStore.Update", "store.sql_bot.delete.app_error", map[string]interface{}{"user_id": botUserId}, err.Error(), http.StatusBadRequest) 251 } 252 }) 253 }