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