github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/store/sqlstore/bot_store.go (about) 1 // Copyright (c) 2015-present Xenia, 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/xzl8028/xenia-server/einterfaces" 12 "github.com/xzl8028/xenia-server/model" 13 "github.com/xzl8028/xenia-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) (*model.Bot, *model.AppError) { 80 var excludeDeletedSql = "AND b.DeleteAt = 0" 81 if includeDeleted { 82 excludeDeletedSql = "" 83 } 84 85 query := ` 86 SELECT 87 b.UserId, 88 u.Username, 89 u.FirstName AS DisplayName, 90 b.Description, 91 b.OwnerId, 92 b.CreateAt, 93 b.UpdateAt, 94 b.DeleteAt 95 FROM 96 Bots b 97 JOIN 98 Users u ON (u.Id = b.UserId) 99 WHERE 100 b.UserId = :user_id 101 ` + excludeDeletedSql + ` 102 ` 103 104 var bot *model.Bot 105 if err := us.GetReplica().SelectOne(&bot, query, map[string]interface{}{"user_id": botUserId}); err == sql.ErrNoRows { 106 return nil, model.MakeBotNotFoundError(botUserId) 107 } else if err != nil { 108 return nil, model.NewAppError("SqlBotStore.Get", "store.sql_bot.get.app_error", map[string]interface{}{"user_id": botUserId}, err.Error(), http.StatusInternalServerError) 109 } 110 111 return bot, nil 112 } 113 114 // GetAll fetches from all bots in the database. 115 func (us SqlBotStore) GetAll(options *model.BotGetOptions) ([]*model.Bot, *model.AppError) { 116 params := map[string]interface{}{ 117 "offset": options.Page * options.PerPage, 118 "limit": options.PerPage, 119 } 120 121 var conditions []string 122 var conditionsSql string 123 var additionalJoin string 124 125 if !options.IncludeDeleted { 126 conditions = append(conditions, "b.DeleteAt = 0") 127 } 128 if options.OwnerId != "" { 129 conditions = append(conditions, "b.OwnerId = :creator_id") 130 params["creator_id"] = options.OwnerId 131 } 132 if options.OnlyOrphaned { 133 additionalJoin = "JOIN Users o ON (o.Id = b.OwnerId)" 134 conditions = append(conditions, "o.DeleteAt != 0") 135 } 136 137 if len(conditions) > 0 { 138 conditionsSql = "WHERE " + strings.Join(conditions, " AND ") 139 } 140 141 sql := ` 142 SELECT 143 b.UserId, 144 u.Username, 145 u.FirstName AS DisplayName, 146 b.Description, 147 b.OwnerId, 148 b.CreateAt, 149 b.UpdateAt, 150 b.DeleteAt 151 FROM 152 Bots b 153 JOIN 154 Users u ON (u.Id = b.UserId) 155 ` + additionalJoin + ` 156 ` + conditionsSql + ` 157 ORDER BY 158 b.CreateAt ASC, 159 u.Username ASC 160 LIMIT 161 :limit 162 OFFSET 163 :offset 164 ` 165 166 var bots []*model.Bot 167 if _, err := us.GetReplica().Select(&bots, sql, params); err != nil { 168 return nil, model.NewAppError("SqlBotStore.GetAll", "store.sql_bot.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 169 } 170 171 return bots, nil 172 } 173 174 // Save persists a new bot to the database. 175 // It assumes the corresponding user was saved via the user store. 176 func (us SqlBotStore) Save(bot *model.Bot) (*model.Bot, *model.AppError) { 177 bot = bot.Clone() 178 bot.PreSave() 179 180 if err := bot.IsValid(); err != nil { 181 return nil, err 182 } 183 184 if err := us.GetMaster().Insert(botFromModel(bot)); err != nil { 185 return nil, model.NewAppError("SqlBotStore.Save", "store.sql_bot.save.app_error", bot.Trace(), err.Error(), http.StatusInternalServerError) 186 } 187 188 return bot, nil 189 } 190 191 // Update persists an updated bot to the database. 192 // It assumes the corresponding user was updated via the user store. 193 func (us SqlBotStore) Update(bot *model.Bot) (*model.Bot, *model.AppError) { 194 bot = bot.Clone() 195 196 bot.PreUpdate() 197 if err := bot.IsValid(); err != nil { 198 return nil, err 199 } 200 201 oldBot, err := us.Get(bot.UserId, true) 202 if err != nil { 203 return nil, err 204 } 205 206 oldBot.Description = bot.Description 207 oldBot.OwnerId = bot.OwnerId 208 oldBot.UpdateAt = bot.UpdateAt 209 oldBot.DeleteAt = bot.DeleteAt 210 bot = oldBot 211 212 if count, err := us.GetMaster().Update(botFromModel(bot)); err != nil { 213 return nil, model.NewAppError("SqlBotStore.Update", "store.sql_bot.update.updating.app_error", bot.Trace(), err.Error(), http.StatusInternalServerError) 214 } else if count != 1 { 215 return nil, model.NewAppError("SqlBotStore.Update", "store.sql_bot.update.app_error", traceBot(bot, map[string]interface{}{"count": count}), "", http.StatusInternalServerError) 216 } 217 218 return bot, nil 219 } 220 221 // PermanentDelete removes the bot from the database altogether. 222 // If the corresponding user is to be deleted, it must be done via the user store. 223 func (us SqlBotStore) PermanentDelete(botUserId string) *model.AppError { 224 query := "DELETE FROM Bots WHERE UserId = :user_id" 225 if _, err := us.GetMaster().Exec(query, map[string]interface{}{"user_id": botUserId}); err != nil { 226 return model.NewAppError("SqlBotStore.Update", "store.sql_bot.delete.app_error", map[string]interface{}{"user_id": botUserId}, err.Error(), http.StatusBadRequest) 227 } 228 return nil 229 }