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