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