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 © 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 }