github.com/larkox/mattermost-server@v5.11.1+incompatible/model/bot.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package model
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"strings"
    12  	"unicode/utf8"
    13  )
    14  
    15  const (
    16  	BOT_DISPLAY_NAME_MAX_RUNES = USER_FIRST_NAME_MAX_RUNES
    17  	BOT_DESCRIPTION_MAX_RUNES  = 1024
    18  	BOT_CREATOR_ID_MAX_RUNES   = KEY_VALUE_PLUGIN_ID_MAX_RUNES // UserId or PluginId
    19  )
    20  
    21  // Bot is a special type of User meant for programmatic interactions.
    22  // Note that the primary key of a bot is the UserId, and matches the primary key of the
    23  // corresponding user.
    24  type Bot struct {
    25  	UserId      string `json:"user_id"`
    26  	Username    string `json:"username"`
    27  	DisplayName string `json:"display_name,omitempty"`
    28  	Description string `json:"description,omitempty"`
    29  	OwnerId     string `json:"owner_id"`
    30  	CreateAt    int64  `json:"create_at"`
    31  	UpdateAt    int64  `json:"update_at"`
    32  	DeleteAt    int64  `json:"delete_at"`
    33  }
    34  
    35  // BotPatch is a description of what fields to update on an existing bot.
    36  type BotPatch struct {
    37  	Username    *string `json:"username"`
    38  	DisplayName *string `json:"display_name"`
    39  	Description *string `json:"description"`
    40  }
    41  
    42  // BotGetOptions acts as a filter on bulk bot fetching queries.
    43  type BotGetOptions struct {
    44  	OwnerId        string
    45  	IncludeDeleted bool
    46  	OnlyOrphaned   bool
    47  	Page           int
    48  	PerPage        int
    49  }
    50  
    51  // BotList is a list of bots.
    52  type BotList []*Bot
    53  
    54  // Trace describes the minimum information required to identify a bot for the purpose of logging.
    55  func (b *Bot) Trace() map[string]interface{} {
    56  	return map[string]interface{}{"user_id": b.UserId}
    57  }
    58  
    59  // Clone returns a shallow copy of the bot.
    60  func (b *Bot) Clone() *Bot {
    61  	copy := *b
    62  	return &copy
    63  }
    64  
    65  // IsValid validates the bot and returns an error if it isn't configured correctly.
    66  func (b *Bot) IsValid() *AppError {
    67  	if !IsValidId(b.UserId) {
    68  		return NewAppError("Bot.IsValid", "model.bot.is_valid.user_id.app_error", b.Trace(), "", http.StatusBadRequest)
    69  	}
    70  
    71  	if !IsValidUsername(b.Username) {
    72  		return NewAppError("Bot.IsValid", "model.bot.is_valid.username.app_error", b.Trace(), "", http.StatusBadRequest)
    73  	}
    74  
    75  	if utf8.RuneCountInString(b.DisplayName) > BOT_DISPLAY_NAME_MAX_RUNES {
    76  		return NewAppError("Bot.IsValid", "model.bot.is_valid.user_id.app_error", b.Trace(), "", http.StatusBadRequest)
    77  	}
    78  
    79  	if utf8.RuneCountInString(b.Description) > BOT_DESCRIPTION_MAX_RUNES {
    80  		return NewAppError("Bot.IsValid", "model.bot.is_valid.description.app_error", b.Trace(), "", http.StatusBadRequest)
    81  	}
    82  
    83  	if len(b.OwnerId) == 0 || utf8.RuneCountInString(b.OwnerId) > BOT_CREATOR_ID_MAX_RUNES {
    84  		return NewAppError("Bot.IsValid", "model.bot.is_valid.creator_id.app_error", b.Trace(), "", http.StatusBadRequest)
    85  	}
    86  
    87  	if b.CreateAt == 0 {
    88  		return NewAppError("Bot.IsValid", "model.bot.is_valid.create_at.app_error", b.Trace(), "", http.StatusBadRequest)
    89  	}
    90  
    91  	if b.UpdateAt == 0 {
    92  		return NewAppError("Bot.IsValid", "model.bot.is_valid.update_at.app_error", b.Trace(), "", http.StatusBadRequest)
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  // PreSave should be run before saving a new bot to the database.
    99  func (b *Bot) PreSave() {
   100  	b.CreateAt = GetMillis()
   101  	b.UpdateAt = b.CreateAt
   102  	b.DeleteAt = 0
   103  }
   104  
   105  // PreUpdate should be run before saving an updated bot to the database.
   106  func (b *Bot) PreUpdate() {
   107  	b.UpdateAt = GetMillis()
   108  }
   109  
   110  // Etag generates an etag for caching.
   111  func (b *Bot) Etag() string {
   112  	return Etag(b.UserId, b.UpdateAt)
   113  }
   114  
   115  // ToJson serializes the bot to json.
   116  func (b *Bot) ToJson() []byte {
   117  	data, _ := json.Marshal(b)
   118  	return data
   119  }
   120  
   121  // BotFromJson deserializes a bot from json.
   122  func BotFromJson(data io.Reader) *Bot {
   123  	var bot *Bot
   124  	json.NewDecoder(data).Decode(&bot)
   125  	return bot
   126  }
   127  
   128  // Patch modifies an existing bot with optional fields from the given patch.
   129  func (b *Bot) Patch(patch *BotPatch) {
   130  	if patch.Username != nil {
   131  		b.Username = *patch.Username
   132  	}
   133  
   134  	if patch.DisplayName != nil {
   135  		b.DisplayName = *patch.DisplayName
   136  	}
   137  
   138  	if patch.Description != nil {
   139  		b.Description = *patch.Description
   140  	}
   141  }
   142  
   143  // ToJson serializes the bot patch to json.
   144  func (b *BotPatch) ToJson() []byte {
   145  	data, err := json.Marshal(b)
   146  	if err != nil {
   147  		return nil
   148  	}
   149  
   150  	return data
   151  }
   152  
   153  // BotPatchFromJson deserializes a bot patch from json.
   154  func BotPatchFromJson(data io.Reader) *BotPatch {
   155  	decoder := json.NewDecoder(data)
   156  	var botPatch BotPatch
   157  	err := decoder.Decode(&botPatch)
   158  	if err != nil {
   159  		return nil
   160  	}
   161  
   162  	return &botPatch
   163  }
   164  
   165  // UserFromBot returns a user model describing the bot fields stored in the User store.
   166  func UserFromBot(b *Bot) *User {
   167  	return &User{
   168  		Id:        b.UserId,
   169  		Username:  b.Username,
   170  		Email:     fmt.Sprintf("%s@localhost", strings.ToLower(b.Username)),
   171  		FirstName: b.DisplayName,
   172  	}
   173  }
   174  
   175  // BotListFromJson deserializes a list of bots from json.
   176  func BotListFromJson(data io.Reader) BotList {
   177  	var bots BotList
   178  	json.NewDecoder(data).Decode(&bots)
   179  	return bots
   180  }
   181  
   182  // ToJson serializes a list of bots to json.
   183  func (l *BotList) ToJson() []byte {
   184  	b, _ := json.Marshal(l)
   185  	return b
   186  }
   187  
   188  // Etag computes the etag for a list of bots.
   189  func (l *BotList) Etag() string {
   190  	id := "0"
   191  	var t int64 = 0
   192  	var delta int64 = 0
   193  
   194  	for _, v := range *l {
   195  		if v.UpdateAt > t {
   196  			t = v.UpdateAt
   197  			id = v.UserId
   198  		}
   199  
   200  	}
   201  
   202  	return Etag(id, t, delta, len(*l))
   203  }
   204  
   205  // MakeBotNotFoundError creates the error returned when a bot does not exist, or when the user isn't allowed to query the bot.
   206  // The errors must the same in both cases to avoid leaking that a user is a bot.
   207  func MakeBotNotFoundError(userId string) *AppError {
   208  	return NewAppError("SqlBotStore.Get", "store.sql_bot.get.missing.app_error", map[string]interface{}{"user_id": userId}, "", http.StatusNotFound)
   209  }