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