github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/model/channel.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package model
     5  
     6  import (
     7  	"crypto/sha1"
     8  	"encoding/hex"
     9  	"encoding/json"
    10  	"io"
    11  	"net/http"
    12  	"sort"
    13  	"strings"
    14  	"unicode/utf8"
    15  )
    16  
    17  const (
    18  	CHANNEL_OPEN                   = "O"
    19  	CHANNEL_PRIVATE                = "P"
    20  	CHANNEL_DIRECT                 = "D"
    21  	CHANNEL_GROUP                  = "G"
    22  	CHANNEL_GROUP_MAX_USERS        = 8
    23  	CHANNEL_GROUP_MIN_USERS        = 3
    24  	DEFAULT_CHANNEL                = "town-square"
    25  	CHANNEL_DISPLAY_NAME_MAX_RUNES = 64
    26  	CHANNEL_NAME_MIN_LENGTH        = 2
    27  	CHANNEL_NAME_MAX_LENGTH        = 64
    28  	CHANNEL_HEADER_MAX_RUNES       = 1024
    29  	CHANNEL_PURPOSE_MAX_RUNES      = 250
    30  	CHANNEL_CACHE_SIZE             = 25000
    31  
    32  	CHANNEL_SORT_BY_USERNAME = "username"
    33  	CHANNEL_SORT_BY_STATUS   = "status"
    34  )
    35  
    36  type Channel struct {
    37  	Id               string                 `json:"id"`
    38  	CreateAt         int64                  `json:"create_at"`
    39  	UpdateAt         int64                  `json:"update_at"`
    40  	DeleteAt         int64                  `json:"delete_at"`
    41  	TeamId           string                 `json:"team_id"`
    42  	Type             string                 `json:"type"`
    43  	DisplayName      string                 `json:"display_name"`
    44  	Name             string                 `json:"name"`
    45  	Header           string                 `json:"header"`
    46  	Purpose          string                 `json:"purpose"`
    47  	LastPostAt       int64                  `json:"last_post_at"`
    48  	TotalMsgCount    int64                  `json:"total_msg_count"`
    49  	ExtraUpdateAt    int64                  `json:"extra_update_at"`
    50  	CreatorId        string                 `json:"creator_id"`
    51  	SchemeId         *string                `json:"scheme_id"`
    52  	Props            map[string]interface{} `json:"props" db:"-"`
    53  	GroupConstrained *bool                  `json:"group_constrained"`
    54  }
    55  
    56  type ChannelWithTeamData struct {
    57  	Channel
    58  	TeamDisplayName string `json:"team_display_name"`
    59  	TeamName        string `json:"team_name"`
    60  	TeamUpdateAt    int64  `json:"team_update_at"`
    61  }
    62  
    63  type ChannelsWithCount struct {
    64  	Channels   *ChannelListWithTeamData `json:"channels"`
    65  	TotalCount int64                    `json:"total_count"`
    66  }
    67  
    68  type ChannelPatch struct {
    69  	DisplayName      *string `json:"display_name"`
    70  	Name             *string `json:"name"`
    71  	Header           *string `json:"header"`
    72  	Purpose          *string `json:"purpose"`
    73  	GroupConstrained *bool   `json:"group_constrained"`
    74  }
    75  
    76  type ChannelForExport struct {
    77  	Channel
    78  	TeamName   string
    79  	SchemeName *string
    80  }
    81  
    82  type DirectChannelForExport struct {
    83  	Channel
    84  	Members *[]string
    85  }
    86  
    87  type ChannelModeration struct {
    88  	Name  string                 `json:"name"`
    89  	Roles *ChannelModeratedRoles `json:"roles"`
    90  }
    91  
    92  type ChannelModeratedRoles struct {
    93  	Guests  *ChannelModeratedRole `json:"guests"`
    94  	Members *ChannelModeratedRole `json:"members"`
    95  }
    96  
    97  type ChannelModeratedRole struct {
    98  	Value   bool `json:"value"`
    99  	Enabled bool `json:"enabled"`
   100  }
   101  
   102  type ChannelModerationPatch struct {
   103  	Name  *string                     `json:"name"`
   104  	Roles *ChannelModeratedRolesPatch `json:"roles"`
   105  }
   106  
   107  type ChannelModeratedRolesPatch struct {
   108  	Guests  *bool `json:"guests"`
   109  	Members *bool `json:"members"`
   110  }
   111  
   112  // ChannelSearchOpts contains options for searching channels.
   113  //
   114  // NotAssociatedToGroup will exclude channels that have associated, active GroupChannels records.
   115  // ExcludeDefaultChannels will exclude the configured default channels (ex 'town-square' and 'off-topic').
   116  // IncludeDeleted will include channel records where DeleteAt != 0.
   117  // ExcludeChannelNames will exclude channels from the results by name.
   118  // Paginate whether to paginate the results.
   119  // Page page requested, if results are paginated.
   120  // PerPage number of results per page, if paginated.
   121  //
   122  type ChannelSearchOpts struct {
   123  	NotAssociatedToGroup    string
   124  	ExcludeDefaultChannels  bool
   125  	IncludeDeleted          bool
   126  	Deleted                 bool
   127  	ExcludeChannelNames     []string
   128  	TeamIds                 []string
   129  	GroupConstrained        bool
   130  	ExcludeGroupConstrained bool
   131  	Public                  bool
   132  	Private                 bool
   133  	Page                    *int
   134  	PerPage                 *int
   135  }
   136  
   137  type ChannelMemberCountByGroup struct {
   138  	GroupId                     string `db:"-" json:"group_id"`
   139  	ChannelMemberCount          int64  `db:"-" json:"channel_member_count"`
   140  	ChannelMemberTimezonesCount int64  `db:"-" json:"channel_member_timezones_count"`
   141  }
   142  
   143  func (o *Channel) DeepCopy() *Channel {
   144  	copy := *o
   145  	if copy.SchemeId != nil {
   146  		copy.SchemeId = NewString(*o.SchemeId)
   147  	}
   148  	return &copy
   149  }
   150  
   151  func (o *Channel) ToJson() string {
   152  	b, _ := json.Marshal(o)
   153  	return string(b)
   154  }
   155  
   156  func (o *ChannelPatch) ToJson() string {
   157  	b, _ := json.Marshal(o)
   158  	return string(b)
   159  }
   160  
   161  func (o *ChannelsWithCount) ToJson() []byte {
   162  	b, _ := json.Marshal(o)
   163  	return b
   164  }
   165  
   166  func ChannelsWithCountFromJson(data io.Reader) *ChannelsWithCount {
   167  	var o *ChannelsWithCount
   168  	json.NewDecoder(data).Decode(&o)
   169  	return o
   170  }
   171  
   172  func ChannelFromJson(data io.Reader) *Channel {
   173  	var o *Channel
   174  	json.NewDecoder(data).Decode(&o)
   175  	return o
   176  }
   177  
   178  func ChannelPatchFromJson(data io.Reader) *ChannelPatch {
   179  	var o *ChannelPatch
   180  	json.NewDecoder(data).Decode(&o)
   181  	return o
   182  }
   183  
   184  func ChannelModerationsFromJson(data io.Reader) []*ChannelModeration {
   185  	var o []*ChannelModeration
   186  	json.NewDecoder(data).Decode(&o)
   187  	return o
   188  }
   189  
   190  func ChannelModerationsPatchFromJson(data io.Reader) []*ChannelModerationPatch {
   191  	var o []*ChannelModerationPatch
   192  	json.NewDecoder(data).Decode(&o)
   193  	return o
   194  }
   195  
   196  func ChannelMemberCountsByGroupFromJson(data io.Reader) []*ChannelMemberCountByGroup {
   197  	var o []*ChannelMemberCountByGroup
   198  	json.NewDecoder(data).Decode(&o)
   199  	return o
   200  }
   201  
   202  func (o *Channel) Etag() string {
   203  	return Etag(o.Id, o.UpdateAt)
   204  }
   205  
   206  func (o *Channel) IsValid() *AppError {
   207  	if !IsValidId(o.Id) {
   208  		return NewAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "", http.StatusBadRequest)
   209  	}
   210  
   211  	if o.CreateAt == 0 {
   212  		return NewAppError("Channel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   213  	}
   214  
   215  	if o.UpdateAt == 0 {
   216  		return NewAppError("Channel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   217  	}
   218  
   219  	if utf8.RuneCountInString(o.DisplayName) > CHANNEL_DISPLAY_NAME_MAX_RUNES {
   220  		return NewAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   221  	}
   222  
   223  	if !IsValidChannelIdentifier(o.Name) {
   224  		return NewAppError("Channel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   225  	}
   226  
   227  	if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP) {
   228  		return NewAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   229  	}
   230  
   231  	if utf8.RuneCountInString(o.Header) > CHANNEL_HEADER_MAX_RUNES {
   232  		return NewAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   233  	}
   234  
   235  	if utf8.RuneCountInString(o.Purpose) > CHANNEL_PURPOSE_MAX_RUNES {
   236  		return NewAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   237  	}
   238  
   239  	if len(o.CreatorId) > 26 {
   240  		return NewAppError("Channel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "", http.StatusBadRequest)
   241  	}
   242  
   243  	userIds := strings.Split(o.Name, "__")
   244  	if o.Type != CHANNEL_DIRECT && len(userIds) == 2 && IsValidId(userIds[0]) && IsValidId(userIds[1]) {
   245  		return NewAppError("Channel.IsValid", "model.channel.is_valid.name.app_error", nil, "", http.StatusBadRequest)
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  func (o *Channel) PreSave() {
   252  	if o.Id == "" {
   253  		o.Id = NewId()
   254  	}
   255  
   256  	o.Name = SanitizeUnicode(o.Name)
   257  	o.DisplayName = SanitizeUnicode(o.DisplayName)
   258  
   259  	o.CreateAt = GetMillis()
   260  	o.UpdateAt = o.CreateAt
   261  	o.ExtraUpdateAt = 0
   262  }
   263  
   264  func (o *Channel) PreUpdate() {
   265  	o.UpdateAt = GetMillis()
   266  	o.Name = SanitizeUnicode(o.Name)
   267  	o.DisplayName = SanitizeUnicode(o.DisplayName)
   268  }
   269  
   270  func (o *Channel) IsGroupOrDirect() bool {
   271  	return o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP
   272  }
   273  
   274  func (o *Channel) IsOpen() bool {
   275  	return o.Type == CHANNEL_OPEN
   276  }
   277  
   278  func (o *Channel) Patch(patch *ChannelPatch) {
   279  	if patch.DisplayName != nil {
   280  		o.DisplayName = *patch.DisplayName
   281  	}
   282  
   283  	if patch.Name != nil {
   284  		o.Name = *patch.Name
   285  	}
   286  
   287  	if patch.Header != nil {
   288  		o.Header = *patch.Header
   289  	}
   290  
   291  	if patch.Purpose != nil {
   292  		o.Purpose = *patch.Purpose
   293  	}
   294  
   295  	if patch.GroupConstrained != nil {
   296  		o.GroupConstrained = patch.GroupConstrained
   297  	}
   298  }
   299  
   300  func (o *Channel) MakeNonNil() {
   301  	if o.Props == nil {
   302  		o.Props = make(map[string]interface{})
   303  	}
   304  }
   305  
   306  func (o *Channel) AddProp(key string, value interface{}) {
   307  	o.MakeNonNil()
   308  
   309  	o.Props[key] = value
   310  }
   311  
   312  func (o *Channel) IsGroupConstrained() bool {
   313  	return o.GroupConstrained != nil && *o.GroupConstrained
   314  }
   315  
   316  func (o *Channel) GetOtherUserIdForDM(userId string) string {
   317  	if o.Type != CHANNEL_DIRECT {
   318  		return ""
   319  	}
   320  
   321  	userIds := strings.Split(o.Name, "__")
   322  
   323  	var otherUserId string
   324  
   325  	if userIds[0] != userIds[1] {
   326  		if userIds[0] == userId {
   327  			otherUserId = userIds[1]
   328  		} else {
   329  			otherUserId = userIds[0]
   330  		}
   331  	}
   332  
   333  	return otherUserId
   334  }
   335  
   336  func GetDMNameFromIds(userId1, userId2 string) string {
   337  	if userId1 > userId2 {
   338  		return userId2 + "__" + userId1
   339  	} else {
   340  		return userId1 + "__" + userId2
   341  	}
   342  }
   343  
   344  func GetGroupDisplayNameFromUsers(users []*User, truncate bool) string {
   345  	usernames := make([]string, len(users))
   346  	for index, user := range users {
   347  		usernames[index] = user.Username
   348  	}
   349  
   350  	sort.Strings(usernames)
   351  
   352  	name := strings.Join(usernames, ", ")
   353  
   354  	if truncate && len(name) > CHANNEL_NAME_MAX_LENGTH {
   355  		name = name[:CHANNEL_NAME_MAX_LENGTH]
   356  	}
   357  
   358  	return name
   359  }
   360  
   361  func GetGroupNameFromUserIds(userIds []string) string {
   362  	sort.Strings(userIds)
   363  
   364  	h := sha1.New()
   365  	for _, id := range userIds {
   366  		io.WriteString(h, id)
   367  	}
   368  
   369  	return hex.EncodeToString(h.Sum(nil))
   370  }