github.com/coincircle/mattermost-server@v4.8.1-0.20180321182714-9d701c704416+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 l4g "github.com/alecthomas/log4go" 10 "github.com/mattermost/gorp" 11 12 "github.com/mattermost/mattermost-server/model" 13 "github.com/mattermost/mattermost-server/store" 14 "github.com/mattermost/mattermost-server/utils" 15 ) 16 17 type SqlPreferenceStore struct { 18 SqlStore 19 } 20 21 func NewSqlPreferenceStore(sqlStore SqlStore) store.PreferenceStore { 22 s := &SqlPreferenceStore{sqlStore} 23 24 for _, db := range sqlStore.GetAllConns() { 25 table := db.AddTableWithName(model.Preference{}, "Preferences").SetKeys(false, "UserId", "Category", "Name") 26 table.ColMap("UserId").SetMaxSize(26) 27 table.ColMap("Category").SetMaxSize(32) 28 table.ColMap("Name").SetMaxSize(32) 29 table.ColMap("Value").SetMaxSize(2000) 30 } 31 32 return s 33 } 34 35 func (s SqlPreferenceStore) CreateIndexesIfNotExists() { 36 s.CreateIndexIfNotExists("idx_preferences_user_id", "Preferences", "UserId") 37 s.CreateIndexIfNotExists("idx_preferences_category", "Preferences", "Category") 38 s.CreateIndexIfNotExists("idx_preferences_name", "Preferences", "Name") 39 } 40 41 func (s SqlPreferenceStore) DeleteUnusedFeatures() { 42 l4g.Debug(utils.T("store.sql_preference.delete_unused_features.debug")) 43 44 sql := `DELETE 45 FROM Preferences 46 WHERE 47 Category = :Category 48 AND Value = :Value 49 AND Name LIKE '` + store.FEATURE_TOGGLE_PREFIX + `%'` 50 51 queryParams := map[string]string{ 52 "Category": model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS, 53 "Value": "false", 54 } 55 s.GetMaster().Exec(sql, queryParams) 56 } 57 58 func (s SqlPreferenceStore) Save(preferences *model.Preferences) store.StoreChannel { 59 return store.Do(func(result *store.StoreResult) { 60 // wrap in a transaction so that if one fails, everything fails 61 transaction, err := s.GetMaster().Begin() 62 if err != nil { 63 result.Err = model.NewAppError("SqlPreferenceStore.Save", "store.sql_preference.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 64 } else { 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 } else { 80 if err := transaction.Rollback(); err != nil { 81 result.Err = model.NewAppError("SqlPreferenceStore.Save", "store.sql_preference.save.rollback_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 82 } 83 } 84 } 85 }) 86 } 87 88 func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *model.Preference) store.StoreResult { 89 result := store.StoreResult{} 90 91 preference.PreUpdate() 92 93 if result.Err = preference.IsValid(); result.Err != nil { 94 return result 95 } 96 97 params := map[string]interface{}{ 98 "UserId": preference.UserId, 99 "Category": preference.Category, 100 "Name": preference.Name, 101 "Value": preference.Value, 102 } 103 104 if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 105 if _, err := transaction.Exec( 106 `INSERT INTO 107 Preferences 108 (UserId, Category, Name, Value) 109 VALUES 110 (:UserId, :Category, :Name, :Value) 111 ON DUPLICATE KEY UPDATE 112 Value = :Value`, params); err != nil { 113 result.Err = model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error(), http.StatusInternalServerError) 114 } 115 } else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 116 // postgres has no way to upsert values until version 9.5 and trying inserting and then updating causes transactions to abort 117 count, err := transaction.SelectInt( 118 `SELECT 119 count(0) 120 FROM 121 Preferences 122 WHERE 123 UserId = :UserId 124 AND Category = :Category 125 AND Name = :Name`, params) 126 if err != nil { 127 result.Err = model.NewAppError("SqlPreferenceStore.save", "store.sql_preference.save.updating.app_error", nil, err.Error(), http.StatusInternalServerError) 128 return result 129 } 130 131 if count == 1 { 132 s.update(transaction, preference) 133 } else { 134 s.insert(transaction, preference) 135 } 136 } else { 137 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) 138 } 139 140 return result 141 } 142 143 func (s SqlPreferenceStore) insert(transaction *gorp.Transaction, preference *model.Preference) store.StoreResult { 144 result := store.StoreResult{} 145 146 if err := transaction.Insert(preference); err != nil { 147 if IsUniqueConstraintError(err, []string{"UserId", "preferences_pkey"}) { 148 result.Err = model.NewAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.exists.app_error", nil, 149 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusBadRequest) 150 } else { 151 result.Err = model.NewAppError("SqlPreferenceStore.insert", "store.sql_preference.insert.save.app_error", nil, 152 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusInternalServerError) 153 } 154 } 155 156 return result 157 } 158 159 func (s SqlPreferenceStore) update(transaction *gorp.Transaction, preference *model.Preference) store.StoreResult { 160 result := store.StoreResult{} 161 162 if _, err := transaction.Update(preference); err != nil { 163 result.Err = model.NewAppError("SqlPreferenceStore.update", "store.sql_preference.update.app_error", nil, 164 "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", "+err.Error(), http.StatusInternalServerError) 165 } 166 167 return result 168 } 169 170 func (s SqlPreferenceStore) Get(userId string, category string, name string) store.StoreChannel { 171 return store.Do(func(result *store.StoreResult) { 172 var preference model.Preference 173 174 if err := s.GetReplica().SelectOne(&preference, 175 `SELECT 176 * 177 FROM 178 Preferences 179 WHERE 180 UserId = :UserId 181 AND Category = :Category 182 AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil { 183 result.Err = model.NewAppError("SqlPreferenceStore.Get", "store.sql_preference.get.app_error", nil, err.Error(), http.StatusInternalServerError) 184 } else { 185 result.Data = preference 186 } 187 }) 188 } 189 190 func (s SqlPreferenceStore) GetCategory(userId string, category string) store.StoreChannel { 191 return store.Do(func(result *store.StoreResult) { 192 var preferences model.Preferences 193 194 if _, err := s.GetReplica().Select(&preferences, 195 `SELECT 196 * 197 FROM 198 Preferences 199 WHERE 200 UserId = :UserId 201 AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil { 202 result.Err = model.NewAppError("SqlPreferenceStore.GetCategory", "store.sql_preference.get_category.app_error", nil, err.Error(), http.StatusInternalServerError) 203 } else { 204 result.Data = preferences 205 } 206 }) 207 } 208 209 func (s SqlPreferenceStore) GetAll(userId string) store.StoreChannel { 210 return store.Do(func(result *store.StoreResult) { 211 var preferences model.Preferences 212 213 if _, err := s.GetReplica().Select(&preferences, 214 `SELECT 215 * 216 FROM 217 Preferences 218 WHERE 219 UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil { 220 result.Err = model.NewAppError("SqlPreferenceStore.GetAll", "store.sql_preference.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 221 } else { 222 result.Data = preferences 223 } 224 }) 225 } 226 227 func (s SqlPreferenceStore) PermanentDeleteByUser(userId string) store.StoreChannel { 228 return store.Do(func(result *store.StoreResult) { 229 if _, err := s.GetMaster().Exec( 230 `DELETE FROM Preferences WHERE UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil { 231 result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.permanent_delete_by_user.app_error", nil, err.Error(), http.StatusInternalServerError) 232 } 233 }) 234 } 235 236 func (s SqlPreferenceStore) IsFeatureEnabled(feature, userId string) store.StoreChannel { 237 return store.Do(func(result *store.StoreResult) { 238 if value, err := s.GetReplica().SelectStr(`SELECT 239 value 240 FROM 241 Preferences 242 WHERE 243 UserId = :UserId 244 AND Category = :Category 245 AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS, "Name": store.FEATURE_TOGGLE_PREFIX + feature}); err != nil { 246 result.Err = model.NewAppError("SqlPreferenceStore.IsFeatureEnabled", "store.sql_preference.is_feature_enabled.app_error", nil, err.Error(), http.StatusInternalServerError) 247 } else { 248 result.Data = value == "true" 249 } 250 }) 251 } 252 253 func (s SqlPreferenceStore) Delete(userId, category, name string) store.StoreChannel { 254 return store.Do(func(result *store.StoreResult) { 255 if _, err := s.GetMaster().Exec( 256 `DELETE FROM 257 Preferences 258 WHERE 259 UserId = :UserId 260 AND Category = :Category 261 AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil { 262 result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 263 } 264 }) 265 } 266 267 func (s SqlPreferenceStore) DeleteCategory(userId string, category string) store.StoreChannel { 268 return store.Do(func(result *store.StoreResult) { 269 if _, err := s.GetMaster().Exec( 270 `DELETE FROM 271 Preferences 272 WHERE 273 UserId = :UserId 274 AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil { 275 result.Err = model.NewAppError("SqlPreferenceStore.DeleteCategory", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 276 } 277 }) 278 } 279 280 func (s SqlPreferenceStore) DeleteCategoryAndName(category string, name string) store.StoreChannel { 281 return store.Do(func(result *store.StoreResult) { 282 if _, err := s.GetMaster().Exec( 283 `DELETE FROM 284 Preferences 285 WHERE 286 Name = :Name 287 AND Category = :Category`, map[string]interface{}{"Name": name, "Category": category}); err != nil { 288 result.Err = model.NewAppError("SqlPreferenceStore.DeleteCategoryAndName", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 289 } 290 }) 291 } 292 293 func (s SqlPreferenceStore) CleanupFlagsBatch(limit int64) store.StoreChannel { 294 return store.Do(func(result *store.StoreResult) { 295 query := 296 `DELETE FROM 297 Preferences 298 WHERE 299 Category = :Category 300 AND Name IN ( 301 SELECT 302 * 303 FROM ( 304 SELECT 305 Preferences.Name 306 FROM 307 Preferences 308 LEFT JOIN 309 Posts 310 ON 311 Preferences.Name = Posts.Id 312 WHERE 313 Preferences.Category = :Category 314 AND Posts.Id IS null 315 LIMIT 316 :Limit 317 ) 318 AS t 319 )` 320 321 sqlResult, err := s.GetMaster().Exec(query, map[string]interface{}{"Category": model.PREFERENCE_CATEGORY_FLAGGED_POST, "Limit": limit}) 322 if err != nil { 323 result.Err = model.NewAppError("SqlPostStore.CleanupFlagsBatch", "store.sql_preference.cleanup_flags_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError) 324 } else { 325 rowsAffected, err1 := sqlResult.RowsAffected() 326 if err1 != nil { 327 result.Err = model.NewAppError("SqlPostStore.CleanupFlagsBatch", "store.sql_preference.cleanup_flags_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError) 328 result.Data = int64(0) 329 } else { 330 result.Data = rowsAffected 331 } 332 } 333 }) 334 }