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