github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/store/sqlstore/preference_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 "net/http" 8 9 "github.com/mattermost/gorp" 10 11 "github.com/vnforks/kid/v5/mlog" 12 "github.com/vnforks/kid/v5/model" 13 "github.com/vnforks/kid/v5/store" 14 ) 15 16 type SqlPreferenceStore struct { 17 SqlStore 18 } 19 20 func newSqlPreferenceStore(sqlStore SqlStore) store.PreferenceStore { 21 s := &SqlPreferenceStore{sqlStore} 22 23 for _, db := range sqlStore.GetAllConns() { 24 table := db.AddTableWithName(model.Preference{}, "Preferences").SetKeys(false, "UserId", "Category", "Name") 25 table.ColMap("UserId").SetMaxSize(26) 26 table.ColMap("Category").SetMaxSize(32) 27 table.ColMap("Name").SetMaxSize(32) 28 table.ColMap("Value").SetMaxSize(2000) 29 } 30 31 return s 32 } 33 34 func (s SqlPreferenceStore) createIndexesIfNotExists() { 35 s.CreateIndexIfNotExists("idx_preferences_user_id", "Preferences", "UserId") 36 s.CreateIndexIfNotExists("idx_preferences_category", "Preferences", "Category") 37 s.CreateIndexIfNotExists("idx_preferences_name", "Preferences", "Name") 38 } 39 40 func (s SqlPreferenceStore) deleteUnusedFeatures() { 41 mlog.Debug("Deleting any unused pre-release features") 42 43 sql := `DELETE 44 FROM Preferences 45 WHERE 46 Category = :Category 47 AND Value = :Value 48 AND Name LIKE '` + store.FEATURE_TOGGLE_PREFIX + `%'` 49 50 queryParams := map[string]string{ 51 "Category": model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS, 52 "Value": "false", 53 } 54 s.GetMaster().Exec(sql, queryParams) 55 } 56 57 func (s SqlPreferenceStore) Save(preferences *model.Preferences) *model.AppError { 58 // wrap in a transaction so that if one fails, everything fails 59 transaction, err := s.GetMaster().Begin() 60 if err != nil { 61 return model.NewAppError("SqlPreferenceStore.Save", "store.sql_preference.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 62 } 63 64 defer finalizeTransaction(transaction) 65 for _, preference := range *preferences { 66 preference := preference 67 if upsertErr := s.save(transaction, &preference); upsertErr != nil { 68 return upsertErr 69 } 70 } 71 72 if err := transaction.Commit(); err != nil { 73 // don't need to rollback here since the transaction is already closed 74 return model.NewAppError("SqlPreferenceStore.Save", "store.sql_preference.save.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 75 } 76 return nil 77 } 78 79 func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *model.Preference) *model.AppError { 80 preference.PreUpdate() 81 82 if err := preference.IsValid(); err != nil { 83 return err 84 } 85 86 params := map[string]interface{}{ 87 "UserId": preference.UserId, 88 "Category": preference.Category, 89 "Name": preference.Name, 90 "Value": preference.Value, 91 } 92 93 if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 94 if _, err := transaction.Exec( 95 `INSERT INTO 96 Preferences 97 (UserId, Category, Name, Value) 98 VALUES 99 (:UserId, :Category, :Name, :Value) 100 ON DUPLICATE KEY UPDATE 101 Value = :Value`, params); err != nil { 102 return model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error(), http.StatusInternalServerError) 103 } 104 return nil 105 } else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 106 // postgres has no way to upsert values until version 9.5 and trying inserting and then updating causes transactions to abort 107 count, err := transaction.SelectInt( 108 `SELECT 109 count(0) 110 FROM 111 Preferences 112 WHERE 113 UserId = :UserId 114 AND Category = :Category 115 AND Name = :Name`, params) 116 if err != nil { 117 return model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error(), http.StatusInternalServerError) 118 } 119 120 if count == 1 { 121 return s.update(transaction, preference) 122 } 123 return s.insert(transaction, preference) 124 } 125 return model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.missing_driver.app_error", nil, "Failed to update preference because of missing driver", http.StatusNotImplemented) 126 } 127 128 func (s SqlPreferenceStore) insert(transaction *gorp.Transaction, preference *model.Preference) *model.AppError { 129 if err := transaction.Insert(preference); err != nil { 130 if IsUniqueConstraintError(err, []string{"UserId", "preferences_pkey"}) { 131 return model.NewAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.exists.app_error", nil, 132 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusBadRequest) 133 } 134 return model.NewAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.save.app_error", nil, 135 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusInternalServerError) 136 } 137 138 return nil 139 } 140 141 func (s SqlPreferenceStore) update(transaction *gorp.Transaction, preference *model.Preference) *model.AppError { 142 if _, err := transaction.Update(preference); err != nil { 143 return model.NewAppError("SqlPreferenceStore.update", "store.sql_preference.update.app_error", nil, 144 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusInternalServerError) 145 } 146 147 return nil 148 } 149 150 func (s SqlPreferenceStore) Get(userId string, category string, name string) (*model.Preference, *model.AppError) { 151 var preference *model.Preference 152 153 if err := s.GetReplica().SelectOne(&preference, 154 `SELECT 155 * 156 FROM 157 Preferences 158 WHERE 159 UserId = :UserId 160 AND Category = :Category 161 AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil { 162 return nil, model.NewAppError("SqlPreferenceStore.Get", "store.sql_preference.get.app_error", nil, err.Error(), http.StatusInternalServerError) 163 } 164 return preference, nil 165 } 166 167 func (s SqlPreferenceStore) GetCategory(userId string, category string) (model.Preferences, *model.AppError) { 168 var preferences model.Preferences 169 170 if _, err := s.GetReplica().Select(&preferences, 171 `SELECT 172 * 173 FROM 174 Preferences 175 WHERE 176 UserId = :UserId 177 AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil { 178 return nil, model.NewAppError("SqlPreferenceStore.GetCategory", "store.sql_preference.get_category.app_error", nil, err.Error(), http.StatusInternalServerError) 179 } 180 181 return preferences, nil 182 183 } 184 185 func (s SqlPreferenceStore) GetAll(userId string) (model.Preferences, *model.AppError) { 186 var preferences model.Preferences 187 188 if _, err := s.GetReplica().Select(&preferences, 189 `SELECT 190 * 191 FROM 192 Preferences 193 WHERE 194 UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil { 195 return nil, model.NewAppError("SqlPreferenceStore.GetAll", "store.sql_preference.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 196 } 197 return preferences, nil 198 } 199 200 func (s SqlPreferenceStore) PermanentDeleteByUser(userId string) *model.AppError { 201 query := 202 `DELETE FROM 203 Preferences 204 WHERE 205 UserId = :UserId` 206 207 if _, err := s.GetMaster().Exec(query, map[string]interface{}{"UserId": userId}); err != nil { 208 return model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.permanent_delete_by_user.app_error", nil, err.Error(), http.StatusInternalServerError) 209 } 210 211 return nil 212 } 213 214 func (s SqlPreferenceStore) Delete(userId, category, name string) *model.AppError { 215 query := 216 `DELETE FROM Preferences 217 WHERE 218 UserId = :UserId 219 AND Category = :Category 220 AND Name = :Name` 221 222 _, err := s.GetMaster().Exec(query, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}) 223 224 if err != nil { 225 return model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 226 } 227 228 return nil 229 } 230 231 func (s SqlPreferenceStore) DeleteCategory(userId string, category string) *model.AppError { 232 _, err := s.GetMaster().Exec( 233 `DELETE FROM 234 Preferences 235 WHERE 236 UserId = :UserId 237 AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}) 238 239 if err != nil { 240 return model.NewAppError("SqlPreferenceStore.DeleteCategory", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 241 } 242 243 return nil 244 } 245 246 func (s SqlPreferenceStore) DeleteCategoryAndName(category string, name string) *model.AppError { 247 _, err := s.GetMaster().Exec( 248 `DELETE FROM 249 Preferences 250 WHERE 251 Name = :Name 252 AND Category = :Category`, map[string]interface{}{"Name": name, "Category": category}) 253 254 if err != nil { 255 return model.NewAppError("SqlPreferenceStore.DeleteCategoryAndName", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 256 } 257 258 return nil 259 } 260 261 func (s SqlPreferenceStore) CleanupFlagsBatch(limit int64) (int64, *model.AppError) { 262 query := 263 `DELETE FROM 264 Preferences 265 WHERE 266 Category = :Category 267 AND Name IN ( 268 SELECT 269 * 270 FROM ( 271 SELECT 272 Preferences.Name 273 FROM 274 Preferences 275 LEFT JOIN 276 Posts 277 ON 278 Preferences.Name = Posts.Id 279 WHERE 280 Preferences.Category = :Category 281 AND Posts.Id IS null 282 LIMIT 283 :Limit 284 ) 285 AS t 286 )` 287 288 sqlResult, err := s.GetMaster().Exec(query, map[string]interface{}{"Category": model.PREFERENCE_CATEGORY_FLAGGED_POST, "Limit": limit}) 289 if err != nil { 290 return int64(0), model.NewAppError("SqlPostStore.CleanupFlagsBatch", "store.sql_preference.cleanup_flags_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError) 291 } 292 293 rowsAffected, err := sqlResult.RowsAffected() 294 if err != nil { 295 return int64(0), model.NewAppError("SqlPostStore.CleanupFlagsBatch", "store.sql_preference.cleanup_flags_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError) 296 } 297 298 return rowsAffected, nil 299 }