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  }