github.com/keys-pub/mattermost-server@v4.10.10+incompatible/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/mattermost/mattermost-server/mlog" 12 "github.com/mattermost/mattermost-server/model" 13 "github.com/mattermost/mattermost-server/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) store.StoreChannel { 58 return store.Do(func(result *store.StoreResult) { 59 // wrap in a transaction so that if one fails, everything fails 60 transaction, err := s.GetMaster().Begin() 61 if err != nil { 62 result.Err = model.NewAppError("SqlPreferenceStore.Save", "store.sql_preference.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 63 } else { 64 for _, preference := range *preferences { 65 if upsertResult := s.save(transaction, &preference); upsertResult.Err != nil { 66 *result = upsertResult 67 break 68 } 69 } 70 71 if result.Err == nil { 72 if err := transaction.Commit(); err != nil { 73 // don't need to rollback here since the transaction is already closed 74 result.Err = model.NewAppError("SqlPreferenceStore.Save", "store.sql_preference.save.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 75 } else { 76 result.Data = len(*preferences) 77 } 78 } else { 79 if err := transaction.Rollback(); err != nil { 80 result.Err = model.NewAppError("SqlPreferenceStore.Save", "store.sql_preference.save.rollback_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 81 } 82 } 83 } 84 }) 85 } 86 87 func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *model.Preference) store.StoreResult { 88 result := store.StoreResult{} 89 90 preference.PreUpdate() 91 92 if result.Err = preference.IsValid(); result.Err != nil { 93 return result 94 } 95 96 params := map[string]interface{}{ 97 "UserId": preference.UserId, 98 "Category": preference.Category, 99 "Name": preference.Name, 100 "Value": preference.Value, 101 } 102 103 if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 104 if _, err := transaction.Exec( 105 `INSERT INTO 106 Preferences 107 (UserId, Category, Name, Value) 108 VALUES 109 (:UserId, :Category, :Name, :Value) 110 ON DUPLICATE KEY UPDATE 111 Value = :Value`, params); err != nil { 112 result.Err = model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error(), http.StatusInternalServerError) 113 } 114 } else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 115 // postgres has no way to upsert values until version 9.5 and trying inserting and then updating causes transactions to abort 116 count, err := transaction.SelectInt( 117 `SELECT 118 count(0) 119 FROM 120 Preferences 121 WHERE 122 UserId = :UserId 123 AND Category = :Category 124 AND Name = :Name`, params) 125 if err != nil { 126 result.Err = model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error(), http.StatusInternalServerError) 127 return result 128 } 129 130 if count == 1 { 131 s.update(transaction, preference) 132 } else { 133 s.insert(transaction, preference) 134 } 135 } else { 136 result.Err = model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.missing_driver.app_error", nil, "Failed to update preference because of missing driver", http.StatusNotImplemented) 137 } 138 139 return result 140 } 141 142 func (s SqlPreferenceStore) insert(transaction *gorp.Transaction, preference *model.Preference) store.StoreResult { 143 result := store.StoreResult{} 144 145 if err := transaction.Insert(preference); err != nil { 146 if IsUniqueConstraintError(err, []string{"UserId", "preferences_pkey"}) { 147 result.Err = model.NewAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.exists.app_error", nil, 148 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusBadRequest) 149 } else { 150 result.Err = model.NewAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.save.app_error", nil, 151 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusInternalServerError) 152 } 153 } 154 155 return result 156 } 157 158 func (s SqlPreferenceStore) update(transaction *gorp.Transaction, preference *model.Preference) store.StoreResult { 159 result := store.StoreResult{} 160 161 if _, err := transaction.Update(preference); err != nil { 162 result.Err = model.NewAppError("SqlPreferenceStore.update", "store.sql_preference.update.app_error", nil, 163 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusInternalServerError) 164 } 165 166 return result 167 } 168 169 func (s SqlPreferenceStore) Get(userId string, category string, name string) store.StoreChannel { 170 return store.Do(func(result *store.StoreResult) { 171 var preference model.Preference 172 173 if err := s.GetReplica().SelectOne(&preference, 174 `SELECT 175 * 176 FROM 177 Preferences 178 WHERE 179 UserId = :UserId 180 AND Category = :Category 181 AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil { 182 result.Err = model.NewAppError("SqlPreferenceStore.Get", "store.sql_preference.get.app_error", nil, err.Error(), http.StatusInternalServerError) 183 } else { 184 result.Data = preference 185 } 186 }) 187 } 188 189 func (s SqlPreferenceStore) GetCategory(userId string, category string) store.StoreChannel { 190 return store.Do(func(result *store.StoreResult) { 191 var preferences model.Preferences 192 193 if _, err := s.GetReplica().Select(&preferences, 194 `SELECT 195 * 196 FROM 197 Preferences 198 WHERE 199 UserId = :UserId 200 AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil { 201 result.Err = model.NewAppError("SqlPreferenceStore.GetCategory", "store.sql_preference.get_category.app_error", nil, err.Error(), http.StatusInternalServerError) 202 } else { 203 result.Data = preferences 204 } 205 }) 206 } 207 208 func (s SqlPreferenceStore) GetAll(userId string) store.StoreChannel { 209 return store.Do(func(result *store.StoreResult) { 210 var preferences model.Preferences 211 212 if _, err := s.GetReplica().Select(&preferences, 213 `SELECT 214 * 215 FROM 216 Preferences 217 WHERE 218 UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil { 219 result.Err = model.NewAppError("SqlPreferenceStore.GetAll", "store.sql_preference.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 220 } else { 221 result.Data = preferences 222 } 223 }) 224 } 225 226 func (s SqlPreferenceStore) PermanentDeleteByUser(userId string) store.StoreChannel { 227 return store.Do(func(result *store.StoreResult) { 228 if _, err := s.GetMaster().Exec( 229 `DELETE FROM Preferences WHERE UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil { 230 result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.permanent_delete_by_user.app_error", nil, err.Error(), http.StatusInternalServerError) 231 } 232 }) 233 } 234 235 func (s SqlPreferenceStore) IsFeatureEnabled(feature, userId string) store.StoreChannel { 236 return store.Do(func(result *store.StoreResult) { 237 if value, err := s.GetReplica().SelectStr(`SELECT 238 value 239 FROM 240 Preferences 241 WHERE 242 UserId = :UserId 243 AND Category = :Category 244 AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS, "Name": store.FEATURE_TOGGLE_PREFIX + feature}); err != nil { 245 result.Err = model.NewAppError("SqlPreferenceStore.IsFeatureEnabled", "store.sql_preference.is_feature_enabled.app_error", nil, err.Error(), http.StatusInternalServerError) 246 } else { 247 result.Data = value == "true" 248 } 249 }) 250 } 251 252 func (s SqlPreferenceStore) Delete(userId, category, name string) store.StoreChannel { 253 return store.Do(func(result *store.StoreResult) { 254 if _, err := s.GetMaster().Exec( 255 `DELETE FROM 256 Preferences 257 WHERE 258 UserId = :UserId 259 AND Category = :Category 260 AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil { 261 result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 262 } 263 }) 264 } 265 266 func (s SqlPreferenceStore) DeleteCategory(userId string, category string) store.StoreChannel { 267 return store.Do(func(result *store.StoreResult) { 268 if _, err := s.GetMaster().Exec( 269 `DELETE FROM 270 Preferences 271 WHERE 272 UserId = :UserId 273 AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil { 274 result.Err = model.NewAppError("SqlPreferenceStore.DeleteCategory", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 275 } 276 }) 277 } 278 279 func (s SqlPreferenceStore) DeleteCategoryAndName(category string, name string) store.StoreChannel { 280 return store.Do(func(result *store.StoreResult) { 281 if _, err := s.GetMaster().Exec( 282 `DELETE FROM 283 Preferences 284 WHERE 285 Name = :Name 286 AND Category = :Category`, map[string]interface{}{"Name": name, "Category": category}); err != nil { 287 result.Err = model.NewAppError("SqlPreferenceStore.DeleteCategoryAndName", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 288 } 289 }) 290 } 291 292 func (s SqlPreferenceStore) CleanupFlagsBatch(limit int64) store.StoreChannel { 293 return store.Do(func(result *store.StoreResult) { 294 query := 295 `DELETE FROM 296 Preferences 297 WHERE 298 Category = :Category 299 AND Name IN ( 300 SELECT 301 * 302 FROM ( 303 SELECT 304 Preferences.Name 305 FROM 306 Preferences 307 LEFT JOIN 308 Posts 309 ON 310 Preferences.Name = Posts.Id 311 WHERE 312 Preferences.Category = :Category 313 AND Posts.Id IS null 314 LIMIT 315 :Limit 316 ) 317 AS t 318 )` 319 320 sqlResult, err := s.GetMaster().Exec(query, map[string]interface{}{"Category": model.PREFERENCE_CATEGORY_FLAGGED_POST, "Limit": limit}) 321 if err != nil { 322 result.Err = model.NewAppError("SqlPostStore.CleanupFlagsBatch", "store.sql_preference.cleanup_flags_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError) 323 } else { 324 rowsAffected, err1 := sqlResult.RowsAffected() 325 if err1 != nil { 326 result.Err = model.NewAppError("SqlPostStore.CleanupFlagsBatch", "store.sql_preference.cleanup_flags_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError) 327 result.Data = int64(0) 328 } else { 329 result.Data = rowsAffected 330 } 331 } 332 }) 333 }