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