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  }