Creating common token store and moving email invites and verification to it (#6213)
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
0e007e344b
Коммит
9a87bb3af6
@@ -1,128 +0,0 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
type SqlPasswordRecoveryStore struct {
|
||||
*SqlStore
|
||||
}
|
||||
|
||||
func NewSqlPasswordRecoveryStore(sqlStore *SqlStore) PasswordRecoveryStore {
|
||||
s := &SqlPasswordRecoveryStore{sqlStore}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
table := db.AddTableWithName(model.PasswordRecovery{}, "PasswordRecovery").SetKeys(false, "UserId")
|
||||
table.ColMap("UserId").SetMaxSize(26)
|
||||
table.ColMap("Code").SetMaxSize(128)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s SqlPasswordRecoveryStore) CreateIndexesIfNotExists() {
|
||||
s.CreateIndexIfNotExists("idx_password_recovery_code", "PasswordRecovery", "Code")
|
||||
}
|
||||
|
||||
func (s SqlPasswordRecoveryStore) SaveOrUpdate(recovery *model.PasswordRecovery) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel, 1)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
recovery.PreSave()
|
||||
if result.Err = recovery.IsValid(); result.Err != nil {
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&model.PasswordRecovery{}, "SELECT * FROM PasswordRecovery WHERE UserId = :UserId", map[string]interface{}{"UserId": recovery.UserId}); err == nil {
|
||||
if _, err := s.GetMaster().Update(recovery); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.SaveOrUpdate", "store.sql_recover.update.app_error", nil, "")
|
||||
}
|
||||
} else {
|
||||
if err := s.GetMaster().Insert(recovery); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.SaveOrUpdate", "store.sql_recover.save.app_error", nil, "")
|
||||
}
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlPasswordRecoveryStore) Delete(userId string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel, 1)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM PasswordRecovery WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.Delete", "store.sql_recover.delete.app_error", nil, "")
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlPasswordRecoveryStore) Get(userId string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel, 1)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
recovery := model.PasswordRecovery{}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&recovery, "SELECT * FROM PasswordRecovery WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.Get", "store.sql_recover.get.app_error", nil, "")
|
||||
}
|
||||
|
||||
result.Data = &recovery
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlPasswordRecoveryStore) GetByCode(code string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel, 1)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
recovery := model.PasswordRecovery{}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&recovery, "SELECT * FROM PasswordRecovery WHERE Code = :Code", map[string]interface{}{"Code": code}); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
result.Err = model.NewAppError("SqlPasswordRecoveryStore.GetByCode", "store.sql_recover.get_by_code.app_error", nil, "", http.StatusBadRequest)
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlPasswordRecoveryStore.GetByCode", "store.sql_recover.get_by_code.app_error", nil, "", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
result.Data = &recovery
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/mattermost/platform/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSqlPasswordRecoveryGet(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
recovery := &model.PasswordRecovery{UserId: "12345678901234567890123456"}
|
||||
Must(store.PasswordRecovery().SaveOrUpdate(recovery))
|
||||
|
||||
result := <-store.PasswordRecovery().Get(recovery.UserId)
|
||||
rrecovery := result.Data.(*model.PasswordRecovery)
|
||||
if rrecovery.Code != recovery.Code {
|
||||
t.Fatal("codes didn't match")
|
||||
}
|
||||
|
||||
result2 := <-store.PasswordRecovery().GetByCode(recovery.Code)
|
||||
rrecovery2 := result2.Data.(*model.PasswordRecovery)
|
||||
if rrecovery2.Code != recovery.Code {
|
||||
t.Fatal("codes didn't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqlPasswordRecoverySaveOrUpdate(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
recovery := &model.PasswordRecovery{UserId: "12345678901234567890123456"}
|
||||
|
||||
if err := (<-store.PasswordRecovery().SaveOrUpdate(recovery)).Err; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// not duplicate, testing update
|
||||
if err := (<-store.PasswordRecovery().SaveOrUpdate(recovery)).Err; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqlPasswordRecoveryDelete(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
recovery := &model.PasswordRecovery{UserId: "12345678901234567890123456"}
|
||||
Must(store.PasswordRecovery().SaveOrUpdate(recovery))
|
||||
|
||||
if err := (<-store.PasswordRecovery().Delete(recovery.UserId)).Err; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ const (
|
||||
EXIT_REMOVE_INDEX_POSTGRES = 121
|
||||
EXIT_REMOVE_INDEX_MYSQL = 122
|
||||
EXIT_REMOVE_INDEX_MISSING = 123
|
||||
EXIT_REMOVE_TABLE = 134
|
||||
)
|
||||
|
||||
type SqlStore struct {
|
||||
@@ -80,7 +81,7 @@ type SqlStore struct {
|
||||
command CommandStore
|
||||
preference PreferenceStore
|
||||
license LicenseStore
|
||||
recovery PasswordRecoveryStore
|
||||
token TokenStore
|
||||
emoji EmojiStore
|
||||
status StatusStore
|
||||
fileInfo FileInfoStore
|
||||
@@ -131,7 +132,7 @@ func NewSqlStore() Store {
|
||||
sqlStore.command = NewSqlCommandStore(sqlStore)
|
||||
sqlStore.preference = NewSqlPreferenceStore(sqlStore)
|
||||
sqlStore.license = NewSqlLicenseStore(sqlStore)
|
||||
sqlStore.recovery = NewSqlPasswordRecoveryStore(sqlStore)
|
||||
sqlStore.token = NewSqlTokenStore(sqlStore)
|
||||
sqlStore.emoji = NewSqlEmojiStore(sqlStore)
|
||||
sqlStore.status = NewSqlStatusStore(sqlStore)
|
||||
sqlStore.fileInfo = NewSqlFileInfoStore(sqlStore)
|
||||
@@ -159,7 +160,7 @@ func NewSqlStore() Store {
|
||||
sqlStore.command.(*SqlCommandStore).CreateIndexesIfNotExists()
|
||||
sqlStore.preference.(*SqlPreferenceStore).CreateIndexesIfNotExists()
|
||||
sqlStore.license.(*SqlLicenseStore).CreateIndexesIfNotExists()
|
||||
sqlStore.recovery.(*SqlPasswordRecoveryStore).CreateIndexesIfNotExists()
|
||||
sqlStore.token.(*SqlTokenStore).CreateIndexesIfNotExists()
|
||||
sqlStore.emoji.(*SqlEmojiStore).CreateIndexesIfNotExists()
|
||||
sqlStore.status.(*SqlStatusStore).CreateIndexesIfNotExists()
|
||||
sqlStore.fileInfo.(*SqlFileInfoStore).CreateIndexesIfNotExists()
|
||||
@@ -388,7 +389,7 @@ func (ss *SqlStore) RemoveColumnIfExists(tableName string, columnName string) bo
|
||||
|
||||
_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
|
||||
if err != nil {
|
||||
l4g.Critical(utils.T("store.sql.drop_column.critical"), err)
|
||||
l4g.Critical("Failed to drop column %v", err)
|
||||
time.Sleep(time.Second)
|
||||
os.Exit(EXIT_REMOVE_COLUMN)
|
||||
}
|
||||
@@ -396,6 +397,21 @@ func (ss *SqlStore) RemoveColumnIfExists(tableName string, columnName string) bo
|
||||
return true
|
||||
}
|
||||
|
||||
func (ss *SqlStore) RemoveTableIfExists(tableName string) bool {
|
||||
if !ss.DoesTableExist(tableName) {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err := ss.GetMaster().Exec("DROP TABLE " + tableName)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to drop table %v", err)
|
||||
time.Sleep(time.Second)
|
||||
os.Exit(EXIT_REMOVE_TABLE)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ss *SqlStore) RenameColumnIfExists(tableName string, oldColumnName string, newColumnName string, colType string) bool {
|
||||
if !ss.DoesColumnExist(tableName, oldColumnName) {
|
||||
return false
|
||||
@@ -667,8 +683,8 @@ func (ss *SqlStore) License() LicenseStore {
|
||||
return ss.license
|
||||
}
|
||||
|
||||
func (ss *SqlStore) PasswordRecovery() PasswordRecoveryStore {
|
||||
return ss.recovery
|
||||
func (ss *SqlStore) Token() TokenStore {
|
||||
return ss.token
|
||||
}
|
||||
|
||||
func (ss *SqlStore) Emoji() EmojiStore {
|
||||
|
||||
108
store/sql_tokens_store.go
Обычный файл
108
store/sql_tokens_store.go
Обычный файл
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
type SqlTokenStore struct {
|
||||
*SqlStore
|
||||
}
|
||||
|
||||
func NewSqlTokenStore(sqlStore *SqlStore) TokenStore {
|
||||
s := &SqlTokenStore{sqlStore}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
table := db.AddTableWithName(model.Token{}, "Tokens").SetKeys(false, "Token")
|
||||
table.ColMap("Type").SetMaxSize(64)
|
||||
table.ColMap("Extra").SetMaxSize(128)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s SqlTokenStore) CreateIndexesIfNotExists() {
|
||||
}
|
||||
|
||||
func (s SqlTokenStore) Save(token *model.Token) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel, 1)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
if result.Err = token.IsValid(); result.Err != nil {
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(token); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlTokenStore.Save", "store.sql_recover.save.app_error", nil, "")
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlTokenStore) Delete(token string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel, 1)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM Tokens WHERE Token = :Token", map[string]interface{}{"Token": token}); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlTokenStore.Delete", "store.sql_recover.delete.app_error", nil, "")
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlTokenStore) GetByToken(tokenString string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel, 1)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
token := model.Token{}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&token, "SELECT * FROM Tokens WHERE Token = :Token", map[string]interface{}{"Token": tokenString}); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
result.Err = model.NewAppError("SqlTokenStore.GetByToken", "store.sql_recover.get_by_code.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlTokenStore.GetByToken", "store.sql_recover.get_by_code.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
result.Data = &token
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlTokenStore) Cleanup() {
|
||||
l4g.Debug("Cleaning up token store.")
|
||||
deltime := model.GetMillis() - model.MAX_TOKEN_EXIPRY_TIME
|
||||
if _, err := s.GetMaster().Exec("DELETE FROM Tokens WHERE CreateAt < :DelTime", map[string]interface{}{"DelTime": deltime}); err != nil {
|
||||
l4g.Error("Unable to cleanup token store.")
|
||||
}
|
||||
}
|
||||
@@ -258,6 +258,7 @@ func UpgradeDatabaseToVersion39(sqlStore *SqlStore) {
|
||||
// TODO: Uncomment following condition when version 3.9.0 is released
|
||||
//if shouldPerformUpgrade(sqlStore, VERSION_3_8_0, VERSION_3_9_0) {
|
||||
sqlStore.CreateColumnIfNotExists("OAuthAccessData", "Scope", "varchar(128)", "varchar(128)", model.DEFAULT_SCOPE)
|
||||
sqlStore.RemoveTableIfExists("PasswordRecovery")
|
||||
|
||||
// saveSchemaVersion(sqlStore, VERSION_3_9_0)
|
||||
//}
|
||||
|
||||
@@ -42,7 +42,7 @@ type Store interface {
|
||||
Command() CommandStore
|
||||
Preference() PreferenceStore
|
||||
License() LicenseStore
|
||||
PasswordRecovery() PasswordRecoveryStore
|
||||
Token() TokenStore
|
||||
Emoji() EmojiStore
|
||||
Status() StatusStore
|
||||
FileInfo() FileInfoStore
|
||||
@@ -322,11 +322,11 @@ type LicenseStore interface {
|
||||
Get(id string) StoreChannel
|
||||
}
|
||||
|
||||
type PasswordRecoveryStore interface {
|
||||
SaveOrUpdate(recovery *model.PasswordRecovery) StoreChannel
|
||||
Delete(userId string) StoreChannel
|
||||
Get(userId string) StoreChannel
|
||||
GetByCode(code string) StoreChannel
|
||||
type TokenStore interface {
|
||||
Save(recovery *model.Token) StoreChannel
|
||||
Delete(token string) StoreChannel
|
||||
GetByToken(token string) StoreChannel
|
||||
Cleanup()
|
||||
}
|
||||
|
||||
type EmojiStore interface {
|
||||
|
||||
Ссылка в новой задаче
Block a user