github.com/teloshs/mattermost-server@v5.11.1+incompatible/store/sqlstore/bot_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  	"database/sql"
     8  	"net/http"
     9  	"strings"
    10  
    11  	"github.com/mattermost/mattermost-server/einterfaces"
    12  	"github.com/mattermost/mattermost-server/model"
    13  	"github.com/mattermost/mattermost-server/store"
    14  )
    15  
    16  // bot is a subset of the model.Bot type, omitting the model.User fields.
    17  type bot struct {
    18  	UserId      string `json:"user_id"`
    19  	Description string `json:"description"`
    20  	OwnerId     string `json:"owner_id"`
    21  	CreateAt    int64  `json:"create_at"`
    22  	UpdateAt    int64  `json:"update_at"`
    23  	DeleteAt    int64  `json:"delete_at"`
    24  }
    25  
    26  func botFromModel(b *model.Bot) *bot {
    27  	return &bot{
    28  		UserId:      b.UserId,
    29  		Description: b.Description,
    30  		OwnerId:     b.OwnerId,
    31  		CreateAt:    b.CreateAt,
    32  		UpdateAt:    b.UpdateAt,
    33  		DeleteAt:    b.DeleteAt,
    34  	}
    35  }
    36  
    37  // SqlBotStore is a store for managing bots in the database.
    38  // Bots are otherwise normal users with extra metadata record in the Bots table. The primary key
    39  // for a bot matches the primary key value for corresponding User record.
    40  type SqlBotStore struct {
    41  	SqlStore
    42  	metrics einterfaces.MetricsInterface
    43  }
    44  
    45  // NewSqlBotStore creates an instance of SqlBotStore, registering the table schema in question.
    46  func NewSqlBotStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.BotStore {
    47  	us := &SqlBotStore{
    48  		SqlStore: sqlStore,
    49  		metrics:  metrics,
    50  	}
    51  
    52  	for _, db := range sqlStore.GetAllConns() {
    53  		table := db.AddTableWithName(bot{}, "Bots").SetKeys(false, "UserId")
    54  		table.ColMap("UserId").SetMaxSize(26)
    55  		table.ColMap("Description").SetMaxSize(1024)
    56  		table.ColMap("OwnerId").SetMaxSize(model.BOT_CREATOR_ID_MAX_RUNES)
    57  	}
    58  
    59  	return us
    60  }
    61  
    62  func (us SqlBotStore) CreateIndexesIfNotExists() {
    63  }
    64  
    65  // traceBot is a helper function for adding to a bot trace when logging.
    66  func traceBot(bot *model.Bot, extra map[string]interface{}) map[string]interface{} {
    67  	trace := make(map[string]interface{})
    68  	for key, value := range bot.Trace() {
    69  		trace[key] = value
    70  	}
    71  	for key, value := range extra {
    72  		trace[key] = value
    73  	}
    74  
    75  	return trace
    76  }
    77  
    78  // Get fetches the given bot in the database.
    79  func (us SqlBotStore) Get(botUserId string, includeDeleted bool) store.StoreChannel {
    80  	return store.Do(func(result *store.StoreResult) {
    81  		var excludeDeletedSql = "AND b.DeleteAt = 0"
    82  		if includeDeleted {
    83  			excludeDeletedSql = ""
    84  		}
    85  
    86  		var bot *model.Bot
    87  		if err := us.GetReplica().SelectOne(&bot, `
    88  			SELECT
    89  			    b.UserId,
    90  			    u.Username,
    91  			    u.FirstName AS DisplayName,
    92  			    b.Description,
    93  			    b.OwnerId,
    94  			    b.CreateAt,
    95  			    b.UpdateAt,
    96  			    b.DeleteAt
    97  			FROM
    98  			    Bots b
    99  			JOIN
   100  			    Users u ON (u.Id = b.UserId)
   101  			WHERE
   102  			    b.UserId = :user_id
   103  			    `+excludeDeletedSql+`
   104  		`, map[string]interface{}{
   105  			"user_id": botUserId,
   106  		}); err == sql.ErrNoRows {
   107  			result.Err = model.MakeBotNotFoundError(botUserId)
   108  		} else if err != nil {
   109  			result.Err = model.NewAppError("SqlBotStore.Get", "store.sql_bot.get.app_error", map[string]interface{}{"user_id": botUserId}, err.Error(), http.StatusInternalServerError)
   110  		} else {
   111  			result.Data = bot
   112  		}
   113  	})
   114  }
   115  
   116  // GetAll fetches from all bots in the database.
   117  func (us SqlBotStore) GetAll(options *model.BotGetOptions) store.StoreChannel {
   118  	return store.Do(func(result *store.StoreResult) {
   119  		params := map[string]interface{}{
   120  			"offset": options.Page * options.PerPage,
   121  			"limit":  options.PerPage,
   122  		}
   123  
   124  		var conditions []string
   125  		var conditionsSql string
   126  		var additionalJoin string
   127  
   128  		if !options.IncludeDeleted {
   129  			conditions = append(conditions, "b.DeleteAt = 0")
   130  		}
   131  		if options.OwnerId != "" {
   132  			conditions = append(conditions, "b.OwnerId = :creator_id")
   133  			params["creator_id"] = options.OwnerId
   134  		}
   135  		if options.OnlyOrphaned {
   136  			additionalJoin = "JOIN Users o ON (o.Id = b.OwnerId)"
   137  			conditions = append(conditions, "o.DeleteAt != 0")
   138  		}
   139  
   140  		if len(conditions) > 0 {
   141  			conditionsSql = "WHERE " + strings.Join(conditions, " AND ")
   142  		}
   143  
   144  		sql := `
   145  			SELECT
   146  			    b.UserId,
   147  			    u.Username,
   148  			    u.FirstName AS DisplayName,
   149  			    b.Description,
   150  			    b.OwnerId,
   151  			    b.CreateAt,
   152  			    b.UpdateAt,
   153  			    b.DeleteAt
   154  			FROM
   155  			    Bots b
   156  			JOIN
   157  			    Users u ON (u.Id = b.UserId)
   158  			` + additionalJoin + `
   159  			` + conditionsSql + `
   160  			ORDER BY
   161  			    b.CreateAt ASC,
   162  			    u.Username ASC
   163  			LIMIT
   164  			    :limit
   165  			OFFSET
   166  			    :offset
   167  		`
   168  
   169  		var data []*model.Bot
   170  		if _, err := us.GetReplica().Select(&data, sql, params); err != nil {
   171  			result.Err = model.NewAppError("SqlBotStore.GetAll", "store.sql_bot.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   172  		}
   173  
   174  		result.Data = data
   175  	})
   176  }
   177  
   178  // Save persists a new bot to the database.
   179  // It assumes the corresponding user was saved via the user store.
   180  func (us SqlBotStore) Save(bot *model.Bot) store.StoreChannel {
   181  	bot = bot.Clone()
   182  
   183  	return store.Do(func(result *store.StoreResult) {
   184  		bot.PreSave()
   185  		if result.Err = bot.IsValid(); result.Err != nil {
   186  			return
   187  		}
   188  
   189  		if err := us.GetMaster().Insert(botFromModel(bot)); err != nil {
   190  			result.Err = model.NewAppError("SqlBotStore.Save", "store.sql_bot.save.app_error", bot.Trace(), err.Error(), http.StatusInternalServerError)
   191  			return
   192  		}
   193  
   194  		result.Data = bot
   195  	})
   196  }
   197  
   198  // Update persists an updated bot to the database.
   199  // It assumes the corresponding user was updated via the user store.
   200  func (us SqlBotStore) Update(bot *model.Bot) store.StoreChannel {
   201  	bot = bot.Clone()
   202  
   203  	return store.Do(func(result *store.StoreResult) {
   204  		bot.PreUpdate()
   205  		if result.Err = bot.IsValid(); result.Err != nil {
   206  			return
   207  		}
   208  
   209  		oldBotResult := <-us.Get(bot.UserId, true)
   210  		if oldBotResult.Err != nil {
   211  			result.Err = oldBotResult.Err
   212  			return
   213  		}
   214  		oldBot := oldBotResult.Data.(*model.Bot)
   215  
   216  		oldBot.Description = bot.Description
   217  		oldBot.OwnerId = bot.OwnerId
   218  		oldBot.UpdateAt = bot.UpdateAt
   219  		oldBot.DeleteAt = bot.DeleteAt
   220  		bot = oldBot
   221  
   222  		if count, err := us.GetMaster().Update(botFromModel(bot)); err != nil {
   223  			result.Err = model.NewAppError("SqlBotStore.Update", "store.sql_bot.update.updating.app_error", bot.Trace(), err.Error(), http.StatusInternalServerError)
   224  		} else if count != 1 {
   225  			result.Err = model.NewAppError("SqlBotStore.Update", "store.sql_bot.update.app_error", traceBot(bot, map[string]interface{}{"count": count}), "", http.StatusInternalServerError)
   226  		}
   227  
   228  		result.Data = bot
   229  	})
   230  }
   231  
   232  // PermanentDelete removes the bot from the database altogether.
   233  // If the corresponding user is to be deleted, it must be done via the user store.
   234  func (us SqlBotStore) PermanentDelete(botUserId string) store.StoreChannel {
   235  	return store.Do(func(result *store.StoreResult) {
   236  		userResult := <-us.User().PermanentDelete(botUserId)
   237  		if userResult.Err != nil {
   238  			result.Err = userResult.Err
   239  			return
   240  		}
   241  
   242  		if _, err := us.GetMaster().Exec(`
   243  			DELETE FROM
   244  			    Bots
   245  			WHERE
   246  			    UserId = :user_id
   247  		`, map[string]interface{}{
   248  			"user_id": botUserId,
   249  		}); err != nil {
   250  			result.Err = model.NewAppError("SqlBotStore.Update", "store.sql_bot.delete.app_error", map[string]interface{}{"user_id": botUserId}, err.Error(), http.StatusBadRequest)
   251  		}
   252  	})
   253  }