Update mattermost library (#2152)
* Update mattermost library * Fix linting
This commit is contained in:
202
vendor/github.com/mattermost/mattermost/server/public/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/mattermost/mattermost/server/public/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
71
vendor/github.com/mattermost/mattermost/server/public/model/access.go
generated
vendored
Normal file
71
vendor/github.com/mattermost/mattermost/server/public/model/access.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
AccessTokenGrantType = "authorization_code"
|
||||
AccessTokenType = "bearer"
|
||||
RefreshTokenGrantType = "refresh_token"
|
||||
)
|
||||
|
||||
type AccessData struct {
|
||||
ClientId string `json:"client_id"`
|
||||
UserId string `json:"user_id"`
|
||||
Token string `json:"token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
RedirectUri string `json:"redirect_uri"`
|
||||
ExpiresAt int64 `json:"expires_at"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
type AccessResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresInSeconds int32 `json:"expires_in"`
|
||||
Scope string `json:"scope"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
IdToken string `json:"id_token"`
|
||||
}
|
||||
|
||||
// IsValid validates the AccessData and returns an error if it isn't configured
|
||||
// correctly.
|
||||
func (ad *AccessData) IsValid() *AppError {
|
||||
if ad.ClientId == "" || len(ad.ClientId) > 26 {
|
||||
return NewAppError("AccessData.IsValid", "model.access.is_valid.client_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if ad.UserId == "" || len(ad.UserId) > 26 {
|
||||
return NewAppError("AccessData.IsValid", "model.access.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(ad.Token) != 26 {
|
||||
return NewAppError("AccessData.IsValid", "model.access.is_valid.access_token.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(ad.RefreshToken) > 26 {
|
||||
return NewAppError("AccessData.IsValid", "model.access.is_valid.refresh_token.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if ad.RedirectUri == "" || len(ad.RedirectUri) > 256 || !IsValidHTTPURL(ad.RedirectUri) {
|
||||
return NewAppError("AccessData.IsValid", "model.access.is_valid.redirect_uri.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ad *AccessData) IsExpired() bool {
|
||||
if ad.ExpiresAt <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if GetMillis() > ad.ExpiresAt {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
11
vendor/github.com/mattermost/mattermost/server/public/model/analytics_row.go
generated
vendored
Normal file
11
vendor/github.com/mattermost/mattermost/server/public/model/analytics_row.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type AnalyticsRow struct {
|
||||
Name string `json:"name"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
type AnalyticsRows []*AnalyticsRow
|
||||
14
vendor/github.com/mattermost/mattermost/server/public/model/audit.go
generated
vendored
Normal file
14
vendor/github.com/mattermost/mattermost/server/public/model/audit.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type Audit struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UserId string `json:"user_id"`
|
||||
Action string `json:"action"`
|
||||
ExtraInfo string `json:"extra_info"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
SessionId string `json:"session_id"`
|
||||
}
|
||||
777
vendor/github.com/mattermost/mattermost/server/public/model/auditconv.go
generated
vendored
Normal file
777
vendor/github.com/mattermost/mattermost/server/public/model/auditconv.go
generated
vendored
Normal file
@@ -0,0 +1,777 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
)
|
||||
|
||||
// AuditModelTypeConv converts key model types to something better suited for audit output.
|
||||
func AuditModelTypeConv(val any) (newVal any, converted bool) {
|
||||
if val == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := val.(type) {
|
||||
case *Channel:
|
||||
return newAuditChannel(v), true
|
||||
case Channel:
|
||||
return newAuditChannel(&v), true
|
||||
case *Team:
|
||||
return newAuditTeam(v), true
|
||||
case Team:
|
||||
return newAuditTeam(&v), true
|
||||
case *User:
|
||||
return newAuditUser(v), true
|
||||
case User:
|
||||
return newAuditUser(&v), true
|
||||
case *UserPatch:
|
||||
return newAuditUserPatch(v), true
|
||||
case UserPatch:
|
||||
return newAuditUserPatch(&v), true
|
||||
case *Command:
|
||||
return newAuditCommand(v), true
|
||||
case Command:
|
||||
return newAuditCommand(&v), true
|
||||
case *CommandArgs:
|
||||
return newAuditCommandArgs(v), true
|
||||
case CommandArgs:
|
||||
return newAuditCommandArgs(&v), true
|
||||
case *Bot:
|
||||
return newAuditBot(v), true
|
||||
case Bot:
|
||||
return newAuditBot(&v), true
|
||||
case *ChannelModerationPatch:
|
||||
return newAuditChannelModerationPatch(v), true
|
||||
case ChannelModerationPatch:
|
||||
return newAuditChannelModerationPatch(&v), true
|
||||
case *Emoji:
|
||||
return newAuditEmoji(v), true
|
||||
case Emoji:
|
||||
return newAuditEmoji(&v), true
|
||||
case *FileInfo:
|
||||
return newAuditFileInfo(v), true
|
||||
case FileInfo:
|
||||
return newAuditFileInfo(&v), true
|
||||
case *Group:
|
||||
return newAuditGroup(v), true
|
||||
case Group:
|
||||
return newAuditGroup(&v), true
|
||||
case *Job:
|
||||
return newAuditJob(v), true
|
||||
case Job:
|
||||
return newAuditJob(&v), true
|
||||
case *OAuthApp:
|
||||
return newAuditOAuthApp(v), true
|
||||
case OAuthApp:
|
||||
return newAuditOAuthApp(&v), true
|
||||
case *Post:
|
||||
return newAuditPost(v), true
|
||||
case Post:
|
||||
return newAuditPost(&v), true
|
||||
case *Role:
|
||||
return newAuditRole(v), true
|
||||
case Role:
|
||||
return newAuditRole(&v), true
|
||||
case *Scheme:
|
||||
return newAuditScheme(v), true
|
||||
case Scheme:
|
||||
return newAuditScheme(&v), true
|
||||
case *SchemeRoles:
|
||||
return newAuditSchemeRoles(v), true
|
||||
case SchemeRoles:
|
||||
return newAuditSchemeRoles(&v), true
|
||||
case *Session:
|
||||
return newAuditSession(v), true
|
||||
case Session:
|
||||
return newAuditSession(&v), true
|
||||
case *IncomingWebhook:
|
||||
return newAuditIncomingWebhook(v), true
|
||||
case IncomingWebhook:
|
||||
return newAuditIncomingWebhook(&v), true
|
||||
case *OutgoingWebhook:
|
||||
return newAuditOutgoingWebhook(v), true
|
||||
case OutgoingWebhook:
|
||||
return newAuditOutgoingWebhook(&v), true
|
||||
case *RemoteCluster:
|
||||
return newRemoteCluster(v), true
|
||||
case RemoteCluster:
|
||||
return newRemoteCluster(&v), true
|
||||
}
|
||||
return val, false
|
||||
}
|
||||
|
||||
type auditChannel struct {
|
||||
ID string
|
||||
Name string
|
||||
Type ChannelType
|
||||
}
|
||||
|
||||
// newAuditChannel creates a simplified representation of Channel for output to audit log.
|
||||
func newAuditChannel(c *Channel) auditChannel {
|
||||
var channel auditChannel
|
||||
if c != nil {
|
||||
channel.ID = c.Id
|
||||
channel.Name = c.Name
|
||||
channel.Type = c.Type
|
||||
}
|
||||
return channel
|
||||
}
|
||||
|
||||
func (c auditChannel) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", c.ID)
|
||||
enc.StringKey("name", c.Name)
|
||||
enc.StringKey("type", string(c.Type))
|
||||
}
|
||||
|
||||
func (c auditChannel) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditTeam struct {
|
||||
ID string
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
// newAuditTeam creates a simplified representation of Team for output to audit log.
|
||||
func newAuditTeam(t *Team) auditTeam {
|
||||
var team auditTeam
|
||||
if t != nil {
|
||||
team.ID = t.Id
|
||||
team.Name = t.Name
|
||||
team.Type = t.Type
|
||||
}
|
||||
return team
|
||||
}
|
||||
|
||||
func (t auditTeam) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", t.ID)
|
||||
enc.StringKey("name", t.Name)
|
||||
enc.StringKey("type", t.Type)
|
||||
}
|
||||
|
||||
func (t auditTeam) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditUser struct {
|
||||
ID string
|
||||
Name string
|
||||
Roles string
|
||||
}
|
||||
|
||||
// newAuditUser creates a simplified representation of User for output to audit log.
|
||||
func newAuditUser(u *User) auditUser {
|
||||
var user auditUser
|
||||
if u != nil {
|
||||
user.ID = u.Id
|
||||
user.Name = u.Username
|
||||
user.Roles = u.Roles
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
type auditUserPatch struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// newAuditUserPatch creates a simplified representation of UserPatch for output to audit log.
|
||||
func newAuditUserPatch(up *UserPatch) auditUserPatch {
|
||||
var userPatch auditUserPatch
|
||||
if up != nil {
|
||||
if up.Username != nil {
|
||||
userPatch.Name = *up.Username
|
||||
}
|
||||
}
|
||||
return userPatch
|
||||
}
|
||||
|
||||
func (u auditUser) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", u.ID)
|
||||
enc.StringKey("name", u.Name)
|
||||
enc.StringKey("roles", u.Roles)
|
||||
}
|
||||
|
||||
func (u auditUser) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditCommand struct {
|
||||
ID string
|
||||
CreatorID string
|
||||
TeamID string
|
||||
Trigger string
|
||||
Method string
|
||||
Username string
|
||||
IconURL string
|
||||
AutoComplete bool
|
||||
AutoCompleteDesc string
|
||||
AutoCompleteHint string
|
||||
DisplayName string
|
||||
Description string
|
||||
URL string
|
||||
}
|
||||
|
||||
// newAuditCommand creates a simplified representation of Command for output to audit log.
|
||||
func newAuditCommand(c *Command) auditCommand {
|
||||
var cmd auditCommand
|
||||
if c != nil {
|
||||
cmd.ID = c.Id
|
||||
cmd.CreatorID = c.CreatorId
|
||||
cmd.TeamID = c.TeamId
|
||||
cmd.Trigger = c.Trigger
|
||||
cmd.Method = c.Method
|
||||
cmd.Username = c.Username
|
||||
cmd.IconURL = c.IconURL
|
||||
cmd.AutoComplete = c.AutoComplete
|
||||
cmd.AutoCompleteDesc = c.AutoCompleteDesc
|
||||
cmd.AutoCompleteHint = c.AutoCompleteHint
|
||||
cmd.DisplayName = c.DisplayName
|
||||
cmd.Description = c.Description
|
||||
cmd.URL = c.URL
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (cmd auditCommand) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", cmd.ID)
|
||||
enc.StringKey("creator_id", cmd.CreatorID)
|
||||
enc.StringKey("team_id", cmd.TeamID)
|
||||
enc.StringKey("trigger", cmd.Trigger)
|
||||
enc.StringKey("method", cmd.Method)
|
||||
enc.StringKey("username", cmd.Username)
|
||||
enc.StringKey("icon_url", cmd.IconURL)
|
||||
enc.BoolKey("auto_complete", cmd.AutoComplete)
|
||||
enc.StringKey("auto_complete_desc", cmd.AutoCompleteDesc)
|
||||
enc.StringKey("auto_complete_hint", cmd.AutoCompleteHint)
|
||||
enc.StringKey("display", cmd.DisplayName)
|
||||
enc.StringKey("desc", cmd.Description)
|
||||
enc.StringKey("url", cmd.URL)
|
||||
}
|
||||
|
||||
func (cmd auditCommand) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditCommandArgs struct {
|
||||
ChannelID string
|
||||
TeamID string
|
||||
TriggerID string
|
||||
Command string
|
||||
}
|
||||
|
||||
// newAuditCommandArgs creates a simplified representation of CommandArgs for output to audit log.
|
||||
func newAuditCommandArgs(ca *CommandArgs) auditCommandArgs {
|
||||
var cmdargs auditCommandArgs
|
||||
if ca != nil {
|
||||
cmdargs.ChannelID = ca.ChannelId
|
||||
cmdargs.TeamID = ca.TeamId
|
||||
cmdargs.TriggerID = ca.TriggerId
|
||||
cmdFields := strings.Fields(ca.Command)
|
||||
if len(cmdFields) > 0 {
|
||||
cmdargs.Command = cmdFields[0]
|
||||
}
|
||||
}
|
||||
return cmdargs
|
||||
}
|
||||
|
||||
func (ca auditCommandArgs) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("channel_id", ca.ChannelID)
|
||||
enc.StringKey("team_id", ca.TriggerID)
|
||||
enc.StringKey("trigger_id", ca.TeamID)
|
||||
enc.StringKey("command", ca.Command)
|
||||
}
|
||||
|
||||
func (ca auditCommandArgs) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditBot struct {
|
||||
UserID string
|
||||
Username string
|
||||
Displayname string
|
||||
}
|
||||
|
||||
// newAuditBot creates a simplified representation of Bot for output to audit log.
|
||||
func newAuditBot(b *Bot) auditBot {
|
||||
var bot auditBot
|
||||
if b != nil {
|
||||
bot.UserID = b.UserId
|
||||
bot.Username = b.Username
|
||||
bot.Displayname = b.DisplayName
|
||||
}
|
||||
return bot
|
||||
}
|
||||
|
||||
func (b auditBot) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("user_id", b.UserID)
|
||||
enc.StringKey("username", b.Username)
|
||||
enc.StringKey("display", b.Displayname)
|
||||
}
|
||||
|
||||
func (b auditBot) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditChannelModerationPatch struct {
|
||||
Name string
|
||||
RoleGuests bool
|
||||
RoleMembers bool
|
||||
}
|
||||
|
||||
// newAuditChannelModerationPatch creates a simplified representation of ChannelModerationPatch for output to audit log.
|
||||
func newAuditChannelModerationPatch(p *ChannelModerationPatch) auditChannelModerationPatch {
|
||||
var patch auditChannelModerationPatch
|
||||
if p != nil {
|
||||
if p.Name != nil {
|
||||
patch.Name = *p.Name
|
||||
}
|
||||
if p.Roles.Guests != nil {
|
||||
patch.RoleGuests = *p.Roles.Guests
|
||||
}
|
||||
if p.Roles.Members != nil {
|
||||
patch.RoleMembers = *p.Roles.Members
|
||||
}
|
||||
}
|
||||
return patch
|
||||
}
|
||||
|
||||
func (p auditChannelModerationPatch) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("name", p.Name)
|
||||
enc.BoolKey("role_guests", p.RoleGuests)
|
||||
enc.BoolKey("role_members", p.RoleMembers)
|
||||
}
|
||||
|
||||
func (p auditChannelModerationPatch) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditEmoji struct {
|
||||
ID string
|
||||
Name string
|
||||
}
|
||||
|
||||
// newAuditEmoji creates a simplified representation of Emoji for output to audit log.
|
||||
func newAuditEmoji(e *Emoji) auditEmoji {
|
||||
var emoji auditEmoji
|
||||
if e != nil {
|
||||
emoji.ID = e.Id
|
||||
emoji.Name = e.Name
|
||||
}
|
||||
return emoji
|
||||
}
|
||||
|
||||
func (e auditEmoji) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", e.ID)
|
||||
enc.StringKey("name", e.Name)
|
||||
}
|
||||
|
||||
func (e auditEmoji) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditFileInfo struct {
|
||||
ID string
|
||||
PostID string
|
||||
Path string
|
||||
Name string
|
||||
Extension string
|
||||
Size int64
|
||||
}
|
||||
|
||||
// newAuditFileInfo creates a simplified representation of FileInfo for output to audit log.
|
||||
func newAuditFileInfo(f *FileInfo) auditFileInfo {
|
||||
var fi auditFileInfo
|
||||
if f != nil {
|
||||
fi.ID = f.Id
|
||||
fi.PostID = f.PostId
|
||||
fi.Path = f.Path
|
||||
fi.Name = f.Name
|
||||
fi.Extension = f.Extension
|
||||
fi.Size = f.Size
|
||||
}
|
||||
return fi
|
||||
}
|
||||
|
||||
func (fi auditFileInfo) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", fi.ID)
|
||||
enc.StringKey("post_id", fi.PostID)
|
||||
enc.StringKey("path", fi.Path)
|
||||
enc.StringKey("name", fi.Name)
|
||||
enc.StringKey("ext", fi.Extension)
|
||||
enc.Int64Key("size", fi.Size)
|
||||
}
|
||||
|
||||
func (fi auditFileInfo) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditGroup struct {
|
||||
ID string
|
||||
Name string
|
||||
DisplayName string
|
||||
Description string
|
||||
}
|
||||
|
||||
// newAuditGroup creates a simplified representation of Group for output to audit log.
|
||||
func newAuditGroup(g *Group) auditGroup {
|
||||
var group auditGroup
|
||||
if g != nil {
|
||||
group.ID = g.Id
|
||||
if g.Name == nil {
|
||||
group.Name = ""
|
||||
} else {
|
||||
group.Name = *g.Name
|
||||
}
|
||||
group.DisplayName = g.DisplayName
|
||||
group.Description = g.Description
|
||||
}
|
||||
return group
|
||||
}
|
||||
|
||||
func (g auditGroup) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", g.ID)
|
||||
enc.StringKey("name", g.Name)
|
||||
enc.StringKey("display", g.DisplayName)
|
||||
enc.StringKey("desc", g.Description)
|
||||
}
|
||||
|
||||
func (g auditGroup) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditJob struct {
|
||||
ID string
|
||||
Type string
|
||||
Priority int64
|
||||
StartAt int64
|
||||
}
|
||||
|
||||
// newAuditJob creates a simplified representation of Job for output to audit log.
|
||||
func newAuditJob(j *Job) auditJob {
|
||||
var job auditJob
|
||||
if j != nil {
|
||||
job.ID = j.Id
|
||||
job.Type = j.Type
|
||||
job.Priority = j.Priority
|
||||
job.StartAt = j.StartAt
|
||||
}
|
||||
return job
|
||||
}
|
||||
|
||||
func (j auditJob) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", j.ID)
|
||||
enc.StringKey("type", j.Type)
|
||||
enc.Int64Key("priority", j.Priority)
|
||||
enc.Int64Key("start_at", j.StartAt)
|
||||
}
|
||||
|
||||
func (j auditJob) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditOAuthApp struct {
|
||||
ID string
|
||||
CreatorID string
|
||||
Name string
|
||||
Description string
|
||||
IsTrusted bool
|
||||
}
|
||||
|
||||
// newAuditOAuthApp creates a simplified representation of OAuthApp for output to audit log.
|
||||
func newAuditOAuthApp(o *OAuthApp) auditOAuthApp {
|
||||
var oauth auditOAuthApp
|
||||
if o != nil {
|
||||
oauth.ID = o.Id
|
||||
oauth.CreatorID = o.CreatorId
|
||||
oauth.Name = o.Name
|
||||
oauth.Description = o.Description
|
||||
oauth.IsTrusted = o.IsTrusted
|
||||
}
|
||||
return oauth
|
||||
}
|
||||
|
||||
func (o auditOAuthApp) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", o.ID)
|
||||
enc.StringKey("creator_id", o.CreatorID)
|
||||
enc.StringKey("name", o.Name)
|
||||
enc.StringKey("desc", o.Description)
|
||||
enc.BoolKey("trusted", o.IsTrusted)
|
||||
}
|
||||
|
||||
func (o auditOAuthApp) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditPost struct {
|
||||
ID string
|
||||
ChannelID string
|
||||
Type string
|
||||
IsPinned bool
|
||||
}
|
||||
|
||||
// newAuditPost creates a simplified representation of Post for output to audit log.
|
||||
func newAuditPost(p *Post) auditPost {
|
||||
var post auditPost
|
||||
if p != nil {
|
||||
post.ID = p.Id
|
||||
post.ChannelID = p.ChannelId
|
||||
post.Type = p.Type
|
||||
post.IsPinned = p.IsPinned
|
||||
}
|
||||
return post
|
||||
}
|
||||
|
||||
func (p auditPost) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", p.ID)
|
||||
enc.StringKey("channel_id", p.ChannelID)
|
||||
enc.StringKey("type", p.Type)
|
||||
enc.BoolKey("pinned", p.IsPinned)
|
||||
}
|
||||
|
||||
func (p auditPost) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditRole struct {
|
||||
ID string
|
||||
Name string
|
||||
DisplayName string
|
||||
Permissions []string
|
||||
SchemeManaged bool
|
||||
BuiltIn bool
|
||||
}
|
||||
|
||||
// newAuditRole creates a simplified representation of Role for output to audit log.
|
||||
func newAuditRole(r *Role) auditRole {
|
||||
var role auditRole
|
||||
if r != nil {
|
||||
role.ID = r.Id
|
||||
role.Name = r.Name
|
||||
role.DisplayName = r.DisplayName
|
||||
role.Permissions = append(role.Permissions, r.Permissions...)
|
||||
role.SchemeManaged = r.SchemeManaged
|
||||
role.BuiltIn = r.BuiltIn
|
||||
}
|
||||
return role
|
||||
}
|
||||
|
||||
func (r auditRole) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", r.ID)
|
||||
enc.StringKey("name", r.Name)
|
||||
enc.StringKey("display", r.DisplayName)
|
||||
enc.SliceStringKey("perms", r.Permissions)
|
||||
enc.BoolKey("schemeManaged", r.SchemeManaged)
|
||||
enc.BoolKey("builtin", r.BuiltIn)
|
||||
}
|
||||
|
||||
func (r auditRole) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditScheme struct {
|
||||
ID string
|
||||
Name string
|
||||
DisplayName string
|
||||
Scope string
|
||||
}
|
||||
|
||||
// newAuditScheme creates a simplified representation of Scheme for output to audit log.
|
||||
func newAuditScheme(s *Scheme) auditScheme {
|
||||
var scheme auditScheme
|
||||
if s != nil {
|
||||
scheme.ID = s.Id
|
||||
scheme.Name = s.Name
|
||||
scheme.DisplayName = s.DisplayName
|
||||
scheme.Scope = s.Scope
|
||||
}
|
||||
return scheme
|
||||
}
|
||||
|
||||
func (s auditScheme) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", s.ID)
|
||||
enc.StringKey("name", s.Name)
|
||||
enc.StringKey("display", s.DisplayName)
|
||||
enc.StringKey("scope", s.Scope)
|
||||
}
|
||||
|
||||
func (s auditScheme) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditSchemeRoles struct {
|
||||
SchemeAdmin bool
|
||||
SchemeUser bool
|
||||
SchemeGuest bool
|
||||
}
|
||||
|
||||
// newAuditSchemeRoles creates a simplified representation of SchemeRoles for output to audit log.
|
||||
func newAuditSchemeRoles(s *SchemeRoles) auditSchemeRoles {
|
||||
var roles auditSchemeRoles
|
||||
if s != nil {
|
||||
roles.SchemeAdmin = s.SchemeAdmin
|
||||
roles.SchemeUser = s.SchemeUser
|
||||
roles.SchemeGuest = s.SchemeGuest
|
||||
}
|
||||
return roles
|
||||
}
|
||||
|
||||
func (s auditSchemeRoles) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.BoolKey("admin", s.SchemeAdmin)
|
||||
enc.BoolKey("user", s.SchemeUser)
|
||||
enc.BoolKey("guest", s.SchemeGuest)
|
||||
}
|
||||
|
||||
func (s auditSchemeRoles) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditSession struct {
|
||||
ID string
|
||||
UserId string
|
||||
DeviceId string
|
||||
}
|
||||
|
||||
// newAuditSession creates a simplified representation of Session for output to audit log.
|
||||
func newAuditSession(s *Session) auditSession {
|
||||
var session auditSession
|
||||
if s != nil {
|
||||
session.ID = s.Id
|
||||
session.UserId = s.UserId
|
||||
session.DeviceId = s.DeviceId
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
func (s auditSession) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", s.ID)
|
||||
enc.StringKey("user_id", s.UserId)
|
||||
enc.StringKey("device_id", s.DeviceId)
|
||||
}
|
||||
|
||||
func (s auditSession) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditIncomingWebhook struct {
|
||||
ID string
|
||||
ChannelID string
|
||||
TeamId string
|
||||
DisplayName string
|
||||
Description string
|
||||
}
|
||||
|
||||
// newAuditIncomingWebhook creates a simplified representation of IncomingWebhook for output to audit log.
|
||||
func newAuditIncomingWebhook(h *IncomingWebhook) auditIncomingWebhook {
|
||||
var hook auditIncomingWebhook
|
||||
if h != nil {
|
||||
hook.ID = h.Id
|
||||
hook.ChannelID = h.ChannelId
|
||||
hook.TeamId = h.TeamId
|
||||
hook.DisplayName = h.DisplayName
|
||||
hook.Description = h.Description
|
||||
}
|
||||
return hook
|
||||
}
|
||||
|
||||
func (h auditIncomingWebhook) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", h.ID)
|
||||
enc.StringKey("channel_id", h.ChannelID)
|
||||
enc.StringKey("team_id", h.TeamId)
|
||||
enc.StringKey("display", h.DisplayName)
|
||||
enc.StringKey("desc", h.Description)
|
||||
}
|
||||
|
||||
func (h auditIncomingWebhook) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditOutgoingWebhook struct {
|
||||
ID string
|
||||
ChannelID string
|
||||
TeamID string
|
||||
TriggerWords StringArray
|
||||
TriggerWhen int
|
||||
DisplayName string
|
||||
Description string
|
||||
ContentType string
|
||||
Username string
|
||||
}
|
||||
|
||||
// newAuditOutgoingWebhook creates a simplified representation of OutgoingWebhook for output to audit log.
|
||||
func newAuditOutgoingWebhook(h *OutgoingWebhook) auditOutgoingWebhook {
|
||||
var hook auditOutgoingWebhook
|
||||
if h != nil {
|
||||
hook.ID = h.Id
|
||||
hook.ChannelID = h.ChannelId
|
||||
hook.TeamID = h.TeamId
|
||||
hook.TriggerWords = h.TriggerWords
|
||||
hook.TriggerWhen = h.TriggerWhen
|
||||
hook.DisplayName = h.DisplayName
|
||||
hook.Description = h.Description
|
||||
hook.ContentType = h.ContentType
|
||||
hook.Username = h.Username
|
||||
}
|
||||
return hook
|
||||
}
|
||||
|
||||
func (h auditOutgoingWebhook) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("id", h.ID)
|
||||
enc.StringKey("channel_id", h.ChannelID)
|
||||
enc.StringKey("team_id", h.TeamID)
|
||||
enc.SliceStringKey("trigger_words", h.TriggerWords)
|
||||
enc.IntKey("trigger_when", h.TriggerWhen)
|
||||
enc.StringKey("display", h.DisplayName)
|
||||
enc.StringKey("desc", h.Description)
|
||||
enc.StringKey("content_type", h.ContentType)
|
||||
enc.StringKey("username", h.Username)
|
||||
}
|
||||
|
||||
func (h auditOutgoingWebhook) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type auditRemoteCluster struct {
|
||||
RemoteId string
|
||||
RemoteTeamId string
|
||||
Name string
|
||||
DisplayName string
|
||||
SiteURL string
|
||||
CreateAt int64
|
||||
LastPingAt int64
|
||||
CreatorId string
|
||||
}
|
||||
|
||||
// newRemoteCluster creates a simplified representation of RemoteCluster for output to audit log.
|
||||
func newRemoteCluster(r *RemoteCluster) auditRemoteCluster {
|
||||
var rc auditRemoteCluster
|
||||
if r != nil {
|
||||
rc.RemoteId = r.RemoteId
|
||||
rc.RemoteTeamId = r.RemoteTeamId
|
||||
rc.Name = r.Name
|
||||
rc.DisplayName = r.DisplayName
|
||||
rc.SiteURL = r.SiteURL
|
||||
rc.CreateAt = r.CreateAt
|
||||
rc.LastPingAt = r.LastPingAt
|
||||
rc.CreatorId = r.CreatorId
|
||||
}
|
||||
return rc
|
||||
}
|
||||
|
||||
func (r auditRemoteCluster) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("remote_id", r.RemoteId)
|
||||
enc.StringKey("remote_team_id", r.RemoteTeamId)
|
||||
enc.StringKey("name", r.Name)
|
||||
enc.StringKey("display_name", r.DisplayName)
|
||||
enc.StringKey("site_url", r.SiteURL)
|
||||
enc.Int64Key("create_at", r.CreateAt)
|
||||
enc.Int64Key("last_ping_at", r.LastPingAt)
|
||||
enc.StringKey("creator_id", r.CreatorId)
|
||||
}
|
||||
|
||||
func (r auditRemoteCluster) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
14
vendor/github.com/mattermost/mattermost/server/public/model/audits.go
generated
vendored
Normal file
14
vendor/github.com/mattermost/mattermost/server/public/model/audits.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type Audits []Audit
|
||||
|
||||
func (o Audits) Etag() string {
|
||||
if len(o) > 0 {
|
||||
// the first in the list is always the most current
|
||||
return Etag(o[0].CreateAt)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
116
vendor/github.com/mattermost/mattermost/server/public/model/authorize.go
generated
vendored
Normal file
116
vendor/github.com/mattermost/mattermost/server/public/model/authorize.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthCodeExpireTime = 60 * 10 // 10 minutes
|
||||
AuthCodeResponseType = "code"
|
||||
ImplicitResponseType = "token"
|
||||
DefaultScope = "user"
|
||||
)
|
||||
|
||||
type AuthData struct {
|
||||
ClientId string `json:"client_id"`
|
||||
UserId string `json:"user_id"`
|
||||
Code string `json:"code"`
|
||||
ExpiresIn int32 `json:"expires_in"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
RedirectUri string `json:"redirect_uri"`
|
||||
State string `json:"state"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
type AuthorizeRequest struct {
|
||||
ResponseType string `json:"response_type"`
|
||||
ClientId string `json:"client_id"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
Scope string `json:"scope"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
// IsValid validates the AuthData and returns an error if it isn't configured
|
||||
// correctly.
|
||||
func (ad *AuthData) IsValid() *AppError {
|
||||
if !IsValidId(ad.ClientId) {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(ad.UserId) {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if ad.Code == "" || len(ad.Code) > 128 {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.auth_code.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if ad.ExpiresIn == 0 {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.expires.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if ad.CreateAt <= 0 {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.create_at.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(ad.RedirectUri) > 256 || !IsValidHTTPURL(ad.RedirectUri) {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(ad.State) > 1024 {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(ad.Scope) > 128 {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid validates the AuthorizeRequest and returns an error if it isn't configured
|
||||
// correctly.
|
||||
func (ar *AuthorizeRequest) IsValid() *AppError {
|
||||
if !IsValidId(ar.ClientId) {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if ar.ResponseType == "" {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.response_type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if ar.RedirectURI == "" || len(ar.RedirectURI) > 256 || !IsValidHTTPURL(ar.RedirectURI) {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(ar.State) > 1024 {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(ar.Scope) > 128 {
|
||||
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ad *AuthData) PreSave() {
|
||||
if ad.ExpiresIn == 0 {
|
||||
ad.ExpiresIn = AuthCodeExpireTime
|
||||
}
|
||||
|
||||
if ad.CreateAt == 0 {
|
||||
ad.CreateAt = GetMillis()
|
||||
}
|
||||
|
||||
if ad.Scope == "" {
|
||||
ad.Scope = DefaultScope
|
||||
}
|
||||
}
|
||||
|
||||
func (ad *AuthData) IsExpired() bool {
|
||||
return GetMillis() > ad.CreateAt+int64(ad.ExpiresIn*1000)
|
||||
}
|
||||
229
vendor/github.com/mattermost/mattermost/server/public/model/bot.go
generated
vendored
Normal file
229
vendor/github.com/mattermost/mattermost/server/public/model/bot.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
BotDisplayNameMaxRunes = UserFirstNameMaxRunes
|
||||
BotDescriptionMaxRunes = 1024
|
||||
BotCreatorIdMaxRunes = KeyValuePluginIdMaxRunes // UserId or PluginId
|
||||
BotWarnMetricBotUsername = "mattermost-advisor"
|
||||
BotSystemBotUsername = "system-bot"
|
||||
)
|
||||
|
||||
// Bot is a special type of User meant for programmatic interactions.
|
||||
// Note that the primary key of a bot is the UserId, and matches the primary key of the
|
||||
// corresponding user.
|
||||
type Bot struct {
|
||||
UserId string `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"display_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
OwnerId string `json:"owner_id"`
|
||||
LastIconUpdate int64 `json:"last_icon_update,omitempty"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
}
|
||||
|
||||
func (b *Bot) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"user_id": b.UserId,
|
||||
"username": b.Username,
|
||||
"display_name": b.DisplayName,
|
||||
"description": b.Description,
|
||||
"owner_id": b.OwnerId,
|
||||
"last_icon_update": b.LastIconUpdate,
|
||||
"create_at": b.CreateAt,
|
||||
"update_at": b.UpdateAt,
|
||||
"delete_at": b.DeleteAt,
|
||||
}
|
||||
}
|
||||
|
||||
// BotPatch is a description of what fields to update on an existing bot.
|
||||
type BotPatch struct {
|
||||
Username *string `json:"username"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
func (b *BotPatch) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"username": b.Username,
|
||||
"display_name": b.DisplayName,
|
||||
"description": b.Description,
|
||||
}
|
||||
}
|
||||
|
||||
// BotGetOptions acts as a filter on bulk bot fetching queries.
|
||||
type BotGetOptions struct {
|
||||
OwnerId string
|
||||
IncludeDeleted bool
|
||||
OnlyOrphaned bool
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
// BotList is a list of bots.
|
||||
type BotList []*Bot
|
||||
|
||||
// Trace describes the minimum information required to identify a bot for the purpose of logging.
|
||||
func (b *Bot) Trace() map[string]any {
|
||||
return map[string]any{"user_id": b.UserId}
|
||||
}
|
||||
|
||||
// Clone returns a shallow copy of the bot.
|
||||
func (b *Bot) Clone() *Bot {
|
||||
bCopy := *b
|
||||
return &bCopy
|
||||
}
|
||||
|
||||
// IsValidCreate validates bot for Create call. This skips validations of fields that are auto-filled on Create
|
||||
func (b *Bot) IsValidCreate() *AppError {
|
||||
if !IsValidUsername(b.Username) {
|
||||
return NewAppError("Bot.IsValid", "model.bot.is_valid.username.app_error", b.Trace(), "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(b.DisplayName) > BotDisplayNameMaxRunes {
|
||||
return NewAppError("Bot.IsValid", "model.bot.is_valid.user_id.app_error", b.Trace(), "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(b.Description) > BotDescriptionMaxRunes {
|
||||
return NewAppError("Bot.IsValid", "model.bot.is_valid.description.app_error", b.Trace(), "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if b.OwnerId == "" || utf8.RuneCountInString(b.OwnerId) > BotCreatorIdMaxRunes {
|
||||
return NewAppError("Bot.IsValid", "model.bot.is_valid.creator_id.app_error", b.Trace(), "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid validates the bot and returns an error if it isn't configured correctly.
|
||||
func (b *Bot) IsValid() *AppError {
|
||||
if !IsValidId(b.UserId) {
|
||||
return NewAppError("Bot.IsValid", "model.bot.is_valid.user_id.app_error", b.Trace(), "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if b.CreateAt == 0 {
|
||||
return NewAppError("Bot.IsValid", "model.bot.is_valid.create_at.app_error", b.Trace(), "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if b.UpdateAt == 0 {
|
||||
return NewAppError("Bot.IsValid", "model.bot.is_valid.update_at.app_error", b.Trace(), "", http.StatusBadRequest)
|
||||
}
|
||||
return b.IsValidCreate()
|
||||
}
|
||||
|
||||
// PreSave should be run before saving a new bot to the database.
|
||||
func (b *Bot) PreSave() {
|
||||
b.CreateAt = GetMillis()
|
||||
b.UpdateAt = b.CreateAt
|
||||
b.DeleteAt = 0
|
||||
}
|
||||
|
||||
// PreUpdate should be run before saving an updated bot to the database.
|
||||
func (b *Bot) PreUpdate() {
|
||||
b.UpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
// Etag generates an etag for caching.
|
||||
func (b *Bot) Etag() string {
|
||||
return Etag(b.UserId, b.UpdateAt)
|
||||
}
|
||||
|
||||
// Patch modifies an existing bot with optional fields from the given patch.
|
||||
// TODO 6.0: consider returning a boolean to indicate whether or not the patch
|
||||
// applied any changes.
|
||||
func (b *Bot) Patch(patch *BotPatch) {
|
||||
if patch.Username != nil {
|
||||
b.Username = *patch.Username
|
||||
}
|
||||
|
||||
if patch.DisplayName != nil {
|
||||
b.DisplayName = *patch.DisplayName
|
||||
}
|
||||
|
||||
if patch.Description != nil {
|
||||
b.Description = *patch.Description
|
||||
}
|
||||
}
|
||||
|
||||
// WouldPatch returns whether or not the given patch would be applied or not.
|
||||
func (b *Bot) WouldPatch(patch *BotPatch) bool {
|
||||
if patch == nil {
|
||||
return false
|
||||
}
|
||||
if patch.Username != nil && *patch.Username != b.Username {
|
||||
return true
|
||||
}
|
||||
if patch.DisplayName != nil && *patch.DisplayName != b.DisplayName {
|
||||
return true
|
||||
}
|
||||
if patch.Description != nil && *patch.Description != b.Description {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// UserFromBot returns a user model describing the bot fields stored in the User store.
|
||||
func UserFromBot(b *Bot) *User {
|
||||
return &User{
|
||||
Id: b.UserId,
|
||||
Username: b.Username,
|
||||
Email: NormalizeEmail(fmt.Sprintf("%s@localhost", b.Username)),
|
||||
FirstName: b.DisplayName,
|
||||
Roles: SystemUserRoleId,
|
||||
}
|
||||
}
|
||||
|
||||
// BotFromUser returns a bot model given a user model
|
||||
func BotFromUser(u *User) *Bot {
|
||||
return &Bot{
|
||||
OwnerId: u.Id,
|
||||
UserId: u.Id,
|
||||
Username: u.Username,
|
||||
DisplayName: u.GetDisplayName(ShowUsername),
|
||||
}
|
||||
}
|
||||
|
||||
// Etag computes the etag for a list of bots.
|
||||
func (l *BotList) Etag() string {
|
||||
id := "0"
|
||||
var t int64
|
||||
var delta int64
|
||||
|
||||
for _, v := range *l {
|
||||
if v.UpdateAt > t {
|
||||
t = v.UpdateAt
|
||||
id = v.UserId
|
||||
}
|
||||
}
|
||||
|
||||
return Etag(id, t, delta, len(*l))
|
||||
}
|
||||
|
||||
// MakeBotNotFoundError creates the error returned when a bot does not exist, or when the user isn't allowed to query the bot.
|
||||
// The errors must the same in both cases to avoid leaking that a user is a bot.
|
||||
func MakeBotNotFoundError(where, userId string) *AppError {
|
||||
return NewAppError(where, "store.sql_bot.get.missing.app_error", map[string]any{"user_id": userId}, "", http.StatusNotFound)
|
||||
}
|
||||
|
||||
func IsBotDMChannel(channel *Channel, botUserID string) bool {
|
||||
if channel.Type != ChannelTypeDirect {
|
||||
return false
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(channel.Name, botUserID+"__") && !strings.HasSuffix(channel.Name, "__"+botUserID) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
9
vendor/github.com/mattermost/mattermost/server/public/model/builtin.go
generated
vendored
Normal file
9
vendor/github.com/mattermost/mattermost/server/public/model/builtin.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
func NewBool(b bool) *bool { return &b }
|
||||
func NewInt(n int) *int { return &n }
|
||||
func NewInt64(n int64) *int64 { return &n }
|
||||
func NewString(s string) *string { return &s }
|
||||
16
vendor/github.com/mattermost/mattermost/server/public/model/bulk_export.go
generated
vendored
Normal file
16
vendor/github.com/mattermost/mattermost/server/public/model/bulk_export.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
// ExportDataDir is the name of the directory were to store additional data
|
||||
// included with the export (e.g. file attachments).
|
||||
const ExportDataDir = "data"
|
||||
|
||||
type BulkExportOpts struct {
|
||||
IncludeAttachments bool
|
||||
IncludeProfilePictures bool
|
||||
IncludeArchivedChannels bool
|
||||
IncludeRolesAndSchemes bool
|
||||
CreateArchive bool
|
||||
}
|
||||
34
vendor/github.com/mattermost/mattermost/server/public/model/bundle_info.go
generated
vendored
Normal file
34
vendor/github.com/mattermost/mattermost/server/public/model/bundle_info.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
)
|
||||
|
||||
type BundleInfo struct {
|
||||
Path string
|
||||
|
||||
Manifest *Manifest
|
||||
ManifestPath string
|
||||
ManifestError error
|
||||
}
|
||||
|
||||
func (b *BundleInfo) WrapLogger(logger *mlog.Logger) *mlog.Logger {
|
||||
if b.Manifest != nil {
|
||||
return logger.With(mlog.String("plugin_id", b.Manifest.Id))
|
||||
}
|
||||
return logger.With(mlog.String("plugin_path", b.Path))
|
||||
}
|
||||
|
||||
// Returns bundle info for the given path. The return value is never nil.
|
||||
func BundleInfoForPath(path string) *BundleInfo {
|
||||
m, mpath, err := FindManifest(path)
|
||||
return &BundleInfo{
|
||||
Path: path,
|
||||
Manifest: m,
|
||||
ManifestPath: mpath,
|
||||
ManifestError: err,
|
||||
}
|
||||
}
|
||||
403
vendor/github.com/mattermost/mattermost/server/public/model/channel.go
generated
vendored
Normal file
403
vendor/github.com/mattermost/mattermost/server/public/model/channel.go
generated
vendored
Normal file
@@ -0,0 +1,403 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type ChannelType string
|
||||
|
||||
const (
|
||||
ChannelTypeOpen ChannelType = "O"
|
||||
ChannelTypePrivate ChannelType = "P"
|
||||
ChannelTypeDirect ChannelType = "D"
|
||||
ChannelTypeGroup ChannelType = "G"
|
||||
|
||||
ChannelGroupMaxUsers = 8
|
||||
ChannelGroupMinUsers = 3
|
||||
DefaultChannelName = "town-square"
|
||||
ChannelDisplayNameMaxRunes = 64
|
||||
ChannelNameMinLength = 1
|
||||
ChannelNameMaxLength = 64
|
||||
ChannelHeaderMaxRunes = 1024
|
||||
ChannelPurposeMaxRunes = 250
|
||||
ChannelCacheSize = 25000
|
||||
|
||||
ChannelSortByUsername = "username"
|
||||
ChannelSortByStatus = "status"
|
||||
)
|
||||
|
||||
type Channel struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
TeamId string `json:"team_id"`
|
||||
Type ChannelType `json:"type"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Name string `json:"name"`
|
||||
Header string `json:"header"`
|
||||
Purpose string `json:"purpose"`
|
||||
LastPostAt int64 `json:"last_post_at"`
|
||||
TotalMsgCount int64 `json:"total_msg_count"`
|
||||
ExtraUpdateAt int64 `json:"extra_update_at"`
|
||||
CreatorId string `json:"creator_id"`
|
||||
SchemeId *string `json:"scheme_id"`
|
||||
Props map[string]any `json:"props"`
|
||||
GroupConstrained *bool `json:"group_constrained"`
|
||||
Shared *bool `json:"shared"`
|
||||
TotalMsgCountRoot int64 `json:"total_msg_count_root"`
|
||||
PolicyID *string `json:"policy_id"`
|
||||
LastRootPostAt int64 `json:"last_root_post_at"`
|
||||
}
|
||||
|
||||
func (o *Channel) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"create_at": o.CreateAt,
|
||||
"creator_id": o.CreatorId,
|
||||
"delete_at": o.DeleteAt,
|
||||
"extra_group_at": o.ExtraUpdateAt,
|
||||
"group_constrained": o.GroupConstrained,
|
||||
"id": o.Id,
|
||||
"last_post_at": o.LastPostAt,
|
||||
"last_root_post_at": o.LastRootPostAt,
|
||||
"policy_id": o.PolicyID,
|
||||
"props": o.Props,
|
||||
"scheme_id": o.SchemeId,
|
||||
"shared": o.Shared,
|
||||
"team_id": o.TeamId,
|
||||
"total_msg_count_root": o.TotalMsgCountRoot,
|
||||
"type": o.Type,
|
||||
"update_at": o.UpdateAt,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Channel) LogClone() any {
|
||||
return o.Auditable()
|
||||
}
|
||||
|
||||
type ChannelWithTeamData struct {
|
||||
Channel
|
||||
TeamDisplayName string `json:"team_display_name"`
|
||||
TeamName string `json:"team_name"`
|
||||
TeamUpdateAt int64 `json:"team_update_at"`
|
||||
}
|
||||
|
||||
type ChannelsWithCount struct {
|
||||
Channels ChannelListWithTeamData `json:"channels"`
|
||||
TotalCount int64 `json:"total_count"`
|
||||
}
|
||||
|
||||
type ChannelPatch struct {
|
||||
DisplayName *string `json:"display_name"`
|
||||
Name *string `json:"name"`
|
||||
Header *string `json:"header"`
|
||||
Purpose *string `json:"purpose"`
|
||||
GroupConstrained *bool `json:"group_constrained"`
|
||||
}
|
||||
|
||||
func (c *ChannelPatch) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"header": c.Header,
|
||||
"group_constrained": c.GroupConstrained,
|
||||
"purpose": c.Purpose,
|
||||
}
|
||||
}
|
||||
|
||||
type ChannelForExport struct {
|
||||
Channel
|
||||
TeamName string
|
||||
SchemeName *string
|
||||
}
|
||||
|
||||
type DirectChannelForExport struct {
|
||||
Channel
|
||||
Members *[]string
|
||||
}
|
||||
|
||||
type ChannelModeration struct {
|
||||
Name string `json:"name"`
|
||||
Roles *ChannelModeratedRoles `json:"roles"`
|
||||
}
|
||||
|
||||
type ChannelModeratedRoles struct {
|
||||
Guests *ChannelModeratedRole `json:"guests"`
|
||||
Members *ChannelModeratedRole `json:"members"`
|
||||
}
|
||||
|
||||
type ChannelModeratedRole struct {
|
||||
Value bool `json:"value"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type ChannelModerationPatch struct {
|
||||
Name *string `json:"name"`
|
||||
Roles *ChannelModeratedRolesPatch `json:"roles"`
|
||||
}
|
||||
|
||||
func (c *ChannelModerationPatch) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"name": c.Name,
|
||||
"roles": c.Roles,
|
||||
}
|
||||
}
|
||||
|
||||
type ChannelModeratedRolesPatch struct {
|
||||
Guests *bool `json:"guests"`
|
||||
Members *bool `json:"members"`
|
||||
}
|
||||
|
||||
// ChannelSearchOpts contains options for searching channels.
|
||||
//
|
||||
// NotAssociatedToGroup will exclude channels that have associated, active GroupChannels records.
|
||||
// ExcludeDefaultChannels will exclude the configured default channels (ex 'town-square' and 'off-topic').
|
||||
// IncludeDeleted will include channel records where DeleteAt != 0.
|
||||
// ExcludeChannelNames will exclude channels from the results by name.
|
||||
// IncludeSearchById will include searching matches against channel IDs in the results
|
||||
// Paginate whether to paginate the results.
|
||||
// Page page requested, if results are paginated.
|
||||
// PerPage number of results per page, if paginated.
|
||||
type ChannelSearchOpts struct {
|
||||
NotAssociatedToGroup string
|
||||
ExcludeDefaultChannels bool
|
||||
IncludeDeleted bool // If true, deleted channels will be included in the results.
|
||||
Deleted bool
|
||||
ExcludeChannelNames []string
|
||||
TeamIds []string
|
||||
GroupConstrained bool
|
||||
ExcludeGroupConstrained bool
|
||||
PolicyID string
|
||||
ExcludePolicyConstrained bool
|
||||
IncludePolicyID bool
|
||||
IncludeSearchById bool
|
||||
Public bool
|
||||
Private bool
|
||||
Page *int
|
||||
PerPage *int
|
||||
LastDeleteAt int // When combined with IncludeDeleted, only channels deleted after this time will be returned.
|
||||
LastUpdateAt int
|
||||
}
|
||||
|
||||
type ChannelMemberCountByGroup struct {
|
||||
GroupId string `json:"group_id"`
|
||||
ChannelMemberCount int64 `json:"channel_member_count"`
|
||||
ChannelMemberTimezonesCount int64 `json:"channel_member_timezones_count"`
|
||||
}
|
||||
|
||||
type ChannelOption func(channel *Channel)
|
||||
|
||||
var gmNameRegex = regexp.MustCompile("^[a-f0-9]{40}$")
|
||||
|
||||
func WithID(ID string) ChannelOption {
|
||||
return func(channel *Channel) {
|
||||
channel.Id = ID
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Channel) DeepCopy() *Channel {
|
||||
cCopy := *o
|
||||
if cCopy.SchemeId != nil {
|
||||
cCopy.SchemeId = NewString(*o.SchemeId)
|
||||
}
|
||||
return &cCopy
|
||||
}
|
||||
|
||||
func (o *Channel) Etag() string {
|
||||
return Etag(o.Id, o.UpdateAt)
|
||||
}
|
||||
|
||||
func (o *Channel) IsValid() *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.UpdateAt == 0 {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(o.DisplayName) > ChannelDisplayNameMaxRunes {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidChannelIdentifier(o.Name) {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.1_or_more.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !(o.Type == ChannelTypeOpen || o.Type == ChannelTypePrivate || o.Type == ChannelTypeDirect || o.Type == ChannelTypeGroup) {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(o.Header) > ChannelHeaderMaxRunes {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(o.Purpose) > ChannelPurposeMaxRunes {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.CreatorId) > 26 {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.Type != ChannelTypeDirect && o.Type != ChannelTypeGroup {
|
||||
userIds := strings.Split(o.Name, "__")
|
||||
if ok := gmNameRegex.MatchString(o.Name); ok || (o.Type != ChannelTypeDirect && len(userIds) == 2 && IsValidId(userIds[0]) && IsValidId(userIds[1])) {
|
||||
return NewAppError("Channel.IsValid", "model.channel.is_valid.name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Channel) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
o.Name = SanitizeUnicode(o.Name)
|
||||
o.DisplayName = SanitizeUnicode(o.DisplayName)
|
||||
if o.CreateAt == 0 {
|
||||
o.CreateAt = GetMillis()
|
||||
}
|
||||
o.UpdateAt = o.CreateAt
|
||||
o.ExtraUpdateAt = 0
|
||||
}
|
||||
|
||||
func (o *Channel) PreUpdate() {
|
||||
o.UpdateAt = GetMillis()
|
||||
o.Name = SanitizeUnicode(o.Name)
|
||||
o.DisplayName = SanitizeUnicode(o.DisplayName)
|
||||
}
|
||||
|
||||
func (o *Channel) IsGroupOrDirect() bool {
|
||||
return o.Type == ChannelTypeDirect || o.Type == ChannelTypeGroup
|
||||
}
|
||||
|
||||
func (o *Channel) IsOpen() bool {
|
||||
return o.Type == ChannelTypeOpen
|
||||
}
|
||||
|
||||
func (o *Channel) Patch(patch *ChannelPatch) {
|
||||
if patch.DisplayName != nil {
|
||||
o.DisplayName = *patch.DisplayName
|
||||
}
|
||||
|
||||
if patch.Name != nil {
|
||||
o.Name = *patch.Name
|
||||
}
|
||||
|
||||
if patch.Header != nil {
|
||||
o.Header = *patch.Header
|
||||
}
|
||||
|
||||
if patch.Purpose != nil {
|
||||
o.Purpose = *patch.Purpose
|
||||
}
|
||||
|
||||
if patch.GroupConstrained != nil {
|
||||
o.GroupConstrained = patch.GroupConstrained
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Channel) MakeNonNil() {
|
||||
if o.Props == nil {
|
||||
o.Props = make(map[string]any)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Channel) AddProp(key string, value any) {
|
||||
o.MakeNonNil()
|
||||
|
||||
o.Props[key] = value
|
||||
}
|
||||
|
||||
func (o *Channel) IsGroupConstrained() bool {
|
||||
return o.GroupConstrained != nil && *o.GroupConstrained
|
||||
}
|
||||
|
||||
func (o *Channel) IsShared() bool {
|
||||
return o.Shared != nil && *o.Shared
|
||||
}
|
||||
|
||||
func (o *Channel) GetOtherUserIdForDM(userId string) string {
|
||||
if o.Type != ChannelTypeDirect {
|
||||
return ""
|
||||
}
|
||||
|
||||
userIds := strings.Split(o.Name, "__")
|
||||
if len(userIds) != 2 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var otherUserId string
|
||||
|
||||
if userIds[0] != userIds[1] {
|
||||
if userIds[0] == userId {
|
||||
otherUserId = userIds[1]
|
||||
} else {
|
||||
otherUserId = userIds[0]
|
||||
}
|
||||
}
|
||||
|
||||
return otherUserId
|
||||
}
|
||||
|
||||
func (t ChannelType) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(string(t))
|
||||
}
|
||||
|
||||
func GetDMNameFromIds(userId1, userId2 string) string {
|
||||
if userId1 > userId2 {
|
||||
return userId2 + "__" + userId1
|
||||
}
|
||||
return userId1 + "__" + userId2
|
||||
}
|
||||
|
||||
func GetGroupDisplayNameFromUsers(users []*User, truncate bool) string {
|
||||
usernames := make([]string, len(users))
|
||||
for index, user := range users {
|
||||
usernames[index] = user.Username
|
||||
}
|
||||
|
||||
sort.Strings(usernames)
|
||||
|
||||
name := strings.Join(usernames, ", ")
|
||||
|
||||
if truncate && len(name) > ChannelNameMaxLength {
|
||||
name = name[:ChannelNameMaxLength]
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func GetGroupNameFromUserIds(userIds []string) string {
|
||||
sort.Strings(userIds)
|
||||
|
||||
h := sha1.New()
|
||||
for _, id := range userIds {
|
||||
io.WriteString(h, id)
|
||||
}
|
||||
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
type GroupMessageConversionRequestBody struct {
|
||||
ChannelID string `json:"channel_id"`
|
||||
TeamID string `json:"team_id"`
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
322
vendor/github.com/mattermost/mattermost/server/public/model/channel_bookmark.go
generated
vendored
Normal file
322
vendor/github.com/mattermost/mattermost/server/public/model/channel_bookmark.go
generated
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ChannelBookmarkType string
|
||||
|
||||
const (
|
||||
ChannelBookmarkLink ChannelBookmarkType = "link"
|
||||
ChannelBookmarkFile ChannelBookmarkType = "file"
|
||||
BookmarkFileOwner = "bookmark"
|
||||
MaxBookmarksPerChannel = 50
|
||||
)
|
||||
|
||||
type ChannelBookmark struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
OwnerId string `json:"owner_id"`
|
||||
FileId string `json:"file_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
SortOrder int64 `json:"sort_order"`
|
||||
LinkUrl string `json:"link_url,omitempty"`
|
||||
ImageUrl string `json:"image_url,omitempty"`
|
||||
Emoji string `json:"emoji,omitempty"`
|
||||
Type ChannelBookmarkType `json:"type"`
|
||||
OriginalId string `json:"original_id,omitempty"`
|
||||
ParentId string `json:"parent_id,omitempty"`
|
||||
}
|
||||
|
||||
func (o *ChannelBookmark) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": o.Id,
|
||||
"create_at": o.CreateAt,
|
||||
"update_at": o.UpdateAt,
|
||||
"delete_at": o.DeleteAt,
|
||||
"channel_id": o.ChannelId,
|
||||
"owner_id": o.OwnerId,
|
||||
"file_id": o.FileId,
|
||||
"type": o.Type,
|
||||
"original_id": o.OriginalId,
|
||||
"parent_id": o.ParentId,
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a shallow copy of the channel bookmark.
|
||||
func (o *ChannelBookmark) Clone() *ChannelBookmark {
|
||||
bCopy := *o
|
||||
return &bCopy
|
||||
}
|
||||
|
||||
// SetOriginal generates a new bookmark copying the data of the
|
||||
// receiver bookmark, resets its timestamps and main ID, updates its
|
||||
// OriginalId and sets the owner to the ID passed as a parameter
|
||||
func (o *ChannelBookmark) SetOriginal(newOwnerId string) *ChannelBookmark {
|
||||
bCopy := *o
|
||||
bCopy.Id = ""
|
||||
bCopy.CreateAt = 0
|
||||
bCopy.DeleteAt = 0
|
||||
bCopy.UpdateAt = 0
|
||||
bCopy.OriginalId = o.Id
|
||||
bCopy.OwnerId = newOwnerId
|
||||
return &bCopy
|
||||
}
|
||||
|
||||
func (o *ChannelBookmark) IsValid() *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.UpdateAt == 0 {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.ChannelId) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.OwnerId) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.owner_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.DisplayName == "" {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.display_name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !(o.Type == ChannelBookmarkFile || o.Type == ChannelBookmarkLink) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.Type == ChannelBookmarkLink && (o.LinkUrl == "" || !IsValidHTTPURL(o.LinkUrl)) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.link_url.missing_or_invalid.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.Type == ChannelBookmarkLink && o.ImageUrl != "" && !IsValidHTTPURL(o.ImageUrl) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.image_url.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.Type == ChannelBookmarkFile && (o.FileId == "" || !IsValidId(o.FileId)) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.file_id.missing_or_invalid.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.ImageUrl != "" && o.FileId != "" {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.link_file.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.OriginalId != "" && !IsValidId(o.OriginalId) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.original_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.ParentId != "" && !IsValidId(o.ParentId) {
|
||||
return NewAppError("ChannelBookmark.IsValid", "model.channel_bookmark.is_valid.parent_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ChannelBookmark) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
o.DisplayName = SanitizeUnicode(o.DisplayName)
|
||||
if o.CreateAt == 0 {
|
||||
o.CreateAt = GetMillis()
|
||||
}
|
||||
o.UpdateAt = o.CreateAt
|
||||
}
|
||||
|
||||
func (o *ChannelBookmark) PreUpdate() {
|
||||
o.UpdateAt = GetMillis()
|
||||
o.DisplayName = SanitizeUnicode(o.DisplayName)
|
||||
}
|
||||
|
||||
func (o *ChannelBookmark) ToBookmarkWithFileInfo(f *FileInfo) *ChannelBookmarkWithFileInfo {
|
||||
bwf := ChannelBookmarkWithFileInfo{
|
||||
ChannelBookmark: &ChannelBookmark{
|
||||
Id: o.Id,
|
||||
CreateAt: o.CreateAt,
|
||||
UpdateAt: o.UpdateAt,
|
||||
DeleteAt: o.DeleteAt,
|
||||
ChannelId: o.ChannelId,
|
||||
OwnerId: o.OwnerId,
|
||||
FileId: o.FileId,
|
||||
DisplayName: o.DisplayName,
|
||||
SortOrder: o.SortOrder,
|
||||
LinkUrl: o.LinkUrl,
|
||||
ImageUrl: o.ImageUrl,
|
||||
Emoji: o.Emoji,
|
||||
Type: o.Type,
|
||||
OriginalId: o.OriginalId,
|
||||
ParentId: o.ParentId,
|
||||
},
|
||||
}
|
||||
|
||||
if f != nil && f.Id != "" {
|
||||
bwf.FileInfo = f
|
||||
}
|
||||
|
||||
return &bwf
|
||||
}
|
||||
|
||||
type ChannelBookmarkPatch struct {
|
||||
FileId *string `json:"file_id"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
SortOrder *int64 `json:"sort_order"`
|
||||
LinkUrl *string `json:"link_url,omitempty"`
|
||||
ImageUrl *string `json:"image_url,omitempty"`
|
||||
Emoji *string `json:"emoji,omitempty"`
|
||||
}
|
||||
|
||||
func (o *ChannelBookmarkPatch) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"file_id": o.FileId,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ChannelBookmark) Patch(patch *ChannelBookmarkPatch) {
|
||||
if patch.FileId != nil {
|
||||
o.FileId = *patch.FileId
|
||||
}
|
||||
|
||||
if patch.DisplayName != nil {
|
||||
o.DisplayName = *patch.DisplayName
|
||||
}
|
||||
if patch.SortOrder != nil {
|
||||
o.SortOrder = *patch.SortOrder
|
||||
}
|
||||
if patch.LinkUrl != nil {
|
||||
o.LinkUrl = *patch.LinkUrl
|
||||
}
|
||||
if patch.ImageUrl != nil {
|
||||
o.ImageUrl = *patch.ImageUrl
|
||||
}
|
||||
if patch.Emoji != nil {
|
||||
o.Emoji = *patch.Emoji
|
||||
}
|
||||
}
|
||||
|
||||
type ChannelBookmarkWithFileInfo struct {
|
||||
*ChannelBookmark
|
||||
FileInfo *FileInfo `json:"file,omitempty"`
|
||||
}
|
||||
|
||||
func (o *ChannelBookmarkWithFileInfo) Auditable() map[string]interface{} {
|
||||
a := o.ChannelBookmark.Auditable()
|
||||
if o.FileInfo != nil {
|
||||
a["file"] = o.FileInfo.Auditable()
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// Clone returns a shallow copy of the channel bookmark with file info.
|
||||
func (o *ChannelBookmarkWithFileInfo) Clone() *ChannelBookmarkWithFileInfo {
|
||||
bCopy := *o
|
||||
return &bCopy
|
||||
}
|
||||
|
||||
type ChannelWithBookmarks struct {
|
||||
*Channel
|
||||
Bookmarks []*ChannelBookmarkWithFileInfo `json:"bookmarks,omitempty"`
|
||||
}
|
||||
|
||||
type ChannelWithTeamDataAndBookmarks struct {
|
||||
*ChannelWithTeamData
|
||||
Bookmarks []*ChannelBookmarkWithFileInfo `json:"bookmarks,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateChannelBookmarkResponse struct {
|
||||
Updated *ChannelBookmarkWithFileInfo `json:"updated,omitempty"`
|
||||
Deleted *ChannelBookmarkWithFileInfo `json:"deleted,omitempty"`
|
||||
}
|
||||
|
||||
func (o *UpdateChannelBookmarkResponse) Auditable() map[string]any {
|
||||
a := map[string]any{}
|
||||
if o.Updated != nil {
|
||||
a["updated"] = o.Updated.Auditable()
|
||||
}
|
||||
if o.Deleted != nil {
|
||||
a["updated"] = o.Deleted.Auditable()
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
type ChannelBookmarkAndFileInfo struct {
|
||||
Id string
|
||||
CreateAt int64
|
||||
UpdateAt int64
|
||||
DeleteAt int64
|
||||
ChannelId string
|
||||
OwnerId string
|
||||
FileInfoId string
|
||||
DisplayName string
|
||||
SortOrder int64
|
||||
LinkUrl string
|
||||
ImageUrl string
|
||||
Emoji string
|
||||
Type ChannelBookmarkType
|
||||
OriginalId string
|
||||
ParentId string
|
||||
FileId string
|
||||
FileName string
|
||||
Extension string
|
||||
Size int64
|
||||
MimeType string
|
||||
Width int
|
||||
Height int
|
||||
HasPreviewImage bool
|
||||
MiniPreview *[]byte
|
||||
}
|
||||
|
||||
func (o *ChannelBookmarkAndFileInfo) ToChannelBookmarkWithFileInfo() *ChannelBookmarkWithFileInfo {
|
||||
bwf := &ChannelBookmarkWithFileInfo{
|
||||
ChannelBookmark: &ChannelBookmark{
|
||||
Id: o.Id,
|
||||
CreateAt: o.CreateAt,
|
||||
UpdateAt: o.UpdateAt,
|
||||
DeleteAt: o.DeleteAt,
|
||||
ChannelId: o.ChannelId,
|
||||
OwnerId: o.OwnerId,
|
||||
FileId: o.FileInfoId,
|
||||
DisplayName: o.DisplayName,
|
||||
SortOrder: o.SortOrder,
|
||||
LinkUrl: o.LinkUrl,
|
||||
ImageUrl: o.ImageUrl,
|
||||
Emoji: o.Emoji,
|
||||
Type: o.Type,
|
||||
OriginalId: o.OriginalId,
|
||||
ParentId: o.ParentId,
|
||||
},
|
||||
}
|
||||
|
||||
if o.FileInfoId != "" && o.FileId != "" {
|
||||
miniPreview := o.MiniPreview
|
||||
if len(*miniPreview) == 0 {
|
||||
miniPreview = nil
|
||||
}
|
||||
bwf.FileInfo = &FileInfo{
|
||||
Id: o.FileId,
|
||||
Name: o.FileName,
|
||||
Extension: o.Extension,
|
||||
Size: o.Size,
|
||||
MimeType: o.MimeType,
|
||||
Width: o.Width,
|
||||
Height: o.Height,
|
||||
HasPreviewImage: o.HasPreviewImage,
|
||||
MiniPreview: miniPreview,
|
||||
}
|
||||
}
|
||||
return bwf
|
||||
}
|
||||
42
vendor/github.com/mattermost/mattermost/server/public/model/channel_count.go
generated
vendored
Normal file
42
vendor/github.com/mattermost/mattermost/server/public/model/channel_count.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ChannelCounts struct {
|
||||
Counts map[string]int64 `json:"counts"`
|
||||
CountsRoot map[string]int64 `json:"counts_root"`
|
||||
UpdateTimes map[string]int64 `json:"update_times"`
|
||||
}
|
||||
|
||||
func (o *ChannelCounts) Etag() string {
|
||||
// we don't include CountsRoot in ETag calculation, since it's a derivative
|
||||
ids := []string{}
|
||||
for id := range o.Counts {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
sort.Strings(ids)
|
||||
|
||||
str := ""
|
||||
for _, id := range ids {
|
||||
str += id + strconv.FormatInt(o.Counts[id], 10)
|
||||
}
|
||||
|
||||
md5Counts := fmt.Sprintf("%x", md5.Sum([]byte(str)))
|
||||
|
||||
var update int64
|
||||
for _, u := range o.UpdateTimes {
|
||||
if u > update {
|
||||
update = u
|
||||
}
|
||||
}
|
||||
|
||||
return Etag(md5Counts, update)
|
||||
}
|
||||
18
vendor/github.com/mattermost/mattermost/server/public/model/channel_data.go
generated
vendored
Normal file
18
vendor/github.com/mattermost/mattermost/server/public/model/channel_data.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ChannelData struct {
|
||||
Channel *Channel `json:"channel"`
|
||||
Member *ChannelMember `json:"member"`
|
||||
}
|
||||
|
||||
func (o *ChannelData) Etag() string {
|
||||
var mt int64
|
||||
if o.Member != nil {
|
||||
mt = o.Member.LastUpdateAt
|
||||
}
|
||||
|
||||
return Etag(o.Channel.Id, o.Channel.UpdateAt, o.Channel.LastPostAt, mt)
|
||||
}
|
||||
53
vendor/github.com/mattermost/mattermost/server/public/model/channel_list.go
generated
vendored
Normal file
53
vendor/github.com/mattermost/mattermost/server/public/model/channel_list.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ChannelList []*Channel
|
||||
|
||||
func (o *ChannelList) Etag() string {
|
||||
id := "0"
|
||||
var t int64
|
||||
var delta int64
|
||||
|
||||
for _, v := range *o {
|
||||
if v.LastPostAt > t {
|
||||
t = v.LastPostAt
|
||||
id = v.Id
|
||||
}
|
||||
|
||||
if v.UpdateAt > t {
|
||||
t = v.UpdateAt
|
||||
id = v.Id
|
||||
}
|
||||
}
|
||||
|
||||
return Etag(id, t, delta, len(*o))
|
||||
}
|
||||
|
||||
type ChannelListWithTeamData []*ChannelWithTeamData
|
||||
|
||||
func (o *ChannelListWithTeamData) Etag() string {
|
||||
id := "0"
|
||||
var t int64
|
||||
var delta int64
|
||||
|
||||
for _, v := range *o {
|
||||
if v.LastPostAt > t {
|
||||
t = v.LastPostAt
|
||||
id = v.Id
|
||||
}
|
||||
|
||||
if v.UpdateAt > t {
|
||||
t = v.UpdateAt
|
||||
id = v.Id
|
||||
}
|
||||
|
||||
if v.TeamUpdateAt > t {
|
||||
t = v.TeamUpdateAt
|
||||
id = v.Id
|
||||
}
|
||||
}
|
||||
|
||||
return Etag(id, t, delta, len(*o))
|
||||
}
|
||||
238
vendor/github.com/mattermost/mattermost/server/public/model/channel_member.go
generated
vendored
Normal file
238
vendor/github.com/mattermost/mattermost/server/public/model/channel_member.go
generated
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
ChannelNotifyDefault = "default"
|
||||
ChannelNotifyAll = "all"
|
||||
ChannelNotifyMention = "mention"
|
||||
ChannelNotifyNone = "none"
|
||||
ChannelMarkUnreadAll = "all"
|
||||
ChannelMarkUnreadMention = "mention"
|
||||
IgnoreChannelMentionsDefault = "default"
|
||||
IgnoreChannelMentionsOff = "off"
|
||||
IgnoreChannelMentionsOn = "on"
|
||||
IgnoreChannelMentionsNotifyProp = "ignore_channel_mentions"
|
||||
ChannelAutoFollowThreadsOff = "off"
|
||||
ChannelAutoFollowThreadsOn = "on"
|
||||
ChannelAutoFollowThreads = "channel_auto_follow_threads"
|
||||
ChannelMemberNotifyPropsMaxRunes = 800000
|
||||
)
|
||||
|
||||
type ChannelUnread struct {
|
||||
TeamId string `json:"team_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
MsgCount int64 `json:"msg_count"`
|
||||
MentionCount int64 `json:"mention_count"`
|
||||
MentionCountRoot int64 `json:"mention_count_root"`
|
||||
UrgentMentionCount int64 `json:"urgent_mention_count"`
|
||||
MsgCountRoot int64 `json:"msg_count_root"`
|
||||
NotifyProps StringMap `json:"-"`
|
||||
}
|
||||
|
||||
type ChannelUnreadAt struct {
|
||||
TeamId string `json:"team_id"`
|
||||
UserId string `json:"user_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
MsgCount int64 `json:"msg_count"`
|
||||
MentionCount int64 `json:"mention_count"`
|
||||
MentionCountRoot int64 `json:"mention_count_root"`
|
||||
UrgentMentionCount int64 `json:"urgent_mention_count"`
|
||||
MsgCountRoot int64 `json:"msg_count_root"`
|
||||
LastViewedAt int64 `json:"last_viewed_at"`
|
||||
NotifyProps StringMap `json:"-"`
|
||||
}
|
||||
|
||||
type ChannelMember struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
UserId string `json:"user_id"`
|
||||
Roles string `json:"roles"`
|
||||
LastViewedAt int64 `json:"last_viewed_at"`
|
||||
MsgCount int64 `json:"msg_count"`
|
||||
MentionCount int64 `json:"mention_count"`
|
||||
MentionCountRoot int64 `json:"mention_count_root"`
|
||||
UrgentMentionCount int64 `json:"urgent_mention_count"`
|
||||
MsgCountRoot int64 `json:"msg_count_root"`
|
||||
NotifyProps StringMap `json:"notify_props"`
|
||||
LastUpdateAt int64 `json:"last_update_at"`
|
||||
SchemeGuest bool `json:"scheme_guest"`
|
||||
SchemeUser bool `json:"scheme_user"`
|
||||
SchemeAdmin bool `json:"scheme_admin"`
|
||||
ExplicitRoles string `json:"explicit_roles"`
|
||||
}
|
||||
|
||||
func (o *ChannelMember) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"channel_id": o.ChannelId,
|
||||
"user_id": o.UserId,
|
||||
"roles": o.Roles,
|
||||
"last_viewed_at": o.LastViewedAt,
|
||||
"msg_count": o.MsgCount,
|
||||
"mention_count": o.MentionCount,
|
||||
"mention_count_root": o.MentionCountRoot,
|
||||
"urgent_mention_count": o.UrgentMentionCount,
|
||||
"msg_count_root": o.MsgCountRoot,
|
||||
"notify_props": o.NotifyProps,
|
||||
"last_update_at": o.LastUpdateAt,
|
||||
"scheme_guest": o.SchemeGuest,
|
||||
"scheme_user": o.SchemeUser,
|
||||
"scheme_admin": o.SchemeAdmin,
|
||||
"explicit_roles": o.ExplicitRoles,
|
||||
}
|
||||
}
|
||||
|
||||
// ChannelMemberWithTeamData contains ChannelMember appended with extra team information
|
||||
// as well.
|
||||
type ChannelMemberWithTeamData struct {
|
||||
ChannelMember
|
||||
TeamDisplayName string `json:"team_display_name"`
|
||||
TeamName string `json:"team_name"`
|
||||
TeamUpdateAt int64 `json:"team_update_at"`
|
||||
}
|
||||
|
||||
type ChannelMembers []ChannelMember
|
||||
|
||||
type ChannelMembersWithTeamData []ChannelMemberWithTeamData
|
||||
|
||||
type ChannelMemberForExport struct {
|
||||
ChannelMember
|
||||
ChannelName string
|
||||
Username string
|
||||
}
|
||||
|
||||
func (o *ChannelMember) IsValid() *AppError {
|
||||
if !IsValidId(o.ChannelId) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.UserId) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if appErr := IsChannelMemberNotifyPropsValid(o.NotifyProps, false); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
if len(o.Roles) > UserRolesMaxLength {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.roles_limit.app_error",
|
||||
map[string]any{"Limit": UserRolesMaxLength}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsChannelMemberNotifyPropsValid(notifyProps map[string]string, allowMissingFields bool) *AppError {
|
||||
if notifyLevel, ok := notifyProps[DesktopNotifyProp]; ok || !allowMissingFields {
|
||||
if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error", nil, "notify_level="+notifyLevel, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if markUnreadLevel, ok := notifyProps[MarkUnreadNotifyProp]; ok || !allowMissingFields {
|
||||
if len(markUnreadLevel) > 20 || !IsChannelMarkUnreadLevelValid(markUnreadLevel) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.unread_level.app_error", nil, "mark_unread_level="+markUnreadLevel, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if pushLevel, ok := notifyProps[PushNotifyProp]; ok {
|
||||
if len(pushLevel) > 20 || !IsChannelNotifyLevelValid(pushLevel) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.push_level.app_error", nil, "push_notification_level="+pushLevel, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if sendEmail, ok := notifyProps[EmailNotifyProp]; ok {
|
||||
if len(sendEmail) > 20 || !IsSendEmailValid(sendEmail) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.email_value.app_error", nil, "push_notification_level="+sendEmail, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if ignoreChannelMentions, ok := notifyProps[IgnoreChannelMentionsNotifyProp]; ok {
|
||||
if len(ignoreChannelMentions) > 40 || !IsIgnoreChannelMentionsValid(ignoreChannelMentions) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.ignore_channel_mentions_value.app_error", nil, "ignore_channel_mentions="+ignoreChannelMentions, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if channelAutoFollowThreads, ok := notifyProps[ChannelAutoFollowThreads]; ok {
|
||||
if len(channelAutoFollowThreads) > 3 || !IsChannelAutoFollowThreadsValid(channelAutoFollowThreads) {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.channel_auto_follow_threads_value.app_error", nil, "channel_auto_follow_threads="+channelAutoFollowThreads, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
jsonStringNotifyProps := string(ToJSON(notifyProps))
|
||||
if utf8.RuneCountInString(jsonStringNotifyProps) > ChannelMemberNotifyPropsMaxRunes {
|
||||
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_props.app_error", nil, fmt.Sprint("length=", utf8.RuneCountInString(jsonStringNotifyProps)), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ChannelMember) PreSave() {
|
||||
o.LastUpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
func (o *ChannelMember) PreUpdate() {
|
||||
o.LastUpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
func (o *ChannelMember) GetRoles() []string {
|
||||
return strings.Fields(o.Roles)
|
||||
}
|
||||
|
||||
func (o *ChannelMember) SetChannelMuted(muted bool) {
|
||||
if o.IsChannelMuted() {
|
||||
o.NotifyProps[MarkUnreadNotifyProp] = ChannelMarkUnreadAll
|
||||
} else {
|
||||
o.NotifyProps[MarkUnreadNotifyProp] = ChannelMarkUnreadMention
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ChannelMember) IsChannelMuted() bool {
|
||||
return o.NotifyProps[MarkUnreadNotifyProp] == ChannelMarkUnreadMention
|
||||
}
|
||||
|
||||
func IsChannelNotifyLevelValid(notifyLevel string) bool {
|
||||
return notifyLevel == ChannelNotifyDefault ||
|
||||
notifyLevel == ChannelNotifyAll ||
|
||||
notifyLevel == ChannelNotifyMention ||
|
||||
notifyLevel == ChannelNotifyNone
|
||||
}
|
||||
|
||||
func IsChannelMarkUnreadLevelValid(markUnreadLevel string) bool {
|
||||
return markUnreadLevel == ChannelMarkUnreadAll || markUnreadLevel == ChannelMarkUnreadMention
|
||||
}
|
||||
|
||||
func IsSendEmailValid(sendEmail string) bool {
|
||||
return sendEmail == ChannelNotifyDefault || sendEmail == "true" || sendEmail == "false"
|
||||
}
|
||||
|
||||
func IsIgnoreChannelMentionsValid(ignoreChannelMentions string) bool {
|
||||
return ignoreChannelMentions == IgnoreChannelMentionsOn || ignoreChannelMentions == IgnoreChannelMentionsOff || ignoreChannelMentions == IgnoreChannelMentionsDefault
|
||||
}
|
||||
|
||||
func IsChannelAutoFollowThreadsValid(channelAutoFollowThreads string) bool {
|
||||
return channelAutoFollowThreads == ChannelAutoFollowThreadsOn || channelAutoFollowThreads == ChannelAutoFollowThreadsOff
|
||||
}
|
||||
|
||||
func GetDefaultChannelNotifyProps() StringMap {
|
||||
return StringMap{
|
||||
DesktopNotifyProp: ChannelNotifyDefault,
|
||||
MarkUnreadNotifyProp: ChannelMarkUnreadAll,
|
||||
PushNotifyProp: ChannelNotifyDefault,
|
||||
EmailNotifyProp: ChannelNotifyDefault,
|
||||
IgnoreChannelMentionsNotifyProp: IgnoreChannelMentionsDefault,
|
||||
ChannelAutoFollowThreads: ChannelAutoFollowThreadsOff,
|
||||
}
|
||||
}
|
||||
|
||||
type ChannelMemberIdentifier struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
UserId string `json:"user_id"`
|
||||
}
|
||||
11
vendor/github.com/mattermost/mattermost/server/public/model/channel_member_history.go
generated
vendored
Normal file
11
vendor/github.com/mattermost/mattermost/server/public/model/channel_member_history.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ChannelMemberHistory struct {
|
||||
ChannelId string
|
||||
UserId string
|
||||
JoinTime int64
|
||||
LeaveTime *int64
|
||||
}
|
||||
17
vendor/github.com/mattermost/mattermost/server/public/model/channel_member_history_result.go
generated
vendored
Normal file
17
vendor/github.com/mattermost/mattermost/server/public/model/channel_member_history_result.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ChannelMemberHistoryResult struct {
|
||||
ChannelId string
|
||||
UserId string
|
||||
JoinTime int64
|
||||
LeaveTime *int64
|
||||
|
||||
// these two fields are never set in the database - when we SELECT, we join on Users to get them
|
||||
UserEmail string `db:"Email"`
|
||||
Username string
|
||||
IsBot bool
|
||||
UserDeleteAt int64
|
||||
}
|
||||
28
vendor/github.com/mattermost/mattermost/server/public/model/channel_mentions.go
generated
vendored
Normal file
28
vendor/github.com/mattermost/mattermost/server/public/model/channel_mentions.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var channelMentionRegexp = regexp.MustCompile(`\B~[a-zA-Z0-9\-_]+`)
|
||||
|
||||
func ChannelMentions(message string) []string {
|
||||
var names []string
|
||||
|
||||
if strings.Contains(message, "~") {
|
||||
alreadyMentioned := make(map[string]bool)
|
||||
for _, match := range channelMentionRegexp.FindAllString(message, -1) {
|
||||
name := match[1:]
|
||||
if !alreadyMentioned[name] {
|
||||
names = append(names, name)
|
||||
alreadyMentioned[name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return names
|
||||
}
|
||||
23
vendor/github.com/mattermost/mattermost/server/public/model/channel_search.go
generated
vendored
Normal file
23
vendor/github.com/mattermost/mattermost/server/public/model/channel_search.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const ChannelSearchDefaultLimit = 50
|
||||
|
||||
type ChannelSearch struct {
|
||||
Term string `json:"term"`
|
||||
ExcludeDefaultChannels bool `json:"exclude_default_channels"`
|
||||
NotAssociatedToGroup string `json:"not_associated_to_group"`
|
||||
TeamIds []string `json:"team_ids"`
|
||||
GroupConstrained bool `json:"group_constrained"`
|
||||
ExcludeGroupConstrained bool `json:"exclude_group_constrained"`
|
||||
ExcludePolicyConstrained bool `json:"exclude_policy_constrained"`
|
||||
Public bool `json:"public"`
|
||||
Private bool `json:"private"`
|
||||
IncludeDeleted bool `json:"include_deleted"`
|
||||
IncludeSearchById bool `json:"include_search_by_id"`
|
||||
Deleted bool `json:"deleted"`
|
||||
Page *int `json:"page,omitempty"`
|
||||
PerPage *int `json:"per_page,omitempty"`
|
||||
}
|
||||
97
vendor/github.com/mattermost/mattermost/server/public/model/channel_sidebar.go
generated
vendored
Normal file
97
vendor/github.com/mattermost/mattermost/server/public/model/channel_sidebar.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type SidebarCategoryType string
|
||||
type SidebarCategorySorting string
|
||||
|
||||
const (
|
||||
// Each sidebar category has a 'type'. System categories are Channels, Favorites and DMs
|
||||
// All user-created categories will have type Custom
|
||||
SidebarCategoryChannels SidebarCategoryType = "channels"
|
||||
SidebarCategoryDirectMessages SidebarCategoryType = "direct_messages"
|
||||
SidebarCategoryFavorites SidebarCategoryType = "favorites"
|
||||
SidebarCategoryCustom SidebarCategoryType = "custom"
|
||||
// Increment to use when adding/reordering things in the sidebar
|
||||
MinimalSidebarSortDistance = 10
|
||||
// Default Sort Orders for categories
|
||||
DefaultSidebarSortOrderFavorites = 0
|
||||
DefaultSidebarSortOrderChannels = DefaultSidebarSortOrderFavorites + MinimalSidebarSortDistance
|
||||
DefaultSidebarSortOrderDMs = DefaultSidebarSortOrderChannels + MinimalSidebarSortDistance
|
||||
// Sorting modes
|
||||
// default for all categories except DMs (behaves like manual)
|
||||
SidebarCategorySortDefault SidebarCategorySorting = ""
|
||||
// sort manually
|
||||
SidebarCategorySortManual SidebarCategorySorting = "manual"
|
||||
// sort by recency (default for DMs)
|
||||
SidebarCategorySortRecent SidebarCategorySorting = "recent"
|
||||
// sort by display name alphabetically
|
||||
SidebarCategorySortAlphabetical SidebarCategorySorting = "alpha"
|
||||
)
|
||||
|
||||
// SidebarCategory represents the corresponding DB table
|
||||
type SidebarCategory struct {
|
||||
Id string `json:"id"`
|
||||
UserId string `json:"user_id"`
|
||||
TeamId string `json:"team_id"`
|
||||
SortOrder int64 `json:"sort_order"`
|
||||
Sorting SidebarCategorySorting `json:"sorting"`
|
||||
Type SidebarCategoryType `json:"type"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Muted bool `json:"muted"`
|
||||
Collapsed bool `json:"collapsed"`
|
||||
}
|
||||
|
||||
// SidebarCategoryWithChannels combines data from SidebarCategory table with the Channel IDs that belong to that category
|
||||
type SidebarCategoryWithChannels struct {
|
||||
SidebarCategory
|
||||
Channels []string `json:"channel_ids"`
|
||||
}
|
||||
|
||||
func (sc SidebarCategoryWithChannels) ChannelIds() []string {
|
||||
return sc.Channels
|
||||
}
|
||||
|
||||
type SidebarCategoryOrder []string
|
||||
|
||||
// OrderedSidebarCategories combines categories, their channel IDs and an array of Category IDs, sorted
|
||||
type OrderedSidebarCategories struct {
|
||||
Categories SidebarCategoriesWithChannels `json:"categories"`
|
||||
Order SidebarCategoryOrder `json:"order"`
|
||||
}
|
||||
|
||||
type SidebarChannel struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
UserId string `json:"user_id"`
|
||||
CategoryId string `json:"category_id"`
|
||||
SortOrder int64 `json:"-"`
|
||||
}
|
||||
|
||||
type SidebarChannels []*SidebarChannel
|
||||
type SidebarCategoriesWithChannels []*SidebarCategoryWithChannels
|
||||
|
||||
var categoryIdPattern = regexp.MustCompile("(favorites|channels|direct_messages)_[a-z0-9]{26}_[a-z0-9]{26}")
|
||||
|
||||
func IsValidCategoryId(s string) bool {
|
||||
// Category IDs can either be regular IDs
|
||||
if IsValidId(s) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Or default categories can follow the pattern {type}_{userID}_{teamID}
|
||||
return categoryIdPattern.MatchString(s)
|
||||
}
|
||||
|
||||
func (t SidebarCategoryType) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(string(t))
|
||||
}
|
||||
|
||||
func (t SidebarCategorySorting) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(string(t))
|
||||
}
|
||||
24
vendor/github.com/mattermost/mattermost/server/public/model/channel_stats.go
generated
vendored
Normal file
24
vendor/github.com/mattermost/mattermost/server/public/model/channel_stats.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ChannelStats struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
MemberCount int64 `json:"member_count"`
|
||||
GuestCount int64 `json:"guest_count"`
|
||||
PinnedPostCount int64 `json:"pinnedpost_count"`
|
||||
FilesCount int64 `json:"files_count"`
|
||||
}
|
||||
|
||||
func (o *ChannelStats) MemberCount_() float64 {
|
||||
return float64(o.MemberCount)
|
||||
}
|
||||
|
||||
func (o *ChannelStats) GuestCount_() float64 {
|
||||
return float64(o.GuestCount)
|
||||
}
|
||||
|
||||
func (o *ChannelStats) PinnedPostCount_() float64 {
|
||||
return float64(o.PinnedPostCount)
|
||||
}
|
||||
15
vendor/github.com/mattermost/mattermost/server/public/model/channel_view.go
generated
vendored
Normal file
15
vendor/github.com/mattermost/mattermost/server/public/model/channel_view.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ChannelView struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
PrevChannelId string `json:"prev_channel_id"`
|
||||
CollapsedThreadsSupported bool `json:"collapsed_threads_supported"`
|
||||
}
|
||||
|
||||
type ChannelViewResponse struct {
|
||||
Status string `json:"status"`
|
||||
LastViewedAtTimes map[string]int64 `json:"last_viewed_at_times"`
|
||||
}
|
||||
8887
vendor/github.com/mattermost/mattermost/server/public/model/client4.go
generated
vendored
Normal file
8887
vendor/github.com/mattermost/mattermost/server/public/model/client4.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
367
vendor/github.com/mattermost/mattermost/server/public/model/cloud.go
generated
vendored
Normal file
367
vendor/github.com/mattermost/mattermost/server/public/model/cloud.go
generated
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
EventTypeFailedPayment = "failed-payment"
|
||||
EventTypeFailedPaymentNoCard = "failed-payment-no-card"
|
||||
EventTypeSendAdminWelcomeEmail = "send-admin-welcome-email"
|
||||
EventTypeSendUpgradeConfirmationEmail = "send-upgrade-confirmation-email"
|
||||
EventTypeSubscriptionChanged = "subscription-changed"
|
||||
EventTypeTriggerDelinquencyEmail = "trigger-delinquency-email"
|
||||
)
|
||||
|
||||
const UpcomingInvoice = "upcoming"
|
||||
|
||||
var MockCWS string
|
||||
|
||||
type BillingScheme string
|
||||
|
||||
const (
|
||||
BillingSchemePerSeat = BillingScheme("per_seat")
|
||||
BillingSchemeFlatFee = BillingScheme("flat_fee")
|
||||
BillingSchemeSalesServe = BillingScheme("sales_serve")
|
||||
)
|
||||
|
||||
type BillingType string
|
||||
|
||||
const (
|
||||
BillingTypeLicensed = BillingType("licensed")
|
||||
BillingTypeInternal = BillingType("internal")
|
||||
)
|
||||
|
||||
type RecurringInterval string
|
||||
|
||||
const (
|
||||
RecurringIntervalYearly = RecurringInterval("year")
|
||||
RecurringIntervalMonthly = RecurringInterval("month")
|
||||
)
|
||||
|
||||
type SubscriptionFamily string
|
||||
|
||||
const (
|
||||
SubscriptionFamilyCloud = SubscriptionFamily("cloud")
|
||||
SubscriptionFamilyOnPrem = SubscriptionFamily("on-prem")
|
||||
)
|
||||
|
||||
type ProductSku string
|
||||
|
||||
const (
|
||||
SkuStarterGov = ProductSku("starter-gov")
|
||||
SkuProfessionalGov = ProductSku("professional-gov")
|
||||
SkuEnterpriseGov = ProductSku("enterprise-gov")
|
||||
SkuStarter = ProductSku("starter")
|
||||
SkuProfessional = ProductSku("professional")
|
||||
SkuEnterprise = ProductSku("enterprise")
|
||||
SkuCloudStarter = ProductSku("cloud-starter")
|
||||
SkuCloudProfessional = ProductSku("cloud-professional")
|
||||
SkuCloudEnterprise = ProductSku("cloud-enterprise")
|
||||
)
|
||||
|
||||
// Product model represents a product on the cloud system.
|
||||
type Product struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
PricePerSeat float64 `json:"price_per_seat"`
|
||||
AddOns []*AddOn `json:"add_ons"`
|
||||
SKU string `json:"sku"`
|
||||
PriceID string `json:"price_id"`
|
||||
Family SubscriptionFamily `json:"product_family"`
|
||||
RecurringInterval RecurringInterval `json:"recurring_interval"`
|
||||
BillingScheme BillingScheme `json:"billing_scheme"`
|
||||
CrossSellsTo string `json:"cross_sells_to"`
|
||||
}
|
||||
|
||||
type UserFacingProduct struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
SKU string `json:"sku"`
|
||||
PricePerSeat float64 `json:"price_per_seat"`
|
||||
RecurringInterval RecurringInterval `json:"recurring_interval"`
|
||||
CrossSellsTo string `json:"cross_sells_to"`
|
||||
}
|
||||
|
||||
// AddOn represents an addon to a product.
|
||||
type AddOn struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
PricePerSeat float64 `json:"price_per_seat"`
|
||||
}
|
||||
|
||||
// StripeSetupIntent represents the SetupIntent model from Stripe for updating payment methods.
|
||||
type StripeSetupIntent struct {
|
||||
ID string `json:"id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
}
|
||||
|
||||
// ConfirmPaymentMethodRequest contains the fields for the customer payment update API.
|
||||
type ConfirmPaymentMethodRequest struct {
|
||||
StripeSetupIntentID string `json:"stripe_setup_intent_id"`
|
||||
SubscriptionID string `json:"subscription_id"`
|
||||
}
|
||||
|
||||
// Customer model represents a customer on the system.
|
||||
type CloudCustomer struct {
|
||||
CloudCustomerInfo
|
||||
ID string `json:"id"`
|
||||
CreatorID string `json:"creator_id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
BillingAddress *Address `json:"billing_address"`
|
||||
CompanyAddress *Address `json:"company_address"`
|
||||
PaymentMethod *PaymentMethod `json:"payment_method"`
|
||||
}
|
||||
|
||||
type StartCloudTrialRequest struct {
|
||||
Email string `json:"email"`
|
||||
SubscriptionID string `json:"subscription_id"`
|
||||
}
|
||||
|
||||
type ValidateBusinessEmailRequest struct {
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type ValidateBusinessEmailResponse struct {
|
||||
IsValid bool `json:"is_valid"`
|
||||
}
|
||||
|
||||
type SubscriptionLicenseSelfServeStatusResponse struct {
|
||||
IsExpandable bool `json:"is_expandable"`
|
||||
IsRenewable bool `json:"is_renewable"`
|
||||
}
|
||||
|
||||
// CloudCustomerInfo represents editable info of a customer.
|
||||
type CloudCustomerInfo struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email,omitempty"`
|
||||
ContactFirstName string `json:"contact_first_name,omitempty"`
|
||||
ContactLastName string `json:"contact_last_name,omitempty"`
|
||||
NumEmployees int `json:"num_employees"`
|
||||
CloudAltPaymentMethod string `json:"monthly_subscription_alt_payment_method"`
|
||||
}
|
||||
|
||||
// Address model represents a customer's address.
|
||||
type Address struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
Line1 string `json:"line1"`
|
||||
Line2 string `json:"line2"`
|
||||
PostalCode string `json:"postal_code"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
// PaymentMethod represents methods of payment for a customer.
|
||||
type PaymentMethod struct {
|
||||
Type string `json:"type"`
|
||||
LastFour string `json:"last_four"`
|
||||
ExpMonth int `json:"exp_month"`
|
||||
ExpYear int `json:"exp_year"`
|
||||
CardBrand string `json:"card_brand"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Subscription model represents a subscription on the system.
|
||||
type Subscription struct {
|
||||
ID string `json:"id"`
|
||||
CustomerID string `json:"customer_id"`
|
||||
ProductID string `json:"product_id"`
|
||||
AddOns []string `json:"add_ons"`
|
||||
StartAt int64 `json:"start_at"`
|
||||
EndAt int64 `json:"end_at"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
Seats int `json:"seats"`
|
||||
Status string `json:"status"`
|
||||
DNS string `json:"dns"`
|
||||
LastInvoice *Invoice `json:"last_invoice"`
|
||||
UpcomingInvoice *Invoice `json:"upcoming_invoice"`
|
||||
IsFreeTrial string `json:"is_free_trial"`
|
||||
TrialEndAt int64 `json:"trial_end_at"`
|
||||
DelinquentSince *int64 `json:"delinquent_since"`
|
||||
OriginallyLicensedSeats int `json:"originally_licensed_seats"`
|
||||
ComplianceBlocked string `json:"compliance_blocked"`
|
||||
BillingType string `json:"billing_type"`
|
||||
CancelAt *int64 `json:"cancel_at"`
|
||||
WillRenew string `json:"will_renew"`
|
||||
SimulatedCurrentTimeMs *int64 `json:"simulated_current_time_ms"`
|
||||
}
|
||||
|
||||
func (s *Subscription) DaysToExpiration() int64 {
|
||||
now := time.Now().UnixMilli()
|
||||
if GetServiceEnvironment() == ServiceEnvironmentTest {
|
||||
// In the test environment we have test clocks. A test clock is a ms timestamp
|
||||
// If it's not nil, we use it as the current time in all calculations
|
||||
if s.SimulatedCurrentTimeMs != nil {
|
||||
now = *s.SimulatedCurrentTimeMs
|
||||
}
|
||||
}
|
||||
daysToExpiry := (s.EndAt - now) / (1000 * 60 * 60 * 24)
|
||||
return daysToExpiry
|
||||
}
|
||||
|
||||
// Subscription History model represents true up event in a yearly subscription
|
||||
type SubscriptionHistory struct {
|
||||
ID string `json:"id"`
|
||||
SubscriptionID string `json:"subscription_id"`
|
||||
Seats int `json:"seats"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
}
|
||||
|
||||
type SubscriptionHistoryChange struct {
|
||||
SubscriptionID string `json:"subscription_id"`
|
||||
Seats int `json:"seats"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
}
|
||||
|
||||
// GetWorkSpaceNameFromDNS returns the work space name. For example from test.mattermost.cloud.com, it returns test
|
||||
func (s *Subscription) GetWorkSpaceNameFromDNS() string {
|
||||
return strings.Split(s.DNS, ".")[0]
|
||||
}
|
||||
|
||||
// Invoice model represents a cloud invoice
|
||||
type Invoice struct {
|
||||
ID string `json:"id"`
|
||||
Number string `json:"number"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
Total int64 `json:"total"`
|
||||
Tax int64 `json:"tax"`
|
||||
Status string `json:"status"`
|
||||
Description string `json:"description"`
|
||||
PeriodStart int64 `json:"period_start"`
|
||||
PeriodEnd int64 `json:"period_end"`
|
||||
SubscriptionID string `json:"subscription_id"`
|
||||
Items []*InvoiceLineItem `json:"line_items"`
|
||||
CurrentProductName string `json:"current_product_name"`
|
||||
}
|
||||
|
||||
// InvoiceLineItem model represents a cloud invoice lineitem tied to an invoice.
|
||||
type InvoiceLineItem struct {
|
||||
PriceID string `json:"price_id"`
|
||||
Total int64 `json:"total"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
PricePerUnit int64 `json:"price_per_unit"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
PeriodStart int64 `json:"period_start"`
|
||||
PeriodEnd int64 `json:"period_end"`
|
||||
}
|
||||
|
||||
type DelinquencyEmailTrigger struct {
|
||||
EmailToTrigger string `json:"email_to_send"`
|
||||
}
|
||||
|
||||
type DelinquencyEmail string
|
||||
|
||||
const (
|
||||
DelinquencyEmail7 DelinquencyEmail = "7"
|
||||
DelinquencyEmail14 DelinquencyEmail = "14"
|
||||
DelinquencyEmail30 DelinquencyEmail = "30"
|
||||
DelinquencyEmail45 DelinquencyEmail = "45"
|
||||
DelinquencyEmail60 DelinquencyEmail = "60"
|
||||
DelinquencyEmail75 DelinquencyEmail = "75"
|
||||
DelinquencyEmail90 DelinquencyEmail = "90"
|
||||
)
|
||||
|
||||
type CWSWebhookPayload struct {
|
||||
Event string `json:"event"`
|
||||
FailedPayment *FailedPayment `json:"failed_payment"`
|
||||
CloudWorkspaceOwner *CloudWorkspaceOwner `json:"cloud_workspace_owner"`
|
||||
ProductLimits *ProductLimits `json:"product_limits"`
|
||||
Subscription *Subscription `json:"subscription"`
|
||||
SubscriptionTrialEndUnixTimeStamp int64 `json:"trial_end_time_stamp"`
|
||||
DelinquencyEmail *DelinquencyEmailTrigger `json:"delinquency_email"`
|
||||
}
|
||||
|
||||
type FailedPayment struct {
|
||||
CardBrand string `json:"card_brand"`
|
||||
LastFour string `json:"last_four"`
|
||||
FailureMessage string `json:"failure_message"`
|
||||
}
|
||||
|
||||
// CloudWorkspaceOwner is part of the CWS Webhook payload that contains information about the user that created the workspace from the CWS
|
||||
type CloudWorkspaceOwner struct {
|
||||
UserName string `json:"username"`
|
||||
}
|
||||
|
||||
type SubscriptionChange struct {
|
||||
ProductID string `json:"product_id"`
|
||||
Seats int `json:"seats"`
|
||||
Feedback *Feedback `json:"downgrade_feedback"`
|
||||
ShippingAddress *Address `json:"shipping_address"`
|
||||
Customer *CloudCustomerInfo `json:"customer"`
|
||||
}
|
||||
|
||||
type FilesLimits struct {
|
||||
TotalStorage *int64 `json:"total_storage"`
|
||||
}
|
||||
|
||||
type MessagesLimits struct {
|
||||
History *int `json:"history"`
|
||||
}
|
||||
|
||||
type TeamsLimits struct {
|
||||
Active *int `json:"active"`
|
||||
}
|
||||
|
||||
type ProductLimits struct {
|
||||
Files *FilesLimits `json:"files,omitempty"`
|
||||
Messages *MessagesLimits `json:"messages,omitempty"`
|
||||
Teams *TeamsLimits `json:"teams,omitempty"`
|
||||
}
|
||||
|
||||
// CreateSubscriptionRequest is the parameters for the API request to create a subscription.
|
||||
type CreateSubscriptionRequest struct {
|
||||
ProductID string `json:"product_id"`
|
||||
AddOns []string `json:"add_ons"`
|
||||
Seats int `json:"seats"`
|
||||
Total float64 `json:"total"`
|
||||
InternalPurchaseOrder string `json:"internal_purchase_order"`
|
||||
DiscountID string `json:"discount_id"`
|
||||
}
|
||||
|
||||
type Installation struct {
|
||||
ID string `json:"id"`
|
||||
State string `json:"state"`
|
||||
AllowedIPRanges *AllowedIPRanges `json:"allowed_ip_ranges"`
|
||||
}
|
||||
|
||||
type Feedback struct {
|
||||
Reason string `json:"reason"`
|
||||
Comments string `json:"comments"`
|
||||
}
|
||||
|
||||
type WorkspaceDeletionRequest struct {
|
||||
SubscriptionID string `json:"subscription_id"`
|
||||
Feedback *Feedback `json:"delete_feedback"`
|
||||
}
|
||||
|
||||
func (p *Product) IsYearly() bool {
|
||||
return p.RecurringInterval == RecurringIntervalYearly
|
||||
}
|
||||
|
||||
func (p *Product) IsMonthly() bool {
|
||||
return p.RecurringInterval == RecurringIntervalMonthly
|
||||
}
|
||||
|
||||
func (df *Feedback) ToMap() map[string]any {
|
||||
var res map[string]any
|
||||
feedback, err := json.Marshal(df)
|
||||
if err != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
err = json.Unmarshal(feedback, &res)
|
||||
if err != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
115
vendor/github.com/mattermost/mattermost/server/public/model/cluster_discovery.go
generated
vendored
Normal file
115
vendor/github.com/mattermost/mattermost/server/public/model/cluster_discovery.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
CDSOfflineAfterMillis = 1000 * 60 * 30 // 30 minutes
|
||||
CDSTypeApp = "mattermost_app"
|
||||
)
|
||||
|
||||
type ClusterDiscovery struct {
|
||||
Id string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
ClusterName string `json:"cluster_name"`
|
||||
Hostname string `json:"hostname"`
|
||||
GossipPort int32 `json:"gossip_port"`
|
||||
Port int32 `json:"port"` // Deperacted: Port is unused. It's only kept for backwards compatibility.
|
||||
CreateAt int64 `json:"create_at"`
|
||||
LastPingAt int64 `json:"last_ping_at"`
|
||||
}
|
||||
|
||||
func (o *ClusterDiscovery) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
o.CreateAt = GetMillis()
|
||||
o.LastPingAt = o.CreateAt
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ClusterDiscovery) AutoFillHostname() {
|
||||
// attempt to set the hostname from the OS
|
||||
if o.Hostname == "" {
|
||||
if hn, err := os.Hostname(); err == nil {
|
||||
o.Hostname = hn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ClusterDiscovery) AutoFillIPAddress(iface string, ipAddress string) {
|
||||
// attempt to set the hostname to the first non-local IP address
|
||||
if o.Hostname == "" {
|
||||
if ipAddress != "" {
|
||||
o.Hostname = ipAddress
|
||||
} else {
|
||||
o.Hostname = GetServerIPAddress(iface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ClusterDiscovery) IsEqual(in *ClusterDiscovery) bool {
|
||||
if in == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if o.Type != in.Type {
|
||||
return false
|
||||
}
|
||||
|
||||
if o.ClusterName != in.ClusterName {
|
||||
return false
|
||||
}
|
||||
|
||||
if o.Hostname != in.Hostname {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func FilterClusterDiscovery(vs []*ClusterDiscovery, f func(*ClusterDiscovery) bool) []*ClusterDiscovery {
|
||||
cdCopy := make([]*ClusterDiscovery, 0)
|
||||
for _, v := range vs {
|
||||
if f(v) {
|
||||
cdCopy = append(cdCopy, v)
|
||||
}
|
||||
}
|
||||
|
||||
return cdCopy
|
||||
}
|
||||
|
||||
func (o *ClusterDiscovery) IsValid() *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.ClusterName == "" {
|
||||
return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.Type == "" {
|
||||
return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.Hostname == "" {
|
||||
return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.hostname.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.LastPingAt == 0 {
|
||||
return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.last_ping_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
13
vendor/github.com/mattermost/mattermost/server/public/model/cluster_info.go
generated
vendored
Normal file
13
vendor/github.com/mattermost/mattermost/server/public/model/cluster_info.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ClusterInfo struct {
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
ConfigHash string `json:"config_hash"`
|
||||
IPAddress string `json:"ipaddress"`
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
68
vendor/github.com/mattermost/mattermost/server/public/model/cluster_message.go
generated
vendored
Normal file
68
vendor/github.com/mattermost/mattermost/server/public/model/cluster_message.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ClusterEvent string
|
||||
|
||||
const (
|
||||
ClusterEventPublish ClusterEvent = "publish"
|
||||
ClusterEventUpdateStatus ClusterEvent = "update_status"
|
||||
ClusterEventInvalidateAllCaches ClusterEvent = "inv_all_caches"
|
||||
ClusterEventInvalidateCacheForReactions ClusterEvent = "inv_reactions"
|
||||
ClusterEventInvalidateCacheForChannelMembersNotifyProps ClusterEvent = "inv_channel_members_notify_props"
|
||||
ClusterEventInvalidateCacheForChannelByName ClusterEvent = "inv_channel_name"
|
||||
ClusterEventInvalidateCacheForChannel ClusterEvent = "inv_channel"
|
||||
ClusterEventInvalidateCacheForChannelGuestCount ClusterEvent = "inv_channel_guest_count"
|
||||
ClusterEventInvalidateCacheForUser ClusterEvent = "inv_user"
|
||||
ClusterEventInvalidateCacheForUserTeams ClusterEvent = "inv_user_teams"
|
||||
ClusterEventClearSessionCacheForUser ClusterEvent = "clear_session_user"
|
||||
ClusterEventInvalidateCacheForRoles ClusterEvent = "inv_roles"
|
||||
ClusterEventInvalidateCacheForRolePermissions ClusterEvent = "inv_role_permissions"
|
||||
ClusterEventInvalidateCacheForProfileByIds ClusterEvent = "inv_profile_ids"
|
||||
ClusterEventInvalidateCacheForAllProfiles ClusterEvent = "inv_all_profiles"
|
||||
ClusterEventInvalidateCacheForProfileInChannel ClusterEvent = "inv_profile_in_channel"
|
||||
ClusterEventInvalidateCacheForSchemes ClusterEvent = "inv_schemes"
|
||||
ClusterEventInvalidateCacheForFileInfos ClusterEvent = "inv_file_infos"
|
||||
ClusterEventInvalidateCacheForWebhooks ClusterEvent = "inv_webhooks"
|
||||
ClusterEventInvalidateCacheForEmojisById ClusterEvent = "inv_emojis_by_id"
|
||||
ClusterEventInvalidateCacheForEmojisIdByName ClusterEvent = "inv_emojis_id_by_name"
|
||||
ClusterEventInvalidateCacheForChannelFileCount ClusterEvent = "inv_channel_file_count"
|
||||
ClusterEventInvalidateCacheForChannelPinnedpostsCounts ClusterEvent = "inv_channel_pinnedposts_counts"
|
||||
ClusterEventInvalidateCacheForChannelMemberCounts ClusterEvent = "inv_channel_member_counts"
|
||||
ClusterEventInvalidateCacheForChannelsMemberCount ClusterEvent = "inv_channels_member_count"
|
||||
ClusterEventInvalidateCacheForLastPosts ClusterEvent = "inv_last_posts"
|
||||
ClusterEventInvalidateCacheForLastPostTime ClusterEvent = "inv_last_post_time"
|
||||
ClusterEventInvalidateCacheForPostsUsage ClusterEvent = "inv_posts_usage"
|
||||
ClusterEventInvalidateCacheForTeams ClusterEvent = "inv_teams"
|
||||
ClusterEventClearSessionCacheForAllUsers ClusterEvent = "inv_all_user_sessions"
|
||||
ClusterEventInstallPlugin ClusterEvent = "install_plugin"
|
||||
ClusterEventRemovePlugin ClusterEvent = "remove_plugin"
|
||||
ClusterEventPluginEvent ClusterEvent = "plugin_event"
|
||||
ClusterEventInvalidateCacheForTermsOfService ClusterEvent = "inv_terms_of_service"
|
||||
ClusterEventBusyStateChanged ClusterEvent = "busy_state_change"
|
||||
|
||||
// Gossip communication
|
||||
ClusterGossipEventRequestGetLogs = "gossip_request_get_logs"
|
||||
ClusterGossipEventResponseGetLogs = "gossip_response_get_logs"
|
||||
ClusterGossipEventRequestGetClusterStats = "gossip_request_cluster_stats"
|
||||
ClusterGossipEventResponseGetClusterStats = "gossip_response_cluster_stats"
|
||||
ClusterGossipEventRequestGetPluginStatuses = "gossip_request_plugin_statuses"
|
||||
ClusterGossipEventResponseGetPluginStatuses = "gossip_response_plugin_statuses"
|
||||
ClusterGossipEventRequestSaveConfig = "gossip_request_save_config"
|
||||
ClusterGossipEventResponseSaveConfig = "gossip_response_save_config"
|
||||
ClusterGossipEventRequestWebConnCount = "gossip_request_webconn_count"
|
||||
ClusterGossipEventResponseWebConnCount = "gossip_response_webconn_count"
|
||||
|
||||
// SendTypes for ClusterMessage.
|
||||
ClusterSendBestEffort = "best_effort"
|
||||
ClusterSendReliable = "reliable"
|
||||
)
|
||||
|
||||
type ClusterMessage struct {
|
||||
Event ClusterEvent `json:"event"`
|
||||
SendType string `json:"-"`
|
||||
WaitForAllToSend bool `json:"-"`
|
||||
Data []byte `json:"data,omitempty"`
|
||||
Props map[string]string `json:"props,omitempty"`
|
||||
}
|
||||
11
vendor/github.com/mattermost/mattermost/server/public/model/cluster_stats.go
generated
vendored
Normal file
11
vendor/github.com/mattermost/mattermost/server/public/model/cluster_stats.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ClusterStats struct {
|
||||
Id string `json:"id"`
|
||||
TotalWebsocketConnections int `json:"total_websocket_connections"`
|
||||
TotalReadDbConnections int `json:"total_read_db_connections"`
|
||||
TotalMasterDbConnections int `json:"total_master_db_connections"`
|
||||
}
|
||||
156
vendor/github.com/mattermost/mattermost/server/public/model/command.go
generated
vendored
Normal file
156
vendor/github.com/mattermost/mattermost/server/public/model/command.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CommandMethodPost = "P"
|
||||
CommandMethodGet = "G"
|
||||
MinTriggerLength = 1
|
||||
MaxTriggerLength = 128
|
||||
)
|
||||
|
||||
type Command struct {
|
||||
Id string `json:"id"`
|
||||
Token string `json:"token"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
CreatorId string `json:"creator_id"`
|
||||
TeamId string `json:"team_id"`
|
||||
Trigger string `json:"trigger"`
|
||||
Method string `json:"method"`
|
||||
Username string `json:"username"`
|
||||
IconURL string `json:"icon_url"`
|
||||
AutoComplete bool `json:"auto_complete"`
|
||||
AutoCompleteDesc string `json:"auto_complete_desc"`
|
||||
AutoCompleteHint string `json:"auto_complete_hint"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Description string `json:"description"`
|
||||
URL string `json:"url"`
|
||||
// PluginId records the id of the plugin that created this Command. If it is blank, the Command
|
||||
// was not created by a plugin.
|
||||
PluginId string `json:"plugin_id"`
|
||||
AutocompleteData *AutocompleteData `db:"-" json:"autocomplete_data,omitempty"`
|
||||
// AutocompleteIconData is a base64 encoded svg
|
||||
AutocompleteIconData string `db:"-" json:"autocomplete_icon_data,omitempty"`
|
||||
}
|
||||
|
||||
func (o *Command) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": o.Id,
|
||||
"create_at": o.CreateAt,
|
||||
"update_at": o.UpdateAt,
|
||||
"delete_at": o.DeleteAt,
|
||||
"creator_id": o.CreatorId,
|
||||
"team_id": o.TeamId,
|
||||
"trigger": o.Trigger,
|
||||
"username": o.Username,
|
||||
"icon_url": o.IconURL,
|
||||
"auto_complete": o.AutoComplete,
|
||||
"auto_complete_desc": o.AutoCompleteDesc,
|
||||
"auto_complete_hint": o.AutoCompleteHint,
|
||||
"display_name": o.DisplayName,
|
||||
"description": o.Description,
|
||||
"url": o.URL,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Command) IsValid() *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Token) != 26 {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.token.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.UpdateAt == 0 {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.update_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// If the CreatorId is blank, this should be a command created by a plugin.
|
||||
if o.CreatorId == "" && !IsValidPluginId(o.PluginId) {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.plugin_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// If the PluginId is blank, this should be a command associated with a userId.
|
||||
if o.PluginId == "" && !IsValidId(o.CreatorId) {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreatorId != "" && o.PluginId != "" {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.plugin_id.app_error", nil, "command cannot have both a CreatorId and a PluginId", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.TeamId) {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Trigger) < MinTriggerLength || len(o.Trigger) > MaxTriggerLength || strings.Index(o.Trigger, "/") == 0 || strings.Contains(o.Trigger, " ") {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.URL == "" || len(o.URL) > 1024 {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.url.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidHTTPURL(o.URL) {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.url_http.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !(o.Method == CommandMethodGet || o.Method == CommandMethodPost) {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.method.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.DisplayName) > 64 {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.display_name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Description) > 128 {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.description.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.AutocompleteData != nil {
|
||||
if err := o.AutocompleteData.IsValid(); err != nil {
|
||||
return NewAppError("Command.IsValid", "model.command.is_valid.autocomplete_data.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Command) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
if o.Token == "" {
|
||||
o.Token = NewId()
|
||||
}
|
||||
|
||||
o.CreateAt = GetMillis()
|
||||
o.UpdateAt = o.CreateAt
|
||||
}
|
||||
|
||||
func (o *Command) PreUpdate() {
|
||||
o.UpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
func (o *Command) Sanitize() {
|
||||
o.Token = ""
|
||||
o.CreatorId = ""
|
||||
o.Method = ""
|
||||
o.URL = ""
|
||||
o.Username = ""
|
||||
o.IconURL = ""
|
||||
}
|
||||
55
vendor/github.com/mattermost/mattermost/server/public/model/command_args.go
generated
vendored
Normal file
55
vendor/github.com/mattermost/mattermost/server/public/model/command_args.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost/server/public/shared/i18n"
|
||||
)
|
||||
|
||||
type CommandArgs struct {
|
||||
UserId string `json:"user_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
TeamId string `json:"team_id"`
|
||||
RootId string `json:"root_id"`
|
||||
ParentId string `json:"parent_id"`
|
||||
TriggerId string `json:"trigger_id,omitempty"`
|
||||
Command string `json:"command"`
|
||||
SiteURL string `json:"-"`
|
||||
T i18n.TranslateFunc `json:"-"`
|
||||
UserMentions UserMentionMap `json:"-"`
|
||||
ChannelMentions ChannelMentionMap `json:"-"`
|
||||
}
|
||||
|
||||
func (o *CommandArgs) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"user_id": o.UserId,
|
||||
"channel_id": o.ChannelId,
|
||||
"team_id": o.TeamId,
|
||||
"root_id": o.RootId,
|
||||
"parent_id": o.ParentId,
|
||||
"trigger_id": o.TriggerId,
|
||||
"command": o.Command,
|
||||
"site_url": o.SiteURL,
|
||||
}
|
||||
}
|
||||
|
||||
// AddUserMention adds or overrides an entry in UserMentions with name username
|
||||
// and identifier userId
|
||||
func (o *CommandArgs) AddUserMention(username, userId string) {
|
||||
if o.UserMentions == nil {
|
||||
o.UserMentions = make(UserMentionMap)
|
||||
}
|
||||
|
||||
o.UserMentions[username] = userId
|
||||
}
|
||||
|
||||
// AddChannelMention adds or overrides an entry in ChannelMentions with name
|
||||
// channelName and identifier channelId
|
||||
func (o *CommandArgs) AddChannelMention(channelName, channelId string) {
|
||||
if o.ChannelMentions == nil {
|
||||
o.ChannelMentions = make(ChannelMentionMap)
|
||||
}
|
||||
|
||||
o.ChannelMentions[channelName] = channelId
|
||||
}
|
||||
401
vendor/github.com/mattermost/mattermost/server/public/model/command_autocomplete.go
generated
vendored
Normal file
401
vendor/github.com/mattermost/mattermost/server/public/model/command_autocomplete.go
generated
vendored
Normal file
@@ -0,0 +1,401 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"path"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// AutocompleteArgType describes autocomplete argument type
|
||||
type AutocompleteArgType string
|
||||
|
||||
// Argument types
|
||||
const (
|
||||
AutocompleteArgTypeText AutocompleteArgType = "TextInput"
|
||||
AutocompleteArgTypeStaticList AutocompleteArgType = "StaticList"
|
||||
AutocompleteArgTypeDynamicList AutocompleteArgType = "DynamicList"
|
||||
)
|
||||
|
||||
// AutocompleteData describes slash command autocomplete information.
|
||||
type AutocompleteData struct {
|
||||
// Trigger of the command
|
||||
Trigger string
|
||||
// Hint of a command
|
||||
Hint string
|
||||
// Text displayed to the user to help with the autocomplete description
|
||||
HelpText string
|
||||
// Role of the user who should be able to see the autocomplete info of this command
|
||||
RoleID string
|
||||
// Arguments of the command. Arguments can be named or positional.
|
||||
// If they are positional order in the list matters, if they are named order does not matter.
|
||||
// All arguments should be either named or positional, no mixing allowed.
|
||||
Arguments []*AutocompleteArg
|
||||
// Subcommands of the command
|
||||
SubCommands []*AutocompleteData
|
||||
}
|
||||
|
||||
// AutocompleteArg describes an argument of the command. Arguments can be named or positional.
|
||||
// If Name is empty string Argument is positional otherwise it is named argument.
|
||||
// Named arguments are passed as --Name Argument_Value.
|
||||
type AutocompleteArg struct {
|
||||
// Name of the argument
|
||||
Name string
|
||||
// Text displayed to the user to help with the autocomplete
|
||||
HelpText string
|
||||
// Type of the argument
|
||||
Type AutocompleteArgType
|
||||
// Required determines if argument is optional or not.
|
||||
Required bool
|
||||
// Actual data of the argument (depends on the Type)
|
||||
Data any
|
||||
}
|
||||
|
||||
// AutocompleteTextArg describes text user can input as an argument.
|
||||
type AutocompleteTextArg struct {
|
||||
// Hint of the input text
|
||||
Hint string
|
||||
// Regex pattern to match
|
||||
Pattern string
|
||||
}
|
||||
|
||||
// AutocompleteListItem describes an item in the AutocompleteStaticListArg.
|
||||
type AutocompleteListItem struct {
|
||||
Item string
|
||||
Hint string
|
||||
HelpText string
|
||||
}
|
||||
|
||||
// AutocompleteStaticListArg is used to input one of the arguments from the list,
|
||||
// for example [yes, no], [on, off], and so on.
|
||||
type AutocompleteStaticListArg struct {
|
||||
PossibleArguments []AutocompleteListItem
|
||||
}
|
||||
|
||||
// AutocompleteDynamicListArg is used when user wants to download possible argument list from the URL.
|
||||
type AutocompleteDynamicListArg struct {
|
||||
FetchURL string
|
||||
}
|
||||
|
||||
// AutocompleteSuggestion describes a single suggestion item sent to the front-end
|
||||
// Example: for user input `/jira cre` -
|
||||
// Complete might be `/jira create`
|
||||
// Suggestion might be `create`,
|
||||
// Hint might be `[issue text]`,
|
||||
// Description might be `Create a new Issue`
|
||||
type AutocompleteSuggestion struct {
|
||||
// Complete describes completed suggestion
|
||||
Complete string
|
||||
// Suggestion describes what user might want to input next
|
||||
Suggestion string
|
||||
// Hint describes a hint about the suggested input
|
||||
Hint string
|
||||
// Description of the command or a suggestion
|
||||
Description string
|
||||
// IconData is base64 encoded svg image
|
||||
IconData string
|
||||
}
|
||||
|
||||
// NewAutocompleteData returns new Autocomplete data.
|
||||
func NewAutocompleteData(trigger, hint, helpText string) *AutocompleteData {
|
||||
return &AutocompleteData{
|
||||
Trigger: trigger,
|
||||
Hint: hint,
|
||||
HelpText: helpText,
|
||||
RoleID: SystemUserRoleId,
|
||||
Arguments: []*AutocompleteArg{},
|
||||
SubCommands: []*AutocompleteData{},
|
||||
}
|
||||
}
|
||||
|
||||
// AddCommand adds a subcommand to the autocomplete data.
|
||||
func (ad *AutocompleteData) AddCommand(command *AutocompleteData) {
|
||||
ad.SubCommands = append(ad.SubCommands, command)
|
||||
}
|
||||
|
||||
// AddTextArgument adds positional AutocompleteArgTypeText argument to the command.
|
||||
func (ad *AutocompleteData) AddTextArgument(helpText, hint, pattern string) {
|
||||
ad.AddNamedTextArgument("", helpText, hint, pattern, true)
|
||||
}
|
||||
|
||||
// AddNamedTextArgument adds named AutocompleteArgTypeText argument to the command.
|
||||
func (ad *AutocompleteData) AddNamedTextArgument(name, helpText, hint, pattern string, required bool) {
|
||||
argument := AutocompleteArg{
|
||||
Name: name,
|
||||
HelpText: helpText,
|
||||
Type: AutocompleteArgTypeText,
|
||||
Required: required,
|
||||
Data: &AutocompleteTextArg{Hint: hint, Pattern: pattern},
|
||||
}
|
||||
ad.Arguments = append(ad.Arguments, &argument)
|
||||
}
|
||||
|
||||
// AddStaticListArgument adds positional AutocompleteArgTypeStaticList argument to the command.
|
||||
func (ad *AutocompleteData) AddStaticListArgument(helpText string, required bool, items []AutocompleteListItem) {
|
||||
ad.AddNamedStaticListArgument("", helpText, required, items)
|
||||
}
|
||||
|
||||
// AddNamedStaticListArgument adds named AutocompleteArgTypeStaticList argument to the command.
|
||||
func (ad *AutocompleteData) AddNamedStaticListArgument(name, helpText string, required bool, items []AutocompleteListItem) {
|
||||
argument := AutocompleteArg{
|
||||
Name: name,
|
||||
HelpText: helpText,
|
||||
Type: AutocompleteArgTypeStaticList,
|
||||
Required: required,
|
||||
Data: &AutocompleteStaticListArg{PossibleArguments: items},
|
||||
}
|
||||
ad.Arguments = append(ad.Arguments, &argument)
|
||||
}
|
||||
|
||||
// AddDynamicListArgument adds positional AutocompleteArgTypeDynamicList argument to the command.
|
||||
func (ad *AutocompleteData) AddDynamicListArgument(helpText, url string, required bool) {
|
||||
ad.AddNamedDynamicListArgument("", helpText, url, required)
|
||||
}
|
||||
|
||||
// AddNamedDynamicListArgument adds named AutocompleteArgTypeDynamicList argument to the command.
|
||||
func (ad *AutocompleteData) AddNamedDynamicListArgument(name, helpText, url string, required bool) {
|
||||
argument := AutocompleteArg{
|
||||
Name: name,
|
||||
HelpText: helpText,
|
||||
Type: AutocompleteArgTypeDynamicList,
|
||||
Required: required,
|
||||
Data: &AutocompleteDynamicListArg{FetchURL: url},
|
||||
}
|
||||
ad.Arguments = append(ad.Arguments, &argument)
|
||||
}
|
||||
|
||||
// Equals method checks if command is the same.
|
||||
func (ad *AutocompleteData) Equals(command *AutocompleteData) bool {
|
||||
if !(ad.Trigger == command.Trigger && ad.HelpText == command.HelpText && ad.RoleID == command.RoleID && ad.Hint == command.Hint) {
|
||||
return false
|
||||
}
|
||||
if len(ad.Arguments) != len(command.Arguments) || len(ad.SubCommands) != len(command.SubCommands) {
|
||||
return false
|
||||
}
|
||||
for i := range ad.Arguments {
|
||||
if !ad.Arguments[i].Equals(command.Arguments[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := range ad.SubCommands {
|
||||
if !ad.SubCommands[i].Equals(command.SubCommands[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// UpdateRelativeURLsForPluginCommands method updates relative urls for plugin commands
|
||||
func (ad *AutocompleteData) UpdateRelativeURLsForPluginCommands(baseURL *url.URL) error {
|
||||
for _, arg := range ad.Arguments {
|
||||
if arg.Type != AutocompleteArgTypeDynamicList {
|
||||
continue
|
||||
}
|
||||
dynamicList, ok := arg.Data.(*AutocompleteDynamicListArg)
|
||||
if !ok {
|
||||
return errors.New("Not a proper DynamicList type argument")
|
||||
}
|
||||
dynamicListURL, err := url.Parse(dynamicList.FetchURL)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "FetchURL is not a proper url")
|
||||
}
|
||||
if !dynamicListURL.IsAbs() {
|
||||
absURL := &url.URL{}
|
||||
*absURL = *baseURL
|
||||
absURL.Path = path.Join(absURL.Path, dynamicList.FetchURL)
|
||||
dynamicList.FetchURL = absURL.String()
|
||||
}
|
||||
}
|
||||
for _, command := range ad.SubCommands {
|
||||
err := command.UpdateRelativeURLsForPluginCommands(baseURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid method checks if autocomplete data is valid.
|
||||
func (ad *AutocompleteData) IsValid() error {
|
||||
if ad == nil {
|
||||
return errors.New("No nil commands are allowed in AutocompleteData")
|
||||
}
|
||||
if ad.Trigger == "" {
|
||||
return errors.New("An empty command name in the autocomplete data")
|
||||
}
|
||||
if strings.ToLower(ad.Trigger) != ad.Trigger {
|
||||
return errors.New("Command should be lowercase")
|
||||
}
|
||||
roles := []string{SystemAdminRoleId, SystemUserRoleId, ""}
|
||||
if !slices.Contains(roles, ad.RoleID) {
|
||||
return errors.New("Wrong role in the autocomplete data")
|
||||
}
|
||||
if len(ad.Arguments) > 0 && len(ad.SubCommands) > 0 {
|
||||
return errors.New("Command can't have arguments and subcommands")
|
||||
}
|
||||
if len(ad.Arguments) > 0 {
|
||||
namedArgumentIndex := -1
|
||||
for i, arg := range ad.Arguments {
|
||||
if arg.Name != "" { // it's a named argument
|
||||
if namedArgumentIndex == -1 { // first named argument
|
||||
namedArgumentIndex = i
|
||||
}
|
||||
} else { // it's a positional argument
|
||||
if namedArgumentIndex != -1 {
|
||||
return errors.New("Named argument should not be before positional argument")
|
||||
}
|
||||
}
|
||||
if arg.Type == AutocompleteArgTypeDynamicList {
|
||||
dynamicList, ok := arg.Data.(*AutocompleteDynamicListArg)
|
||||
if !ok {
|
||||
return errors.New("Not a proper DynamicList type argument")
|
||||
}
|
||||
_, err := url.Parse(dynamicList.FetchURL)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "FetchURL is not a proper url")
|
||||
}
|
||||
} else if arg.Type == AutocompleteArgTypeStaticList {
|
||||
staticList, ok := arg.Data.(*AutocompleteStaticListArg)
|
||||
if !ok {
|
||||
return errors.New("Not a proper StaticList type argument")
|
||||
}
|
||||
for _, arg := range staticList.PossibleArguments {
|
||||
if arg.Item == "" {
|
||||
return errors.New("Possible argument name not set in StaticList argument")
|
||||
}
|
||||
}
|
||||
} else if arg.Type == AutocompleteArgTypeText {
|
||||
if _, ok := arg.Data.(*AutocompleteTextArg); !ok {
|
||||
return errors.New("Not a proper TextInput type argument")
|
||||
}
|
||||
if arg.Name == "" && !arg.Required {
|
||||
return errors.New("Positional argument can not be optional")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, command := range ad.SubCommands {
|
||||
err := command.IsValid()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Equals method checks if argument is the same.
|
||||
func (a *AutocompleteArg) Equals(arg *AutocompleteArg) bool {
|
||||
if a.Name != arg.Name ||
|
||||
a.HelpText != arg.HelpText ||
|
||||
a.Type != arg.Type ||
|
||||
a.Required != arg.Required ||
|
||||
!reflect.DeepEqual(a.Data, arg.Data) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// UnmarshalJSON will unmarshal argument
|
||||
func (a *AutocompleteArg) UnmarshalJSON(b []byte) error {
|
||||
var arg map[string]any
|
||||
if err := json.Unmarshal(b, &arg); err != nil {
|
||||
return errors.Wrapf(err, "Can't unmarshal argument %s", string(b))
|
||||
}
|
||||
var ok bool
|
||||
a.Name, ok = arg["Name"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Name in the argument %s", string(b))
|
||||
}
|
||||
|
||||
a.HelpText, ok = arg["HelpText"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field HelpText in the argument %s", string(b))
|
||||
}
|
||||
|
||||
t, ok := arg["Type"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Type in the argument %s", string(b))
|
||||
}
|
||||
a.Type = AutocompleteArgType(t)
|
||||
|
||||
a.Required, ok = arg["Required"].(bool)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Required in the argument %s", string(b))
|
||||
}
|
||||
|
||||
data, ok := arg["Data"]
|
||||
if !ok {
|
||||
return errors.Errorf("No field Data in the argument %s", string(b))
|
||||
}
|
||||
|
||||
if a.Type == AutocompleteArgTypeText {
|
||||
m, ok := data.(map[string]any)
|
||||
if !ok {
|
||||
return errors.Errorf("Wrong Data type in the TextInput argument %s", string(b))
|
||||
}
|
||||
pattern, ok := m["Pattern"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Pattern in the TextInput argument %s", string(b))
|
||||
}
|
||||
hint, ok := m["Hint"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Hint in the TextInput argument %s", string(b))
|
||||
}
|
||||
a.Data = &AutocompleteTextArg{Hint: hint, Pattern: pattern}
|
||||
} else if a.Type == AutocompleteArgTypeStaticList {
|
||||
m, ok := data.(map[string]any)
|
||||
if !ok {
|
||||
return errors.Errorf("Wrong Data type in the StaticList argument %s", string(b))
|
||||
}
|
||||
list, ok := m["PossibleArguments"].([]any)
|
||||
if !ok {
|
||||
return errors.Errorf("No field PossibleArguments in the StaticList argument %s", string(b))
|
||||
}
|
||||
|
||||
possibleArguments := []AutocompleteListItem{}
|
||||
for i := range list {
|
||||
args, ok := list[i].(map[string]any)
|
||||
if !ok {
|
||||
return errors.Errorf("Wrong AutocompleteStaticListItem type in the StaticList argument %s", string(b))
|
||||
}
|
||||
item, ok := args["Item"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Item in the StaticList's possible arguments %s", string(b))
|
||||
}
|
||||
|
||||
hint, ok := args["Hint"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Hint in the StaticList's possible arguments %s", string(b))
|
||||
}
|
||||
helpText, ok := args["HelpText"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field Hint in the StaticList's possible arguments %s", string(b))
|
||||
}
|
||||
|
||||
possibleArguments = append(possibleArguments, AutocompleteListItem{
|
||||
Item: item,
|
||||
Hint: hint,
|
||||
HelpText: helpText,
|
||||
})
|
||||
}
|
||||
a.Data = &AutocompleteStaticListArg{PossibleArguments: possibleArguments}
|
||||
} else if a.Type == AutocompleteArgTypeDynamicList {
|
||||
m, ok := data.(map[string]any)
|
||||
if !ok {
|
||||
return errors.Errorf("Wrong type in the DynamicList argument %s", string(b))
|
||||
}
|
||||
url, ok := m["FetchURL"].(string)
|
||||
if !ok {
|
||||
return errors.Errorf("No field FetchURL in the DynamicList's argument %s", string(b))
|
||||
}
|
||||
a.Data = &AutocompleteDynamicListArg{FetchURL: url}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
8
vendor/github.com/mattermost/mattermost/server/public/model/command_request.go
generated
vendored
Normal file
8
vendor/github.com/mattermost/mattermost/server/public/model/command_request.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type CommandMoveRequest struct {
|
||||
TeamId string `json:"team_id"`
|
||||
}
|
||||
71
vendor/github.com/mattermost/mattermost/server/public/model/command_response.go
generated
vendored
Normal file
71
vendor/github.com/mattermost/mattermost/server/public/model/command_response.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
CommandResponseTypeInChannel = "in_channel"
|
||||
CommandResponseTypeEphemeral = "ephemeral"
|
||||
)
|
||||
|
||||
type CommandResponse struct {
|
||||
ResponseType string `json:"response_type"`
|
||||
Text string `json:"text"`
|
||||
Username string `json:"username"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
IconURL string `json:"icon_url"`
|
||||
Type string `json:"type"`
|
||||
Props StringInterface `json:"props"`
|
||||
GotoLocation string `json:"goto_location"`
|
||||
TriggerId string `json:"trigger_id"`
|
||||
SkipSlackParsing bool `json:"skip_slack_parsing"` // Set to `true` to skip the Slack-compatibility handling of Text.
|
||||
Attachments []*SlackAttachment `json:"attachments"`
|
||||
ExtraResponses []*CommandResponse `json:"extra_responses"`
|
||||
}
|
||||
|
||||
func CommandResponseFromHTTPBody(contentType string, body io.Reader) (*CommandResponse, error) {
|
||||
if strings.TrimSpace(strings.Split(contentType, ";")[0]) == "application/json" {
|
||||
return CommandResponseFromJSON(body)
|
||||
}
|
||||
if b, err := io.ReadAll(body); err == nil {
|
||||
return CommandResponseFromPlainText(string(b)), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func CommandResponseFromPlainText(text string) *CommandResponse {
|
||||
return &CommandResponse{
|
||||
Text: text,
|
||||
}
|
||||
}
|
||||
|
||||
func CommandResponseFromJSON(data io.Reader) (*CommandResponse, error) {
|
||||
b, err := io.ReadAll(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var o CommandResponse
|
||||
err = json.Unmarshal(b, &o)
|
||||
if err != nil {
|
||||
return nil, utils.HumanizeJSONError(err, b)
|
||||
}
|
||||
|
||||
o.Attachments = StringifySlackFieldValue(o.Attachments)
|
||||
|
||||
if o.ExtraResponses != nil {
|
||||
for _, resp := range o.ExtraResponses {
|
||||
resp.Attachments = StringifySlackFieldValue(resp.Attachments)
|
||||
}
|
||||
}
|
||||
|
||||
return &o, nil
|
||||
}
|
||||
60
vendor/github.com/mattermost/mattermost/server/public/model/command_webhook.go
generated
vendored
Normal file
60
vendor/github.com/mattermost/mattermost/server/public/model/command_webhook.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type CommandWebhook struct {
|
||||
Id string
|
||||
CreateAt int64
|
||||
CommandId string
|
||||
UserId string
|
||||
ChannelId string
|
||||
RootId string
|
||||
UseCount int
|
||||
}
|
||||
|
||||
const (
|
||||
CommandWebhookLifetime = 1000 * 60 * 30
|
||||
)
|
||||
|
||||
func (o *CommandWebhook) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
o.CreateAt = GetMillis()
|
||||
}
|
||||
}
|
||||
|
||||
func (o *CommandWebhook) IsValid() *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("CommandWebhook.IsValid", "model.command_hook.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("CommandWebhook.IsValid", "model.command_hook.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.CommandId) {
|
||||
return NewAppError("CommandWebhook.IsValid", "model.command_hook.command_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.UserId) {
|
||||
return NewAppError("CommandWebhook.IsValid", "model.command_hook.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.ChannelId) {
|
||||
return NewAppError("CommandWebhook.IsValid", "model.command_hook.channel_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.RootId != "" && !IsValidId(o.RootId) {
|
||||
return NewAppError("CommandWebhook.IsValid", "model.command_hook.root_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
141
vendor/github.com/mattermost/mattermost/server/public/model/compliance.go
generated
vendored
Normal file
141
vendor/github.com/mattermost/mattermost/server/public/model/compliance.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
)
|
||||
|
||||
const (
|
||||
ComplianceStatusCreated = "created"
|
||||
ComplianceStatusRunning = "running"
|
||||
ComplianceStatusFinished = "finished"
|
||||
ComplianceStatusFailed = "failed"
|
||||
ComplianceStatusRemoved = "removed"
|
||||
|
||||
ComplianceTypeDaily = "daily"
|
||||
ComplianceTypeAdhoc = "adhoc"
|
||||
)
|
||||
|
||||
type Compliance struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UserId string `json:"user_id"`
|
||||
Status string `json:"status"`
|
||||
Count int `json:"count"`
|
||||
Desc string `json:"desc"`
|
||||
Type string `json:"type"`
|
||||
StartAt int64 `json:"start_at"`
|
||||
EndAt int64 `json:"end_at"`
|
||||
Keywords string `json:"keywords"`
|
||||
Emails string `json:"emails"`
|
||||
}
|
||||
|
||||
func (c *Compliance) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": c.Id,
|
||||
"create_at": c.CreateAt,
|
||||
"user_id": c.UserId,
|
||||
"status": c.Status,
|
||||
"count": c.Count,
|
||||
"desc": c.Desc,
|
||||
"type": c.Type,
|
||||
"start_at": c.StartAt,
|
||||
"end_at": c.EndAt,
|
||||
"keywords": c.Keywords,
|
||||
"emails": c.Emails,
|
||||
}
|
||||
}
|
||||
|
||||
type Compliances []Compliance
|
||||
|
||||
// ComplianceExportCursor is used for paginated iteration of posts
|
||||
// for compliance export.
|
||||
// We need to keep track of the last post ID in addition to the last post
|
||||
// CreateAt to break ties when two posts have the same CreateAt.
|
||||
type ComplianceExportCursor struct {
|
||||
LastChannelsQueryPostCreateAt int64
|
||||
LastChannelsQueryPostID string
|
||||
ChannelsQueryCompleted bool
|
||||
LastDirectMessagesQueryPostCreateAt int64
|
||||
LastDirectMessagesQueryPostID string
|
||||
DirectMessagesQueryCompleted bool
|
||||
}
|
||||
|
||||
func (c *Compliance) PreSave() {
|
||||
if c.Id == "" {
|
||||
c.Id = NewId()
|
||||
}
|
||||
|
||||
if c.Status == "" {
|
||||
c.Status = ComplianceStatusCreated
|
||||
}
|
||||
|
||||
c.Count = 0
|
||||
c.Emails = NormalizeEmail(c.Emails)
|
||||
c.Keywords = strings.ToLower(c.Keywords)
|
||||
|
||||
c.CreateAt = GetMillis()
|
||||
}
|
||||
|
||||
func (c *Compliance) DeepCopy() *Compliance {
|
||||
cCopy := *c
|
||||
return &cCopy
|
||||
}
|
||||
|
||||
func (c *Compliance) JobName() string {
|
||||
jobName := c.Type
|
||||
if c.Type == ComplianceTypeDaily {
|
||||
jobName += "-" + c.Desc
|
||||
}
|
||||
|
||||
jobName += "-" + c.Id
|
||||
|
||||
return jobName
|
||||
}
|
||||
|
||||
func (c *Compliance) IsValid() *AppError {
|
||||
if !IsValidId(c.Id) {
|
||||
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if c.CreateAt == 0 {
|
||||
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(c.Desc) > 512 || c.Desc == "" {
|
||||
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.desc.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if c.StartAt == 0 {
|
||||
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if c.EndAt == 0 {
|
||||
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.end_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if c.EndAt <= c.StartAt {
|
||||
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_end_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoggerFields returns the logger annotations reflecting the given compliance job metadata.
|
||||
func (c *Compliance) LoggerFields() []mlog.Field {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return []mlog.Field{
|
||||
mlog.String("job_id", c.Id),
|
||||
mlog.String("job_type", c.Type),
|
||||
mlog.String("job_name", c.JobName()),
|
||||
mlog.Millis("job_create_at", c.CreateAt),
|
||||
}
|
||||
}
|
||||
120
vendor/github.com/mattermost/mattermost/server/public/model/compliance_post.go
generated
vendored
Normal file
120
vendor/github.com/mattermost/mattermost/server/public/model/compliance_post.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CompliancePost struct {
|
||||
|
||||
// From Team
|
||||
TeamName string
|
||||
TeamDisplayName string
|
||||
|
||||
// From Channel
|
||||
ChannelName string
|
||||
ChannelDisplayName string
|
||||
ChannelType string
|
||||
|
||||
// From User
|
||||
UserUsername string
|
||||
UserEmail string
|
||||
UserNickname string
|
||||
|
||||
// From Post
|
||||
PostId string
|
||||
PostCreateAt int64
|
||||
PostUpdateAt int64
|
||||
PostDeleteAt int64
|
||||
PostRootId string
|
||||
PostOriginalId string
|
||||
PostMessage string
|
||||
PostType string
|
||||
PostProps string
|
||||
PostHashtags string
|
||||
PostFileIds string
|
||||
|
||||
IsBot bool
|
||||
}
|
||||
|
||||
func CompliancePostHeader() []string {
|
||||
return []string{
|
||||
"TeamName",
|
||||
"TeamDisplayName",
|
||||
|
||||
"ChannelName",
|
||||
"ChannelDisplayName",
|
||||
"ChannelType",
|
||||
|
||||
"UserUsername",
|
||||
"UserEmail",
|
||||
"UserNickname",
|
||||
"UserType",
|
||||
|
||||
"PostId",
|
||||
"PostCreateAt",
|
||||
"PostUpdateAt",
|
||||
"PostDeleteAt",
|
||||
"PostRootId",
|
||||
"PostOriginalId",
|
||||
"PostMessage",
|
||||
"PostType",
|
||||
"PostProps",
|
||||
"PostHashtags",
|
||||
"PostFileIds",
|
||||
}
|
||||
}
|
||||
|
||||
func cleanComplianceStrings(in string) string {
|
||||
if matched, _ := regexp.MatchString("^\\s*(=|\\+|\\-)", in); matched {
|
||||
return "'" + in
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
func (cp *CompliancePost) Row() []string {
|
||||
postDeleteAt := ""
|
||||
if cp.PostDeleteAt > 0 {
|
||||
postDeleteAt = time.Unix(0, cp.PostDeleteAt*int64(1000*1000)).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
postUpdateAt := ""
|
||||
if cp.PostUpdateAt != cp.PostCreateAt {
|
||||
postUpdateAt = time.Unix(0, cp.PostUpdateAt*int64(1000*1000)).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
userType := "user"
|
||||
if cp.IsBot {
|
||||
userType = "bot"
|
||||
}
|
||||
|
||||
return []string{
|
||||
cleanComplianceStrings(cp.TeamName),
|
||||
cleanComplianceStrings(cp.TeamDisplayName),
|
||||
|
||||
cleanComplianceStrings(cp.ChannelName),
|
||||
cleanComplianceStrings(cp.ChannelDisplayName),
|
||||
cleanComplianceStrings(cp.ChannelType),
|
||||
|
||||
cleanComplianceStrings(cp.UserUsername),
|
||||
cleanComplianceStrings(cp.UserEmail),
|
||||
cleanComplianceStrings(cp.UserNickname),
|
||||
userType,
|
||||
|
||||
cp.PostId,
|
||||
time.Unix(0, cp.PostCreateAt*int64(1000*1000)).Format(time.RFC3339),
|
||||
postUpdateAt,
|
||||
postDeleteAt,
|
||||
|
||||
cp.PostRootId,
|
||||
cp.PostOriginalId,
|
||||
cleanComplianceStrings(cp.PostMessage),
|
||||
cp.PostType,
|
||||
cp.PostProps,
|
||||
cp.PostHashtags,
|
||||
cp.PostFileIds,
|
||||
}
|
||||
}
|
||||
4518
vendor/github.com/mattermost/mattermost/server/public/model/config.go
generated
vendored
Normal file
4518
vendor/github.com/mattermost/mattermost/server/public/model/config.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
136
vendor/github.com/mattermost/mattermost/server/public/model/custom_status.go
generated
vendored
Normal file
136
vendor/github.com/mattermost/mattermost/server/public/model/custom_status.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
UserPropsKeyCustomStatus = "customStatus"
|
||||
|
||||
CustomStatusTextMaxRunes = 100
|
||||
MaxRecentCustomStatuses = 5
|
||||
DefaultCustomStatusEmoji = "speech_balloon"
|
||||
)
|
||||
|
||||
var validCustomStatusDuration = map[string]bool{
|
||||
"thirty_minutes": true,
|
||||
"one_hour": true,
|
||||
"four_hours": true,
|
||||
"today": true,
|
||||
"this_week": true,
|
||||
"date_and_time": true,
|
||||
}
|
||||
|
||||
type CustomStatus struct {
|
||||
Emoji string `json:"emoji"`
|
||||
Text string `json:"text"`
|
||||
Duration string `json:"duration"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
func (cs *CustomStatus) PreSave() {
|
||||
if cs.Duration == "" && !cs.ExpiresAt.Before(time.Now()) {
|
||||
cs.Duration = "date_and_time"
|
||||
}
|
||||
|
||||
runes := []rune(cs.Text)
|
||||
if len(runes) > CustomStatusTextMaxRunes {
|
||||
cs.Text = string(runes[:CustomStatusTextMaxRunes])
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *CustomStatus) AreDurationAndExpirationTimeValid() bool {
|
||||
if cs.Duration == "" && (cs.ExpiresAt.IsZero() || !cs.ExpiresAt.Before(time.Now())) {
|
||||
return true
|
||||
}
|
||||
|
||||
if validCustomStatusDuration[cs.Duration] && !cs.ExpiresAt.Before(time.Now()) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func RuneToHexadecimalString(r rune) string {
|
||||
return fmt.Sprintf("%04x", r)
|
||||
}
|
||||
|
||||
type RecentCustomStatuses []CustomStatus
|
||||
|
||||
func (rcs RecentCustomStatuses) Contains(cs *CustomStatus) (bool, error) {
|
||||
if cs == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
csJSON, jsonErr := json.Marshal(cs)
|
||||
if jsonErr != nil {
|
||||
return false, jsonErr
|
||||
}
|
||||
|
||||
// status is empty
|
||||
if len(csJSON) == 0 || (cs.Emoji == "" && cs.Text == "") {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, status := range rcs {
|
||||
js, jsonErr := json.Marshal(status)
|
||||
if jsonErr != nil {
|
||||
return false, jsonErr
|
||||
}
|
||||
if bytes.Equal(js, csJSON) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (rcs RecentCustomStatuses) Add(cs *CustomStatus) RecentCustomStatuses {
|
||||
newRCS := rcs[:0]
|
||||
|
||||
// if same `text` exists in existing recent custom statuses, modify existing status
|
||||
for _, status := range rcs {
|
||||
if status.Text != cs.Text {
|
||||
newRCS = append(newRCS, status)
|
||||
}
|
||||
}
|
||||
newRCS = append(RecentCustomStatuses{*cs}, newRCS...)
|
||||
if len(newRCS) > MaxRecentCustomStatuses {
|
||||
newRCS = newRCS[:MaxRecentCustomStatuses]
|
||||
}
|
||||
return newRCS
|
||||
}
|
||||
|
||||
func (rcs RecentCustomStatuses) Remove(cs *CustomStatus) (RecentCustomStatuses, error) {
|
||||
if cs == nil {
|
||||
return rcs, nil
|
||||
}
|
||||
|
||||
csJSON, jsonErr := json.Marshal(cs)
|
||||
if jsonErr != nil {
|
||||
return rcs, jsonErr
|
||||
}
|
||||
|
||||
if len(csJSON) == 0 || (cs.Emoji == "" && cs.Text == "") {
|
||||
return rcs, nil
|
||||
}
|
||||
|
||||
newRCS := rcs[:0]
|
||||
for _, status := range rcs {
|
||||
js, jsonErr := json.Marshal(status)
|
||||
if jsonErr != nil {
|
||||
return rcs, jsonErr
|
||||
}
|
||||
if !bytes.Equal(js, csJSON) {
|
||||
newRCS = append(newRCS, status)
|
||||
}
|
||||
}
|
||||
|
||||
return newRCS, nil
|
||||
}
|
||||
98
vendor/github.com/mattermost/mattermost/server/public/model/data_retention_policy.go
generated
vendored
Normal file
98
vendor/github.com/mattermost/mattermost/server/public/model/data_retention_policy.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type GlobalRetentionPolicy struct {
|
||||
MessageDeletionEnabled bool `json:"message_deletion_enabled"`
|
||||
FileDeletionEnabled bool `json:"file_deletion_enabled"`
|
||||
MessageRetentionCutoff int64 `json:"message_retention_cutoff"`
|
||||
FileRetentionCutoff int64 `json:"file_retention_cutoff"`
|
||||
}
|
||||
|
||||
type RetentionPolicy struct {
|
||||
ID string `db:"Id" json:"id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
PostDurationDays *int64 `db:"PostDuration" json:"post_duration"`
|
||||
}
|
||||
|
||||
type RetentionPolicyWithTeamAndChannelIDs struct {
|
||||
RetentionPolicy
|
||||
TeamIDs []string `json:"team_ids"`
|
||||
ChannelIDs []string `json:"channel_ids"`
|
||||
}
|
||||
|
||||
func (o *RetentionPolicyWithTeamAndChannelIDs) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"retention_policy": o.RetentionPolicy,
|
||||
"team_ids": o.TeamIDs,
|
||||
"channel_ids": o.ChannelIDs,
|
||||
}
|
||||
}
|
||||
|
||||
type RetentionPolicyWithTeamAndChannelCounts struct {
|
||||
RetentionPolicy
|
||||
ChannelCount int64 `json:"channel_count"`
|
||||
TeamCount int64 `json:"team_count"`
|
||||
}
|
||||
|
||||
func (o *RetentionPolicyWithTeamAndChannelCounts) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"retention_policy": o.RetentionPolicy,
|
||||
"channel_count": o.ChannelCount,
|
||||
"team_count": o.TeamCount,
|
||||
}
|
||||
}
|
||||
|
||||
type RetentionPolicyChannel struct {
|
||||
PolicyID string `db:"PolicyId"`
|
||||
ChannelID string `db:"ChannelId"`
|
||||
}
|
||||
|
||||
type RetentionPolicyTeam struct {
|
||||
PolicyID string `db:"PolicyId"`
|
||||
TeamID string `db:"TeamId"`
|
||||
}
|
||||
|
||||
type RetentionPolicyWithTeamAndChannelCountsList struct {
|
||||
Policies []*RetentionPolicyWithTeamAndChannelCounts `json:"policies"`
|
||||
TotalCount int64 `json:"total_count"`
|
||||
}
|
||||
|
||||
type RetentionPolicyForTeam struct {
|
||||
TeamID string `db:"Id" json:"team_id"`
|
||||
PostDurationDays int64 `db:"PostDuration" json:"post_duration"`
|
||||
}
|
||||
|
||||
type RetentionPolicyForTeamList struct {
|
||||
Policies []*RetentionPolicyForTeam `json:"policies"`
|
||||
TotalCount int64 `json:"total_count"`
|
||||
}
|
||||
|
||||
type RetentionPolicyForChannel struct {
|
||||
ChannelID string `db:"Id" json:"channel_id"`
|
||||
PostDurationDays int64 `db:"PostDuration" json:"post_duration"`
|
||||
}
|
||||
|
||||
type RetentionPolicyForChannelList struct {
|
||||
Policies []*RetentionPolicyForChannel `json:"policies"`
|
||||
TotalCount int64 `json:"total_count"`
|
||||
}
|
||||
|
||||
type RetentionPolicyCursor struct {
|
||||
ChannelPoliciesDone bool
|
||||
TeamPoliciesDone bool
|
||||
GlobalPoliciesDone bool
|
||||
}
|
||||
|
||||
type RetentionIdsForDeletion struct {
|
||||
Id string
|
||||
TableName string
|
||||
Ids []string
|
||||
}
|
||||
|
||||
func (r *RetentionIdsForDeletion) PreSave() {
|
||||
if r.Id == "" {
|
||||
r.Id = NewId()
|
||||
}
|
||||
}
|
||||
104
vendor/github.com/mattermost/mattermost/server/public/model/draft.go
generated
vendored
Normal file
104
vendor/github.com/mattermost/mattermost/server/public/model/draft.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type Draft struct {
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"` // Deprecated, we now just hard delete the rows
|
||||
UserId string `json:"user_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
RootId string `json:"root_id"`
|
||||
|
||||
Message string `json:"message"`
|
||||
|
||||
propsMu sync.RWMutex `db:"-"` // Unexported mutex used to guard Draft.Props.
|
||||
Props StringInterface `json:"props"` // Deprecated: use GetProps()
|
||||
FileIds StringArray `json:"file_ids,omitempty"`
|
||||
Metadata *PostMetadata `json:"metadata,omitempty"`
|
||||
Priority StringInterface `json:"priority,omitempty"`
|
||||
}
|
||||
|
||||
func (o *Draft) IsValid(maxDraftSize int) *AppError {
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.create_at.app_error", nil, "channelid="+o.ChannelId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.UpdateAt == 0 {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.update_at.app_error", nil, "channelid="+o.ChannelId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.UserId) {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.ChannelId) {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !(IsValidId(o.RootId) || o.RootId == "") {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.root_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(o.Message) > maxDraftSize {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.msg.app_error", nil, "channelid="+o.ChannelId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(ArrayToJSON(o.FileIds)) > PostFileidsMaxRunes {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.file_ids.app_error", nil, "channelid="+o.ChannelId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(StringInterfaceToJSON(o.GetProps())) > PostPropsMaxRunes {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.props.app_error", nil, "channelid="+o.ChannelId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(StringInterfaceToJSON(o.Priority)) > PostPropsMaxRunes {
|
||||
return NewAppError("Drafts.IsValid", "model.draft.is_valid.priority.app_error", nil, "channelid="+o.ChannelId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Draft) SetProps(props StringInterface) {
|
||||
o.propsMu.Lock()
|
||||
defer o.propsMu.Unlock()
|
||||
o.Props = props
|
||||
}
|
||||
|
||||
func (o *Draft) GetProps() StringInterface {
|
||||
o.propsMu.RLock()
|
||||
defer o.propsMu.RUnlock()
|
||||
return o.Props
|
||||
}
|
||||
|
||||
func (o *Draft) PreSave() {
|
||||
if o.CreateAt == 0 {
|
||||
o.CreateAt = GetMillis()
|
||||
o.UpdateAt = o.CreateAt
|
||||
} else {
|
||||
o.UpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
o.DeleteAt = 0
|
||||
o.PreCommit()
|
||||
}
|
||||
|
||||
func (o *Draft) PreCommit() {
|
||||
if o.GetProps() == nil {
|
||||
o.SetProps(make(map[string]interface{}))
|
||||
}
|
||||
|
||||
if o.FileIds == nil {
|
||||
o.FileIds = []string{}
|
||||
}
|
||||
|
||||
// There's a rare bug where the client sends up duplicate FileIds so protect against that
|
||||
o.FileIds = RemoveDuplicateStrings(o.FileIds)
|
||||
}
|
||||
109
vendor/github.com/mattermost/mattermost/server/public/model/emoji.go
generated
vendored
Normal file
109
vendor/github.com/mattermost/mattermost/server/public/model/emoji.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
EmojiNameMaxLength = 64
|
||||
EmojiSortByName = "name"
|
||||
)
|
||||
|
||||
var EmojiPattern = regexp.MustCompile(`:[a-zA-Z0-9_+-]+:`)
|
||||
|
||||
type Emoji struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
CreatorId string `json:"creator_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (emoji *Emoji) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": emoji.Id,
|
||||
"create_at": emoji.CreateAt,
|
||||
"update_at": emoji.UpdateAt,
|
||||
"delete_at": emoji.CreateAt,
|
||||
"creator_id": emoji.CreatorId,
|
||||
"name": emoji.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func IsSystemEmojiName(emojiName string) bool {
|
||||
_, ok := SystemEmojis[emojiName]
|
||||
return ok
|
||||
}
|
||||
|
||||
func GetSystemEmojiId(emojiName string) (string, bool) {
|
||||
id, found := SystemEmojis[emojiName]
|
||||
return id, found
|
||||
}
|
||||
|
||||
func makeReverseEmojiMap() map[string][]string {
|
||||
reverseEmojiMap := make(map[string][]string)
|
||||
for key, value := range SystemEmojis {
|
||||
emojiNames := reverseEmojiMap[value]
|
||||
emojiNames = append(emojiNames, key)
|
||||
sort.Strings(emojiNames)
|
||||
reverseEmojiMap[value] = emojiNames
|
||||
}
|
||||
|
||||
return reverseEmojiMap
|
||||
}
|
||||
|
||||
var reverseSystemEmojisMap = makeReverseEmojiMap()
|
||||
|
||||
func GetEmojiNameFromUnicode(unicode string) (emojiName string, count int) {
|
||||
if emojiNames, found := reverseSystemEmojisMap[unicode]; found {
|
||||
return emojiNames[0], len(emojiNames)
|
||||
}
|
||||
|
||||
return "", 0
|
||||
}
|
||||
|
||||
func (emoji *Emoji) IsValid() *AppError {
|
||||
if !IsValidId(emoji.Id) {
|
||||
return NewAppError("Emoji.IsValid", "model.emoji.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if emoji.CreateAt == 0 {
|
||||
return NewAppError("Emoji.IsValid", "model.emoji.create_at.app_error", nil, "id="+emoji.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if emoji.UpdateAt == 0 {
|
||||
return NewAppError("Emoji.IsValid", "model.emoji.update_at.app_error", nil, "id="+emoji.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(emoji.CreatorId) > 26 {
|
||||
return NewAppError("Emoji.IsValid", "model.emoji.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return IsValidEmojiName(emoji.Name)
|
||||
}
|
||||
|
||||
func IsValidEmojiName(name string) *AppError {
|
||||
if name == "" || len(name) > EmojiNameMaxLength || !IsValidAlphaNumHyphenUnderscorePlus(name) {
|
||||
return NewAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
if IsSystemEmojiName(name) {
|
||||
return NewAppError("Emoji.IsValid", "model.emoji.system_emoji_name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (emoji *Emoji) PreSave() {
|
||||
if emoji.Id == "" {
|
||||
emoji.Id = NewId()
|
||||
}
|
||||
|
||||
emoji.CreateAt = GetMillis()
|
||||
emoji.UpdateAt = emoji.CreateAt
|
||||
}
|
||||
4473
vendor/github.com/mattermost/mattermost/server/public/model/emoji_data.go
generated
vendored
Normal file
4473
vendor/github.com/mattermost/mattermost/server/public/model/emoji_data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
vendor/github.com/mattermost/mattermost/server/public/model/emoji_search.go
generated
vendored
Normal file
9
vendor/github.com/mattermost/mattermost/server/public/model/emoji_search.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type EmojiSearch struct {
|
||||
Term string `json:"term"`
|
||||
PrefixOnly bool `json:"prefix_only"`
|
||||
}
|
||||
110
vendor/github.com/mattermost/mattermost/server/public/model/feature_flags.go
generated
vendored
Normal file
110
vendor/github.com/mattermost/mattermost/server/public/model/feature_flags.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type FeatureFlags struct {
|
||||
// Exists only for unit and manual testing.
|
||||
// When set to a value, will be returned by the ping endpoint.
|
||||
TestFeature string
|
||||
// Exists only for testing bool functionality. Boolean feature flags interpret "on" or "true" as true and
|
||||
// all other values as false.
|
||||
TestBoolFeature bool
|
||||
|
||||
// Enable the remote cluster service for shared channels.
|
||||
EnableRemoteClusterService bool
|
||||
|
||||
// AppsEnabled toggles the Apps framework functionalities both in server and client side
|
||||
AppsEnabled bool
|
||||
|
||||
PermalinkPreviews bool
|
||||
|
||||
// CallsEnabled controls whether or not the Calls plugin should be enabled
|
||||
CallsEnabled bool
|
||||
|
||||
NormalizeLdapDNs bool
|
||||
|
||||
// Enable WYSIWYG text editor
|
||||
WysiwygEditor bool
|
||||
|
||||
OnboardingTourTips bool
|
||||
|
||||
DeprecateCloudFree bool
|
||||
|
||||
CloudReverseTrial bool
|
||||
|
||||
EnableExportDirectDownload bool
|
||||
|
||||
MoveThreadsEnabled bool
|
||||
|
||||
StreamlinedMarketplace bool
|
||||
|
||||
CloudIPFiltering bool
|
||||
ConsumePostHook bool
|
||||
|
||||
CloudAnnualRenewals bool
|
||||
CloudDedicatedExportUI bool
|
||||
|
||||
ChannelBookmarks bool
|
||||
|
||||
WebSocketEventScope bool
|
||||
|
||||
NotificationMonitoring bool
|
||||
|
||||
ExperimentalAuditSettingsSystemConsoleUI bool
|
||||
|
||||
ClientMetrics bool
|
||||
}
|
||||
|
||||
func (f *FeatureFlags) SetDefaults() {
|
||||
f.TestFeature = "off"
|
||||
f.TestBoolFeature = false
|
||||
f.EnableRemoteClusterService = false
|
||||
f.AppsEnabled = true
|
||||
f.NormalizeLdapDNs = false
|
||||
f.CallsEnabled = true
|
||||
f.DeprecateCloudFree = false
|
||||
f.WysiwygEditor = false
|
||||
f.OnboardingTourTips = true
|
||||
f.CloudReverseTrial = false
|
||||
f.EnableExportDirectDownload = false
|
||||
f.MoveThreadsEnabled = false
|
||||
f.StreamlinedMarketplace = true
|
||||
f.CloudIPFiltering = false
|
||||
f.ConsumePostHook = false
|
||||
f.CloudAnnualRenewals = false
|
||||
f.CloudDedicatedExportUI = false
|
||||
f.ChannelBookmarks = false
|
||||
f.WebSocketEventScope = false
|
||||
f.NotificationMonitoring = true
|
||||
f.ExperimentalAuditSettingsSystemConsoleUI = false
|
||||
f.ClientMetrics = false
|
||||
}
|
||||
|
||||
// ToMap returns the feature flags as a map[string]string
|
||||
// Supports boolean and string feature flags.
|
||||
func (f *FeatureFlags) ToMap() map[string]string {
|
||||
refStructVal := reflect.ValueOf(*f)
|
||||
refStructType := reflect.TypeOf(*f)
|
||||
ret := make(map[string]string)
|
||||
for i := 0; i < refStructVal.NumField(); i++ {
|
||||
refFieldVal := refStructVal.Field(i)
|
||||
if !refFieldVal.IsValid() {
|
||||
continue
|
||||
}
|
||||
refFieldType := refStructType.Field(i)
|
||||
switch refFieldType.Type.Kind() {
|
||||
case reflect.Bool:
|
||||
ret[refFieldType.Name] = strconv.FormatBool(refFieldVal.Bool())
|
||||
default:
|
||||
ret[refFieldType.Name] = refFieldVal.String()
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
20
vendor/github.com/mattermost/mattermost/server/public/model/file.go
generated
vendored
Normal file
20
vendor/github.com/mattermost/mattermost/server/public/model/file.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
MaxImageSize = int64(6048 * 4032) // 24 megapixels, roughly 36MB as a raw image
|
||||
)
|
||||
|
||||
type FileUploadResponse struct {
|
||||
FileInfos []*FileInfo `json:"file_infos"`
|
||||
ClientIds []string `json:"client_ids"`
|
||||
}
|
||||
|
||||
type PresignURLResponse struct {
|
||||
URL string `json:"url"`
|
||||
Expiration time.Duration `json:"expiration"`
|
||||
}
|
||||
177
vendor/github.com/mattermost/mattermost/server/public/model/file_info.go
generated
vendored
Normal file
177
vendor/github.com/mattermost/mattermost/server/public/model/file_info.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
FileinfoSortByCreated = "CreateAt"
|
||||
FileinfoSortBySize = "Size"
|
||||
)
|
||||
|
||||
// GetFileInfosOptions contains options for getting FileInfos
|
||||
type GetFileInfosOptions struct {
|
||||
// UserIds optionally limits the FileInfos to those created by the given users.
|
||||
UserIds []string `json:"user_ids"`
|
||||
// ChannelIds optionally limits the FileInfos to those created in the given channels.
|
||||
ChannelIds []string `json:"channel_ids"`
|
||||
// Since optionally limits FileInfos to those created at or after the given time, specified as Unix time in milliseconds.
|
||||
Since int64 `json:"since"`
|
||||
// IncludeDeleted if set includes deleted FileInfos.
|
||||
IncludeDeleted bool `json:"include_deleted"`
|
||||
// SortBy sorts the FileInfos by this field. The default is to sort by date created.
|
||||
SortBy string `json:"sort_by"`
|
||||
// SortDescending changes the sort direction to descending order when true.
|
||||
SortDescending bool `json:"sort_descending"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Id string `json:"id"`
|
||||
CreatorId string `json:"user_id"`
|
||||
PostId string `json:"post_id,omitempty"`
|
||||
// ChannelId is the denormalized value from the corresponding post. Note that this value is
|
||||
// potentially distinct from the ChannelId provided when the file is first uploaded and
|
||||
// used to organize the directories in the file store, since in theory that same file
|
||||
// could be attached to a post from a different channel (or not attached to a post at all).
|
||||
ChannelId string `json:"channel_id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
Path string `json:"-"` // not sent back to the client
|
||||
ThumbnailPath string `json:"-"` // not sent back to the client
|
||||
PreviewPath string `json:"-"` // not sent back to the client
|
||||
Name string `json:"name"`
|
||||
Extension string `json:"extension"`
|
||||
Size int64 `json:"size"`
|
||||
MimeType string `json:"mime_type"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
HasPreviewImage bool `json:"has_preview_image,omitempty"`
|
||||
MiniPreview *[]byte `json:"mini_preview"` // declared as *[]byte to avoid postgres/mysql differences in deserialization
|
||||
Content string `json:"-"`
|
||||
RemoteId *string `json:"remote_id"`
|
||||
Archived bool `json:"archived"`
|
||||
}
|
||||
|
||||
func (fi *FileInfo) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": fi.Id,
|
||||
"creator_id": fi.CreatorId,
|
||||
"post_id": fi.PostId,
|
||||
"channel_id": fi.ChannelId,
|
||||
"create_at": fi.CreateAt,
|
||||
"update_at": fi.UpdateAt,
|
||||
"delete_at": fi.DeleteAt,
|
||||
"name": fi.Name,
|
||||
"extension": fi.Extension,
|
||||
"size": fi.Size,
|
||||
}
|
||||
}
|
||||
|
||||
func (fi *FileInfo) PreSave() {
|
||||
if fi.Id == "" {
|
||||
fi.Id = NewId()
|
||||
}
|
||||
|
||||
if fi.CreateAt == 0 {
|
||||
fi.CreateAt = GetMillis()
|
||||
}
|
||||
|
||||
if fi.UpdateAt < fi.CreateAt {
|
||||
fi.UpdateAt = fi.CreateAt
|
||||
}
|
||||
|
||||
if fi.RemoteId == nil {
|
||||
fi.RemoteId = NewString("")
|
||||
}
|
||||
}
|
||||
|
||||
func (fi *FileInfo) IsValid() *AppError {
|
||||
if !IsValidId(fi.Id) {
|
||||
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(fi.CreatorId) && (fi.CreatorId != "nouser" && fi.CreatorId != BookmarkFileOwner) {
|
||||
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if fi.PostId != "" && !IsValidId(fi.PostId) {
|
||||
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if fi.CreateAt == 0 {
|
||||
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.create_at.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if fi.UpdateAt == 0 {
|
||||
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.update_at.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if fi.Path == "" {
|
||||
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.path.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fi *FileInfo) IsImage() bool {
|
||||
return strings.HasPrefix(fi.MimeType, "image")
|
||||
}
|
||||
|
||||
func (fi *FileInfo) IsSvg() bool {
|
||||
return fi.MimeType == "image/svg+xml"
|
||||
}
|
||||
|
||||
func NewInfo(name string) *FileInfo {
|
||||
info := &FileInfo{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
extension := strings.ToLower(filepath.Ext(name))
|
||||
info.MimeType = mime.TypeByExtension(extension)
|
||||
|
||||
if extension != "" && extension[0] == '.' {
|
||||
// The client expects a file extension without the leading period
|
||||
info.Extension = extension[1:]
|
||||
} else {
|
||||
info.Extension = extension
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func GetEtagForFileInfos(infos []*FileInfo) string {
|
||||
if len(infos) == 0 {
|
||||
return Etag()
|
||||
}
|
||||
|
||||
var maxUpdateAt int64
|
||||
|
||||
for _, info := range infos {
|
||||
if info.UpdateAt > maxUpdateAt {
|
||||
maxUpdateAt = info.UpdateAt
|
||||
}
|
||||
}
|
||||
|
||||
return Etag(infos[0].PostId, maxUpdateAt)
|
||||
}
|
||||
|
||||
func (fi *FileInfo) MakeContentInaccessible() {
|
||||
if fi == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fi.Archived = true
|
||||
fi.Content = ""
|
||||
fi.HasPreviewImage = false
|
||||
fi.MiniPreview = nil
|
||||
fi.Path = ""
|
||||
fi.PreviewPath = ""
|
||||
fi.ThumbnailPath = ""
|
||||
}
|
||||
113
vendor/github.com/mattermost/mattermost/server/public/model/file_info_list.go
generated
vendored
Normal file
113
vendor/github.com/mattermost/mattermost/server/public/model/file_info_list.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
type FileInfoList struct {
|
||||
Order []string `json:"order"`
|
||||
FileInfos map[string]*FileInfo `json:"file_infos"`
|
||||
NextFileInfoId string `json:"next_file_info_id"`
|
||||
PrevFileInfoId string `json:"prev_file_info_id"`
|
||||
// If there are inaccessible files, FirstInaccessibleFileTime is the time of the latest inaccessible file
|
||||
FirstInaccessibleFileTime int64 `json:"first_inaccessible_file_time"`
|
||||
}
|
||||
|
||||
func NewFileInfoList() *FileInfoList {
|
||||
return &FileInfoList{
|
||||
Order: make([]string, 0),
|
||||
FileInfos: make(map[string]*FileInfo),
|
||||
NextFileInfoId: "",
|
||||
PrevFileInfoId: "",
|
||||
}
|
||||
}
|
||||
|
||||
func (o *FileInfoList) ToSlice() []*FileInfo {
|
||||
var fileInfos []*FileInfo
|
||||
for _, id := range o.Order {
|
||||
fileInfos = append(fileInfos, o.FileInfos[id])
|
||||
}
|
||||
return fileInfos
|
||||
}
|
||||
|
||||
func (o *FileInfoList) MakeNonNil() {
|
||||
if o.Order == nil {
|
||||
o.Order = make([]string, 0)
|
||||
}
|
||||
|
||||
if o.FileInfos == nil {
|
||||
o.FileInfos = make(map[string]*FileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *FileInfoList) AddOrder(id string) {
|
||||
if o.Order == nil {
|
||||
o.Order = make([]string, 0, 128)
|
||||
}
|
||||
|
||||
o.Order = append(o.Order, id)
|
||||
}
|
||||
|
||||
func (o *FileInfoList) AddFileInfo(fileInfo *FileInfo) {
|
||||
if o.FileInfos == nil {
|
||||
o.FileInfos = make(map[string]*FileInfo)
|
||||
}
|
||||
|
||||
o.FileInfos[fileInfo.Id] = fileInfo
|
||||
}
|
||||
|
||||
func (o *FileInfoList) UniqueOrder() {
|
||||
keys := make(map[string]bool)
|
||||
order := []string{}
|
||||
for _, fileInfoId := range o.Order {
|
||||
if _, value := keys[fileInfoId]; !value {
|
||||
keys[fileInfoId] = true
|
||||
order = append(order, fileInfoId)
|
||||
}
|
||||
}
|
||||
|
||||
o.Order = order
|
||||
}
|
||||
|
||||
func (o *FileInfoList) Extend(other *FileInfoList) {
|
||||
for fileInfoId := range other.FileInfos {
|
||||
o.AddFileInfo(other.FileInfos[fileInfoId])
|
||||
}
|
||||
|
||||
for _, fileInfoId := range other.Order {
|
||||
o.AddOrder(fileInfoId)
|
||||
}
|
||||
|
||||
o.UniqueOrder()
|
||||
}
|
||||
|
||||
func (o *FileInfoList) SortByCreateAt() {
|
||||
sort.Slice(o.Order, func(i, j int) bool {
|
||||
return o.FileInfos[o.Order[i]].CreateAt > o.FileInfos[o.Order[j]].CreateAt
|
||||
})
|
||||
}
|
||||
|
||||
func (o *FileInfoList) Etag() string {
|
||||
id := "0"
|
||||
var t int64
|
||||
|
||||
for _, v := range o.FileInfos {
|
||||
if v.UpdateAt > t {
|
||||
t = v.UpdateAt
|
||||
id = v.Id
|
||||
} else if v.UpdateAt == t && v.Id > id {
|
||||
t = v.UpdateAt
|
||||
id = v.Id
|
||||
}
|
||||
}
|
||||
|
||||
orderId := ""
|
||||
if len(o.Order) > 0 {
|
||||
orderId = o.Order[0]
|
||||
}
|
||||
|
||||
return Etag(orderId, id, t)
|
||||
}
|
||||
18
vendor/github.com/mattermost/mattermost/server/public/model/file_info_search_results.go
generated
vendored
Normal file
18
vendor/github.com/mattermost/mattermost/server/public/model/file_info_search_results.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type FileInfoSearchMatches map[string][]string
|
||||
|
||||
type FileInfoSearchResults struct {
|
||||
*FileInfoList
|
||||
Matches FileInfoSearchMatches `json:"matches"`
|
||||
}
|
||||
|
||||
func MakeFileInfoSearchResults(fileInfos *FileInfoList, matches FileInfoSearchMatches) *FileInfoSearchResults {
|
||||
return &FileInfoSearchResults{
|
||||
fileInfos,
|
||||
matches,
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/mattermost/mattermost/server/public/model/github_release.go
generated
vendored
Normal file
26
vendor/github.com/mattermost/mattermost/server/public/model/github_release.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type GithubReleaseInfo struct {
|
||||
Id int `json:"id"`
|
||||
TagName string `json:"tag_name"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
PublishedAt string `json:"published_at"`
|
||||
Body string `json:"body"`
|
||||
Url string `json:"html_url"`
|
||||
}
|
||||
|
||||
func (g *GithubReleaseInfo) IsValid() *AppError {
|
||||
if g.Id == 0 {
|
||||
return NewAppError("GithubReleaseInfo.IsValid", NoTranslation, nil, "empty ID", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
8
vendor/github.com/mattermost/mattermost/server/public/model/gitlab.go
generated
vendored
Normal file
8
vendor/github.com/mattermost/mattermost/server/public/model/gitlab.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
UserAuthServiceGitlab = "gitlab"
|
||||
)
|
||||
295
vendor/github.com/mattermost/mattermost/server/public/model/group.go
generated
vendored
Normal file
295
vendor/github.com/mattermost/mattermost/server/public/model/group.go
generated
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
GroupSourceLdap GroupSource = "ldap"
|
||||
GroupSourceCustom GroupSource = "custom"
|
||||
|
||||
GroupNameMaxLength = 64
|
||||
GroupSourceMaxLength = 64
|
||||
GroupDisplayNameMaxLength = 128
|
||||
GroupDescriptionMaxLength = 1024
|
||||
GroupRemoteIDMaxLength = 48
|
||||
)
|
||||
|
||||
type GroupSource string
|
||||
|
||||
var allGroupSources = []GroupSource{
|
||||
GroupSourceLdap,
|
||||
GroupSourceCustom,
|
||||
}
|
||||
|
||||
var groupSourcesRequiringRemoteID = []GroupSource{
|
||||
GroupSourceLdap,
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
Id string `json:"id"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Description string `json:"description"`
|
||||
Source GroupSource `json:"source"`
|
||||
RemoteId *string `json:"remote_id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
HasSyncables bool `db:"-" json:"has_syncables"`
|
||||
MemberCount *int `db:"-" json:"member_count,omitempty"`
|
||||
AllowReference bool `json:"allow_reference"`
|
||||
ChannelMemberCount *int `db:"-" json:"channel_member_count,omitempty"`
|
||||
ChannelMemberTimezonesCount *int `db:"-" json:"channel_member_timezones_count,omitempty"`
|
||||
MemberIDs []string `db:"-" json:"member_ids"`
|
||||
}
|
||||
|
||||
func (group *Group) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": group.Id,
|
||||
"source": group.Source,
|
||||
"remote_id": group.RemoteId,
|
||||
"create_at": group.CreateAt,
|
||||
"update_at": group.UpdateAt,
|
||||
"delete_at": group.DeleteAt,
|
||||
"has_syncables": group.HasSyncables,
|
||||
"member_count": group.MemberCount,
|
||||
"allow_reference": group.AllowReference,
|
||||
}
|
||||
}
|
||||
|
||||
func (group *Group) LogClone() any {
|
||||
return group.Auditable()
|
||||
}
|
||||
|
||||
type GroupWithUserIds struct {
|
||||
Group
|
||||
UserIds []string `json:"user_ids"`
|
||||
}
|
||||
|
||||
func (group *GroupWithUserIds) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": group.Id,
|
||||
"source": group.Source,
|
||||
"remote_id": group.RemoteId,
|
||||
"create_at": group.CreateAt,
|
||||
"update_at": group.UpdateAt,
|
||||
"delete_at": group.DeleteAt,
|
||||
"has_syncables": group.HasSyncables,
|
||||
"member_count": group.MemberCount,
|
||||
"allow_reference": group.AllowReference,
|
||||
"user_ids": group.UserIds,
|
||||
}
|
||||
}
|
||||
|
||||
type GroupWithSchemeAdmin struct {
|
||||
Group
|
||||
SchemeAdmin *bool `db:"SyncableSchemeAdmin" json:"scheme_admin,omitempty"`
|
||||
}
|
||||
|
||||
type GroupsAssociatedToChannelWithSchemeAdmin struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
Group
|
||||
SchemeAdmin *bool `db:"SyncableSchemeAdmin" json:"scheme_admin,omitempty"`
|
||||
}
|
||||
type GroupsAssociatedToChannel struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
Groups []*GroupWithSchemeAdmin `json:"groups"`
|
||||
}
|
||||
|
||||
type GroupPatch struct {
|
||||
Name *string `json:"name"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
Description *string `json:"description"`
|
||||
AllowReference *bool `json:"allow_reference"`
|
||||
// For security reasons (including preventing unintended LDAP group synchronization) do no allow a Group's RemoteId or Source field to be
|
||||
// included in patches.
|
||||
}
|
||||
|
||||
type LdapGroupSearchOpts struct {
|
||||
Q string
|
||||
IsLinked *bool
|
||||
IsConfigured *bool
|
||||
}
|
||||
|
||||
type GroupSearchOpts struct {
|
||||
Q string
|
||||
NotAssociatedToTeam string
|
||||
NotAssociatedToChannel string
|
||||
IncludeMemberCount bool
|
||||
FilterAllowReference bool
|
||||
PageOpts *PageOpts
|
||||
Since int64
|
||||
Source GroupSource
|
||||
|
||||
// FilterParentTeamPermitted filters the groups to the intersect of the
|
||||
// set associated to the parent team and those returned by the query.
|
||||
// If the parent team is not group-constrained or if NotAssociatedToChannel
|
||||
// is not set then this option is ignored.
|
||||
FilterParentTeamPermitted bool
|
||||
|
||||
// FilterHasMember filters the groups to the intersect of the
|
||||
// set returned by the query and those that have the given user as a member.
|
||||
FilterHasMember string
|
||||
|
||||
IncludeChannelMemberCount string
|
||||
IncludeTimezones bool
|
||||
IncludeMemberIDs bool
|
||||
|
||||
// Include archived groups
|
||||
IncludeArchived bool
|
||||
|
||||
// Only return archived groups
|
||||
FilterArchived bool
|
||||
}
|
||||
|
||||
type GetGroupOpts struct {
|
||||
IncludeMemberCount bool
|
||||
IncludeMemberIDs bool
|
||||
}
|
||||
|
||||
type PageOpts struct {
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
type GroupStats struct {
|
||||
GroupID string `json:"group_id"`
|
||||
TotalMemberCount int64 `json:"total_member_count"`
|
||||
}
|
||||
|
||||
type GroupModifyMembers struct {
|
||||
UserIds []string `json:"user_ids"`
|
||||
}
|
||||
|
||||
func (group *GroupModifyMembers) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"user_ids": group.UserIds,
|
||||
}
|
||||
}
|
||||
|
||||
func (group *Group) Patch(patch *GroupPatch) {
|
||||
if patch.Name != nil {
|
||||
group.Name = patch.Name
|
||||
}
|
||||
if patch.DisplayName != nil {
|
||||
group.DisplayName = *patch.DisplayName
|
||||
}
|
||||
if patch.Description != nil {
|
||||
group.Description = *patch.Description
|
||||
}
|
||||
if patch.AllowReference != nil {
|
||||
group.AllowReference = *patch.AllowReference
|
||||
}
|
||||
}
|
||||
|
||||
func (group *Group) IsValidForCreate() *AppError {
|
||||
appErr := group.IsValidName()
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
if l := len(group.DisplayName); l == 0 || l > GroupDisplayNameMaxLength {
|
||||
return NewAppError("Group.IsValidForCreate", "model.group.display_name.app_error", map[string]any{"GroupDisplayNameMaxLength": GroupDisplayNameMaxLength}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(group.Description) > GroupDescriptionMaxLength {
|
||||
return NewAppError("Group.IsValidForCreate", "model.group.description.app_error", map[string]any{"GroupDescriptionMaxLength": GroupDescriptionMaxLength}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
isValidSource := false
|
||||
for _, groupSource := range allGroupSources {
|
||||
if group.Source == groupSource {
|
||||
isValidSource = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isValidSource {
|
||||
return NewAppError("Group.IsValidForCreate", "model.group.source.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if (group.GetRemoteId() == "" && group.requiresRemoteId()) || len(group.GetRemoteId()) > GroupRemoteIDMaxLength {
|
||||
return NewAppError("Group.IsValidForCreate", "model.group.remote_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (group *Group) requiresRemoteId() bool {
|
||||
for _, groupSource := range groupSourcesRequiringRemoteID {
|
||||
if groupSource == group.Source {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (group *Group) IsValidForUpdate() *AppError {
|
||||
if !IsValidId(group.Id) {
|
||||
return NewAppError("Group.IsValidForUpdate", "app.group.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
if group.CreateAt == 0 {
|
||||
return NewAppError("Group.IsValidForUpdate", "model.group.create_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
if group.UpdateAt == 0 {
|
||||
return NewAppError("Group.IsValidForUpdate", "model.group.update_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
if appErr := group.IsValidForCreate(); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var validGroupnameChars = regexp.MustCompile(`^[a-z0-9\.\-_]+$`)
|
||||
|
||||
func (group *Group) IsValidName() *AppError {
|
||||
if group.Name == nil {
|
||||
if group.AllowReference {
|
||||
return NewAppError("Group.IsValidName", "model.group.name.app_error", map[string]any{"GroupNameMaxLength": GroupNameMaxLength}, "", http.StatusBadRequest)
|
||||
}
|
||||
} else {
|
||||
if l := len(*group.Name); l == 0 || l > GroupNameMaxLength {
|
||||
return NewAppError("Group.IsValidName", "model.group.name.invalid_length.app_error", map[string]any{"GroupNameMaxLength": GroupNameMaxLength}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if *group.Name == UserNotifyAll || *group.Name == ChannelMentionsNotifyProp || *group.Name == UserNotifyHere {
|
||||
return NewAppError("IsValidName", "model.group.name.reserved_name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !validGroupnameChars.MatchString(*group.Name) {
|
||||
return NewAppError("Group.IsValidName", "model.group.name.invalid_chars.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (group *Group) GetName() string {
|
||||
if group.Name == nil {
|
||||
return ""
|
||||
}
|
||||
return *group.Name
|
||||
}
|
||||
|
||||
func (group *Group) GetRemoteId() string {
|
||||
if group.RemoteId == nil {
|
||||
return ""
|
||||
}
|
||||
return *group.RemoteId
|
||||
}
|
||||
|
||||
type GroupsWithCount struct {
|
||||
Groups []*Group `json:"groups"`
|
||||
TotalCount int64 `json:"total_count"`
|
||||
}
|
||||
|
||||
type CreateDefaultMembershipParams struct {
|
||||
Since int64
|
||||
ReAddRemovedMembers bool
|
||||
ScopedUserID *string
|
||||
ScopedTeamID *string
|
||||
ScopedChannelID *string
|
||||
}
|
||||
28
vendor/github.com/mattermost/mattermost/server/public/model/group_member.go
generated
vendored
Normal file
28
vendor/github.com/mattermost/mattermost/server/public/model/group_member.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import "net/http"
|
||||
|
||||
type GroupMember struct {
|
||||
GroupId string `json:"group_id"`
|
||||
UserId string `json:"user_id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
}
|
||||
|
||||
func (gm *GroupMember) IsValid() *AppError {
|
||||
if !IsValidId(gm.GroupId) {
|
||||
return NewAppError("GroupMember.IsValid", "model.group_member.group_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
if !IsValidId(gm.UserId) {
|
||||
return NewAppError("GroupMember.IsValid", "model.group_member.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GroupMemberList struct {
|
||||
Members []*User `json:"members"`
|
||||
Count int `json:"total_member_count"`
|
||||
}
|
||||
198
vendor/github.com/mattermost/mattermost/server/public/model/group_syncable.go
generated
vendored
Normal file
198
vendor/github.com/mattermost/mattermost/server/public/model/group_syncable.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type GroupSyncableType string
|
||||
|
||||
const (
|
||||
GroupSyncableTypeTeam GroupSyncableType = "Team"
|
||||
GroupSyncableTypeChannel GroupSyncableType = "Channel"
|
||||
)
|
||||
|
||||
func (gst GroupSyncableType) String() string {
|
||||
return string(gst)
|
||||
}
|
||||
|
||||
type GroupSyncable struct {
|
||||
GroupId string `json:"group_id"`
|
||||
|
||||
// SyncableId represents the Id of the model that is being synced with the group, for example a ChannelId or
|
||||
// TeamId.
|
||||
SyncableId string `db:"-" json:"-"`
|
||||
|
||||
AutoAdd bool `json:"auto_add"`
|
||||
SchemeAdmin bool `json:"scheme_admin"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
Type GroupSyncableType `db:"-" json:"-"`
|
||||
|
||||
// Values joined in from the associated team and/or channel
|
||||
ChannelDisplayName string `db:"-" json:"-"`
|
||||
TeamDisplayName string `db:"-" json:"-"`
|
||||
TeamType string `db:"-" json:"-"`
|
||||
ChannelType string `db:"-" json:"-"`
|
||||
TeamID string `db:"-" json:"-"`
|
||||
}
|
||||
|
||||
func (syncable *GroupSyncable) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"group_id": syncable.GroupId,
|
||||
"syncable_id": syncable.SyncableId,
|
||||
"auto_add": syncable.AutoAdd,
|
||||
"scheme_admin": syncable.SchemeAdmin,
|
||||
"create_at": syncable.CreateAt,
|
||||
"delete_at": syncable.DeleteAt,
|
||||
"update_at": syncable.UpdateAt,
|
||||
"type": syncable.Type,
|
||||
"channel_display_name": syncable.ChannelDisplayName,
|
||||
"team_display_name": syncable.TeamDisplayName,
|
||||
"team_type": syncable.TeamType,
|
||||
"channel_type": syncable.ChannelType,
|
||||
"team_id": syncable.TeamID,
|
||||
}
|
||||
}
|
||||
|
||||
func (syncable *GroupSyncable) IsValid() *AppError {
|
||||
if !IsValidId(syncable.GroupId) {
|
||||
return NewAppError("GroupSyncable.SyncableIsValid", "model.group_syncable.group_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
if !IsValidId(syncable.SyncableId) {
|
||||
return NewAppError("GroupSyncable.SyncableIsValid", "model.group_syncable.syncable_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (syncable *GroupSyncable) UnmarshalJSON(b []byte) error {
|
||||
var kvp map[string]any
|
||||
err := json.Unmarshal(b, &kvp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var channelId string
|
||||
var teamId string
|
||||
for key, value := range kvp {
|
||||
switch key {
|
||||
case "team_id":
|
||||
teamId = value.(string)
|
||||
case "channel_id":
|
||||
channelId = value.(string)
|
||||
case "group_id":
|
||||
syncable.GroupId = value.(string)
|
||||
case "auto_add":
|
||||
syncable.AutoAdd = value.(bool)
|
||||
default:
|
||||
}
|
||||
}
|
||||
if channelId != "" {
|
||||
syncable.TeamID = teamId
|
||||
syncable.SyncableId = channelId
|
||||
syncable.Type = GroupSyncableTypeChannel
|
||||
} else {
|
||||
syncable.SyncableId = teamId
|
||||
syncable.Type = GroupSyncableTypeTeam
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (syncable *GroupSyncable) MarshalJSON() ([]byte, error) {
|
||||
type Alias GroupSyncable
|
||||
switch syncable.Type {
|
||||
case GroupSyncableTypeTeam:
|
||||
return json.Marshal(&struct {
|
||||
TeamID string `json:"team_id"`
|
||||
TeamDisplayName string `json:"team_display_name,omitempty"`
|
||||
TeamType string `json:"team_type,omitempty"`
|
||||
Type GroupSyncableType `json:"type,omitempty"`
|
||||
*Alias
|
||||
}{
|
||||
TeamDisplayName: syncable.TeamDisplayName,
|
||||
TeamType: syncable.TeamType,
|
||||
TeamID: syncable.SyncableId,
|
||||
Type: syncable.Type,
|
||||
Alias: (*Alias)(syncable),
|
||||
})
|
||||
case GroupSyncableTypeChannel:
|
||||
return json.Marshal(&struct {
|
||||
ChannelID string `json:"channel_id"`
|
||||
ChannelDisplayName string `json:"channel_display_name,omitempty"`
|
||||
ChannelType string `json:"channel_type,omitempty"`
|
||||
Type GroupSyncableType `json:"type,omitempty"`
|
||||
|
||||
TeamID string `json:"team_id,omitempty"`
|
||||
TeamDisplayName string `json:"team_display_name,omitempty"`
|
||||
TeamType string `json:"team_type,omitempty"`
|
||||
|
||||
*Alias
|
||||
}{
|
||||
ChannelID: syncable.SyncableId,
|
||||
ChannelDisplayName: syncable.ChannelDisplayName,
|
||||
ChannelType: syncable.ChannelType,
|
||||
Type: syncable.Type,
|
||||
|
||||
TeamID: syncable.TeamID,
|
||||
TeamDisplayName: syncable.TeamDisplayName,
|
||||
TeamType: syncable.TeamType,
|
||||
|
||||
Alias: (*Alias)(syncable),
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown syncable type: %s", syncable.Type)
|
||||
}
|
||||
}
|
||||
|
||||
type GroupSyncablePatch struct {
|
||||
AutoAdd *bool `json:"auto_add"`
|
||||
SchemeAdmin *bool `json:"scheme_admin"`
|
||||
}
|
||||
|
||||
func (syncable *GroupSyncablePatch) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"auto_add": syncable.AutoAdd,
|
||||
"scheme_admin": syncable.SchemeAdmin,
|
||||
}
|
||||
}
|
||||
|
||||
func (syncable *GroupSyncable) Patch(patch *GroupSyncablePatch) {
|
||||
if patch.AutoAdd != nil {
|
||||
syncable.AutoAdd = *patch.AutoAdd
|
||||
}
|
||||
if patch.SchemeAdmin != nil {
|
||||
syncable.SchemeAdmin = *patch.SchemeAdmin
|
||||
}
|
||||
}
|
||||
|
||||
type UserTeamIDPair struct {
|
||||
UserID string
|
||||
TeamID string
|
||||
}
|
||||
|
||||
type UserChannelIDPair struct {
|
||||
UserID string
|
||||
ChannelID string
|
||||
}
|
||||
|
||||
func NewGroupTeam(groupID, teamID string, autoAdd bool) *GroupSyncable {
|
||||
return &GroupSyncable{
|
||||
GroupId: groupID,
|
||||
SyncableId: teamID,
|
||||
Type: GroupSyncableTypeTeam,
|
||||
AutoAdd: autoAdd,
|
||||
}
|
||||
}
|
||||
|
||||
func NewGroupChannel(groupID, channelID string, autoAdd bool) *GroupSyncable {
|
||||
return &GroupSyncable{
|
||||
GroupId: groupID,
|
||||
SyncableId: channelID,
|
||||
Type: GroupSyncableTypeChannel,
|
||||
AutoAdd: autoAdd,
|
||||
}
|
||||
}
|
||||
46
vendor/github.com/mattermost/mattermost/server/public/model/guest_invite.go
generated
vendored
Normal file
46
vendor/github.com/mattermost/mattermost/server/public/model/guest_invite.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type GuestsInvite struct {
|
||||
Emails []string `json:"emails"`
|
||||
Channels []string `json:"channels"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (i *GuestsInvite) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"emails": i.Emails,
|
||||
"channels": i.Channels,
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid validates the user and returns an error if it isn't configured
|
||||
// correctly.
|
||||
func (i *GuestsInvite) IsValid() *AppError {
|
||||
if len(i.Emails) == 0 {
|
||||
return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.emails.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
for _, email := range i.Emails {
|
||||
if len(email) > UserEmailMaxLength || email == "" || !IsValidEmail(email) {
|
||||
return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.email.app_error", nil, "email="+email, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if len(i.Channels) == 0 {
|
||||
return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.channels.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
for _, channel := range i.Channels {
|
||||
if len(channel) != 26 {
|
||||
return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.channel.app_error", nil, "channel="+channel, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
10
vendor/github.com/mattermost/mattermost/server/public/model/hosted_customer.go
generated
vendored
Normal file
10
vendor/github.com/mattermost/mattermost/server/public/model/hosted_customer.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type SubscribeNewsletterRequest struct {
|
||||
Email string `json:"email"`
|
||||
ServerID string `json:"server_id"`
|
||||
SubscribedContent string `json:"subscribed_content"`
|
||||
}
|
||||
203
vendor/github.com/mattermost/mattermost/server/public/model/incoming_webhook.go
generated
vendored
Normal file
203
vendor/github.com/mattermost/mattermost/server/public/model/incoming_webhook.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultWebhookUsername = "webhook"
|
||||
)
|
||||
|
||||
type IncomingWebhook struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
UserId string `json:"user_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
TeamId string `json:"team_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Description string `json:"description"`
|
||||
Username string `json:"username"`
|
||||
IconURL string `json:"icon_url"`
|
||||
ChannelLocked bool `json:"channel_locked"`
|
||||
}
|
||||
|
||||
func (o *IncomingWebhook) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": o.Id,
|
||||
"create_at": o.CreateAt,
|
||||
"update_at": o.UpdateAt,
|
||||
"delete_at": o.DeleteAt,
|
||||
"user_id": o.UserId,
|
||||
"channel_id": o.ChannelId,
|
||||
"team_id": o.TeamId,
|
||||
"display_name": o.DisplayName,
|
||||
"description": o.Description,
|
||||
"username": o.Username,
|
||||
"icon_url:": o.IconURL,
|
||||
"channel_locked": o.ChannelLocked,
|
||||
}
|
||||
}
|
||||
|
||||
type IncomingWebhookRequest struct {
|
||||
Text string `json:"text"`
|
||||
Username string `json:"username"`
|
||||
IconURL string `json:"icon_url"`
|
||||
ChannelName string `json:"channel"`
|
||||
Props StringInterface `json:"props"`
|
||||
Attachments []*SlackAttachment `json:"attachments"`
|
||||
Type string `json:"type"`
|
||||
IconEmoji string `json:"icon_emoji"`
|
||||
Priority *PostPriority `json:"priority"`
|
||||
}
|
||||
|
||||
func (o *IncomingWebhook) IsValid() *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.UpdateAt == 0 {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.UserId) {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.ChannelId) {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.channel_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.TeamId) {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.team_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.DisplayName) > 64 {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.display_name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Description) > 500 {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.description.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Username) > 64 {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.username.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.IconURL) > 1024 {
|
||||
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.icon_url.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *IncomingWebhook) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
o.CreateAt = GetMillis()
|
||||
o.UpdateAt = o.CreateAt
|
||||
}
|
||||
|
||||
func (o *IncomingWebhook) PreUpdate() {
|
||||
o.UpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
// escapeControlCharsFromPayload escapes control chars (\n, \t) from a byte slice.
|
||||
// Context:
|
||||
// JSON strings are not supposed to contain control characters such as \n, \t,
|
||||
// ... but some incoming webhooks might still send invalid JSON and we want to
|
||||
// try to handle that. An example invalid JSON string from an incoming webhook
|
||||
// might look like this (strings for both "text" and "fallback" attributes are
|
||||
// invalid JSON strings because they contain unescaped newlines and tabs):
|
||||
//
|
||||
// `{
|
||||
// "text": "this is a test
|
||||
// that contains a newline and tabs",
|
||||
// "attachments": [
|
||||
// {
|
||||
// "fallback": "Required plain-text summary of the attachment
|
||||
// that contains a newline and tabs",
|
||||
// "color": "#36a64f",
|
||||
// ...
|
||||
// "text": "Optional text that appears within the attachment
|
||||
// that contains a newline and tabs",
|
||||
// ...
|
||||
// "thumb_url": "http://example.com/path/to/thumb.png"
|
||||
// }
|
||||
// ]
|
||||
// }`
|
||||
//
|
||||
// This function will search for `"key": "value"` pairs, and escape \n, \t
|
||||
// from the value.
|
||||
func escapeControlCharsFromPayload(by []byte) []byte {
|
||||
// we'll search for `"text": "..."` or `"fallback": "..."`, ...
|
||||
keys := "text|fallback|pretext|author_name|title|value"
|
||||
|
||||
// the regexp reads like this:
|
||||
// (?s): this flag let . match \n (default is false)
|
||||
// "(keys)": we search for the keys defined above
|
||||
// \s*:\s*: followed by 0..n spaces/tabs, a colon then 0..n spaces/tabs
|
||||
// ": a double-quote
|
||||
// (\\"|[^"])*: any number of times the `\"` string or any char but a double-quote
|
||||
// ": a double-quote
|
||||
r := `(?s)"(` + keys + `)"\s*:\s*"(\\"|[^"])*"`
|
||||
re := regexp.MustCompile(r)
|
||||
|
||||
// the function that will escape \n and \t on the regexp matches
|
||||
repl := func(b []byte) []byte {
|
||||
if bytes.Contains(b, []byte("\n")) {
|
||||
b = bytes.Replace(b, []byte("\n"), []byte("\\n"), -1)
|
||||
}
|
||||
if bytes.Contains(b, []byte("\t")) {
|
||||
b = bytes.Replace(b, []byte("\t"), []byte("\\t"), -1)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
return re.ReplaceAllFunc(by, repl)
|
||||
}
|
||||
|
||||
func decodeIncomingWebhookRequest(by []byte) (*IncomingWebhookRequest, error) {
|
||||
decoder := json.NewDecoder(bytes.NewReader(by))
|
||||
var o IncomingWebhookRequest
|
||||
err := decoder.Decode(&o)
|
||||
if err == nil {
|
||||
return &o, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func IncomingWebhookRequestFromJSON(data io.Reader) (*IncomingWebhookRequest, *AppError) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(data)
|
||||
by := buf.Bytes()
|
||||
|
||||
// Try to decode the JSON data. Only if it fails, try to escape control
|
||||
// characters from the strings contained in the JSON data.
|
||||
o, err := decodeIncomingWebhookRequest(by)
|
||||
if err != nil {
|
||||
o, err = decodeIncomingWebhookRequest(escapeControlCharsFromPayload(by))
|
||||
if err != nil {
|
||||
return nil, NewAppError("IncomingWebhookRequestFromJSON", "model.incoming_hook.parse_data.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
o.Attachments = StringifySlackFieldValue(o.Attachments)
|
||||
|
||||
return o, nil
|
||||
}
|
||||
14
vendor/github.com/mattermost/mattermost/server/public/model/initial_load.go
generated
vendored
Normal file
14
vendor/github.com/mattermost/mattermost/server/public/model/initial_load.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type InitialLoad struct {
|
||||
User *User `json:"user"`
|
||||
TeamMembers []*TeamMember `json:"team_members"`
|
||||
Teams []*Team `json:"teams"`
|
||||
Preferences Preferences `json:"preferences"`
|
||||
ClientCfg map[string]string `json:"client_cfg"`
|
||||
LicenseCfg map[string]string `json:"license_cfg"`
|
||||
NoAccounts bool `json:"no_accounts"`
|
||||
}
|
||||
635
vendor/github.com/mattermost/mattermost/server/public/model/integration_action.go
generated
vendored
Normal file
635
vendor/github.com/mattermost/mattermost/server/public/model/integration_action.go
generated
vendored
Normal file
@@ -0,0 +1,635 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
PostActionTypeButton = "button"
|
||||
PostActionTypeSelect = "select"
|
||||
DialogTitleMaxLength = 24
|
||||
DialogElementDisplayNameMaxLength = 24
|
||||
DialogElementNameMaxLength = 300
|
||||
DialogElementHelpTextMaxLength = 150
|
||||
DialogElementTextMaxLength = 150
|
||||
DialogElementTextareaMaxLength = 3000
|
||||
DialogElementSelectMaxLength = 3000
|
||||
DialogElementBoolMaxLength = 150
|
||||
)
|
||||
|
||||
var PostActionRetainPropKeys = []string{"from_webhook", "override_username", "override_icon_url"}
|
||||
|
||||
type DoPostActionRequest struct {
|
||||
SelectedOption string `json:"selected_option,omitempty"`
|
||||
Cookie string `json:"cookie,omitempty"`
|
||||
}
|
||||
|
||||
type PostAction struct {
|
||||
// A unique Action ID. If not set, generated automatically.
|
||||
Id string `json:"id,omitempty"`
|
||||
|
||||
// The type of the interactive element. Currently supported are
|
||||
// "select" and "button".
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
// The text on the button, or in the select placeholder.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// If the action is disabled.
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
|
||||
// Style defines a text and border style.
|
||||
// Supported values are "default", "primary", "success", "good", "warning", "danger"
|
||||
// and any hex color.
|
||||
Style string `json:"style,omitempty"`
|
||||
|
||||
// DataSource indicates the data source for the select action. If left
|
||||
// empty, the select is populated from Options. Other supported values
|
||||
// are "users" and "channels".
|
||||
DataSource string `json:"data_source,omitempty"`
|
||||
|
||||
// Options contains the values listed in a select dropdown on the post.
|
||||
Options []*PostActionOptions `json:"options,omitempty"`
|
||||
|
||||
// DefaultOption contains the option, if any, that will appear as the
|
||||
// default selection in a select box. It has no effect when used with
|
||||
// other types of actions.
|
||||
DefaultOption string `json:"default_option,omitempty"`
|
||||
|
||||
// Defines the interaction with the backend upon a user action.
|
||||
// Integration contains Context, which is private plugin data;
|
||||
// Integrations are stripped from Posts when they are sent to the
|
||||
// client, or are encrypted in a Cookie.
|
||||
Integration *PostActionIntegration `json:"integration,omitempty"`
|
||||
Cookie string `json:"cookie,omitempty" db:"-"`
|
||||
}
|
||||
|
||||
func (p *PostAction) Equals(input *PostAction) bool {
|
||||
if p.Id != input.Id {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Type != input.Type {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Name != input.Name {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.DataSource != input.DataSource {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.DefaultOption != input.DefaultOption {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Cookie != input.Cookie {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compare PostActionOptions
|
||||
if len(p.Options) != len(input.Options) {
|
||||
return false
|
||||
}
|
||||
|
||||
for k := range p.Options {
|
||||
if p.Options[k].Text != input.Options[k].Text {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Options[k].Value != input.Options[k].Value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Compare PostActionIntegration
|
||||
|
||||
// If input is nil, then return true if original is also nil.
|
||||
// Else return false.
|
||||
if input.Integration == nil {
|
||||
return p.Integration == nil
|
||||
}
|
||||
|
||||
// At this point, input is not nil, so return false if original is.
|
||||
if p.Integration == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Both are unequal and not nil.
|
||||
if p.Integration.URL != input.Integration.URL {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(p.Integration.Context) != len(input.Integration.Context) {
|
||||
return false
|
||||
}
|
||||
|
||||
for key, value := range p.Integration.Context {
|
||||
inputValue, ok := input.Integration.Context[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
switch inputValue.(type) {
|
||||
case string, bool, int, float64:
|
||||
if value != inputValue {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !reflect.DeepEqual(value, inputValue) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// PostActionCookie is set by the server, serialized and encrypted into
|
||||
// PostAction.Cookie. The clients should hold on to it, and include it with
|
||||
// subsequent DoPostAction requests. This allows the server to access the
|
||||
// action metadata even when it's not available in the database, for ephemeral
|
||||
// posts.
|
||||
type PostActionCookie struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
PostId string `json:"post_id,omitempty"`
|
||||
RootPostId string `json:"root_post_id,omitempty"`
|
||||
ChannelId string `json:"channel_id,omitempty"`
|
||||
DataSource string `json:"data_source,omitempty"`
|
||||
Integration *PostActionIntegration `json:"integration,omitempty"`
|
||||
RetainProps map[string]any `json:"retain_props,omitempty"`
|
||||
RemoveProps []string `json:"remove_props,omitempty"`
|
||||
}
|
||||
|
||||
type PostActionOptions struct {
|
||||
Text string `json:"text"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type PostActionIntegration struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
Context map[string]any `json:"context,omitempty"`
|
||||
}
|
||||
|
||||
type PostActionIntegrationRequest struct {
|
||||
UserId string `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
TeamId string `json:"team_id"`
|
||||
TeamName string `json:"team_domain"`
|
||||
PostId string `json:"post_id"`
|
||||
TriggerId string `json:"trigger_id"`
|
||||
Type string `json:"type"`
|
||||
DataSource string `json:"data_source"`
|
||||
Context map[string]any `json:"context,omitempty"`
|
||||
}
|
||||
|
||||
type PostActionIntegrationResponse struct {
|
||||
Update *Post `json:"update"`
|
||||
EphemeralText string `json:"ephemeral_text"`
|
||||
SkipSlackParsing bool `json:"skip_slack_parsing"` // Set to `true` to skip the Slack-compatibility handling of Text.
|
||||
}
|
||||
|
||||
type PostActionAPIResponse struct {
|
||||
Status string `json:"status"` // needed to maintain backwards compatibility
|
||||
TriggerId string `json:"trigger_id"`
|
||||
}
|
||||
|
||||
type Dialog struct {
|
||||
CallbackId string `json:"callback_id"`
|
||||
Title string `json:"title"`
|
||||
IntroductionText string `json:"introduction_text"`
|
||||
IconURL string `json:"icon_url"`
|
||||
Elements []DialogElement `json:"elements"`
|
||||
SubmitLabel string `json:"submit_label"`
|
||||
NotifyOnCancel bool `json:"notify_on_cancel"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
type DialogElement struct {
|
||||
DisplayName string `json:"display_name"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SubType string `json:"subtype"`
|
||||
Default string `json:"default"`
|
||||
Placeholder string `json:"placeholder"`
|
||||
HelpText string `json:"help_text"`
|
||||
Optional bool `json:"optional"`
|
||||
MinLength int `json:"min_length"`
|
||||
MaxLength int `json:"max_length"`
|
||||
DataSource string `json:"data_source"`
|
||||
Options []*PostActionOptions `json:"options"`
|
||||
}
|
||||
|
||||
type OpenDialogRequest struct {
|
||||
TriggerId string `json:"trigger_id"`
|
||||
URL string `json:"url"`
|
||||
Dialog Dialog `json:"dialog"`
|
||||
}
|
||||
|
||||
type SubmitDialogRequest struct {
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url,omitempty"`
|
||||
CallbackId string `json:"callback_id"`
|
||||
State string `json:"state"`
|
||||
UserId string `json:"user_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
TeamId string `json:"team_id"`
|
||||
Submission map[string]any `json:"submission"`
|
||||
Cancelled bool `json:"cancelled"`
|
||||
}
|
||||
|
||||
type SubmitDialogResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
Errors map[string]string `json:"errors,omitempty"`
|
||||
}
|
||||
|
||||
func GenerateTriggerId(userId string, s crypto.Signer) (string, string, *AppError) {
|
||||
clientTriggerId := NewId()
|
||||
triggerData := strings.Join([]string{clientTriggerId, userId, strconv.FormatInt(GetMillis(), 10)}, ":") + ":"
|
||||
|
||||
h := crypto.SHA256
|
||||
sum := h.New()
|
||||
sum.Write([]byte(triggerData))
|
||||
signature, err := s.Sign(rand.Reader, sum.Sum(nil), h)
|
||||
if err != nil {
|
||||
return "", "", NewAppError("GenerateTriggerId", "interactive_message.generate_trigger_id.signing_failed", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
base64Sig := base64.StdEncoding.EncodeToString(signature)
|
||||
|
||||
triggerId := base64.StdEncoding.EncodeToString([]byte(triggerData + base64Sig))
|
||||
return clientTriggerId, triggerId, nil
|
||||
}
|
||||
|
||||
func (r *PostActionIntegrationRequest) GenerateTriggerId(s crypto.Signer) (string, string, *AppError) {
|
||||
clientTriggerId, triggerId, appErr := GenerateTriggerId(r.UserId, s)
|
||||
if appErr != nil {
|
||||
return "", "", appErr
|
||||
}
|
||||
|
||||
r.TriggerId = triggerId
|
||||
return clientTriggerId, triggerId, nil
|
||||
}
|
||||
|
||||
func DecodeAndVerifyTriggerId(triggerId string, s *ecdsa.PrivateKey, timeout time.Duration) (string, string, *AppError) {
|
||||
triggerIdBytes, err := base64.StdEncoding.DecodeString(triggerId)
|
||||
if err != nil {
|
||||
return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.base64_decode_failed", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
split := strings.Split(string(triggerIdBytes), ":")
|
||||
if len(split) != 4 {
|
||||
return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.missing_data", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
clientTriggerId := split[0]
|
||||
userId := split[1]
|
||||
timestampStr := split[2]
|
||||
timestamp, _ := strconv.ParseInt(timestampStr, 10, 64)
|
||||
|
||||
if time.Since(time.UnixMilli(timestamp)) > timeout {
|
||||
return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.expired", map[string]any{"Duration": timeout.String()}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
signature, err := base64.StdEncoding.DecodeString(split[3])
|
||||
if err != nil {
|
||||
return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.base64_decode_failed_signature", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
var esig struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
if _, err := asn1.Unmarshal(signature, &esig); err != nil {
|
||||
return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.signature_decode_failed", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
triggerData := strings.Join([]string{clientTriggerId, userId, timestampStr}, ":") + ":"
|
||||
|
||||
h := crypto.SHA256
|
||||
sum := h.New()
|
||||
sum.Write([]byte(triggerData))
|
||||
|
||||
if !ecdsa.Verify(&s.PublicKey, sum.Sum(nil), esig.R, esig.S) {
|
||||
return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.verify_signature_failed", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return clientTriggerId, userId, nil
|
||||
}
|
||||
|
||||
func (r *OpenDialogRequest) DecodeAndVerifyTriggerId(s *ecdsa.PrivateKey, timeout time.Duration) (string, string, *AppError) {
|
||||
return DecodeAndVerifyTriggerId(r.TriggerId, s, timeout)
|
||||
}
|
||||
|
||||
func (r *OpenDialogRequest) IsValid() error {
|
||||
var multiErr *multierror.Error
|
||||
if r.URL == "" {
|
||||
multiErr = multierror.Append(multiErr, errors.New("empty URL"))
|
||||
}
|
||||
|
||||
if r.TriggerId == "" {
|
||||
multiErr = multierror.Append(multiErr, errors.New("empty trigger id"))
|
||||
}
|
||||
|
||||
err := r.Dialog.IsValid()
|
||||
if err != nil {
|
||||
multiErr = multierror.Append(multiErr, err)
|
||||
}
|
||||
|
||||
return multiErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (d *Dialog) IsValid() error {
|
||||
var multiErr *multierror.Error
|
||||
|
||||
if d.Title == "" || len(d.Title) > DialogTitleMaxLength {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("invalid dialog title %q", d.Title))
|
||||
}
|
||||
|
||||
if d.IconURL != "" && !IsValidHTTPURL(d.IconURL) {
|
||||
multiErr = multierror.Append(multiErr, errors.New("invalid icon url"))
|
||||
}
|
||||
|
||||
if len(d.Elements) != 0 {
|
||||
elementMap := make(map[string]bool)
|
||||
|
||||
for _, element := range d.Elements {
|
||||
if elementMap[element.Name] {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("duplicate dialog element %q", element.Name))
|
||||
}
|
||||
elementMap[element.Name] = true
|
||||
|
||||
err := element.IsValid()
|
||||
if err != nil {
|
||||
multiErr = multierror.Append(multiErr, errors.Wrapf(err, "%q field is not valid", element.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return multiErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (e *DialogElement) IsValid() error {
|
||||
var multiErr *multierror.Error
|
||||
textSubTypes := map[string]bool{
|
||||
"": true,
|
||||
"text": true,
|
||||
"email": true,
|
||||
"number": true,
|
||||
"tel": true,
|
||||
"url": true,
|
||||
"password": true,
|
||||
}
|
||||
|
||||
if e.MinLength < 0 {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("min length cannot be a negative number, got %d", e.MinLength))
|
||||
}
|
||||
if e.MinLength > e.MaxLength {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("min length should be less then max length, got %d > %d", e.MinLength, e.MaxLength))
|
||||
}
|
||||
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("DisplayName", e.DisplayName, DialogElementDisplayNameMaxLength))
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Name", e.Name, DialogElementNameMaxLength))
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("HelpText", e.HelpText, DialogElementHelpTextMaxLength))
|
||||
|
||||
switch e.Type {
|
||||
case "text":
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Default", e.Default, DialogElementTextMaxLength))
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Placeholder", e.Placeholder, DialogElementTextMaxLength))
|
||||
if _, ok := textSubTypes[e.SubType]; !ok {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("invalid subtype %q", e.Type))
|
||||
}
|
||||
|
||||
case "textarea":
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Default", e.Default, DialogElementTextareaMaxLength))
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Placeholder", e.Placeholder, DialogElementTextareaMaxLength))
|
||||
|
||||
if _, ok := textSubTypes[e.SubType]; !ok {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("invalid subtype %q", e.Type))
|
||||
}
|
||||
|
||||
case "select":
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Default", e.Default, DialogElementSelectMaxLength))
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Placeholder", e.Placeholder, DialogElementSelectMaxLength))
|
||||
if e.DataSource != "" && e.DataSource != "users" && e.DataSource != "channels" {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("invalid data source %q, allowed are 'users' or 'channels'", e.DataSource))
|
||||
}
|
||||
if e.DataSource == "" && !isDefaultInOptions(e.Default, e.Options) {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("default value %q doesn't exist in options ", e.Default))
|
||||
}
|
||||
|
||||
case "bool":
|
||||
if e.Default != "" && e.Default != "true" && e.Default != "false" {
|
||||
multiErr = multierror.Append(multiErr, errors.New("invalid default of bool"))
|
||||
}
|
||||
multiErr = multierror.Append(multiErr, checkMaxLength("Placeholder", e.Placeholder, DialogElementBoolMaxLength))
|
||||
|
||||
case "radio":
|
||||
if !isDefaultInOptions(e.Default, e.Options) {
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("default value %q doesn't exist in options ", e.Default))
|
||||
}
|
||||
|
||||
default:
|
||||
multiErr = multierror.Append(multiErr, errors.Errorf("invalid element type: %q", e.Type))
|
||||
}
|
||||
|
||||
return multiErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
func isDefaultInOptions(defaultValue string, options []*PostActionOptions) bool {
|
||||
if defaultValue == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
if defaultValue == option.Value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkMaxLength(fieldName string, field string, length int) error {
|
||||
var valid bool
|
||||
// DisplayName and Name are required fields
|
||||
if fieldName == "DisplayName" || fieldName == "Name" {
|
||||
valid = len(field) > 0 && len(field) > length
|
||||
} else {
|
||||
valid = len(field) > length
|
||||
}
|
||||
if valid {
|
||||
return errors.Errorf("%v cannot be longer than %d characters", fieldName, length)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Post) StripActionIntegrations() {
|
||||
attachments := o.Attachments()
|
||||
if o.GetProp("attachments") != nil {
|
||||
o.AddProp("attachments", attachments)
|
||||
}
|
||||
for _, attachment := range attachments {
|
||||
for _, action := range attachment.Actions {
|
||||
action.Integration = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Post) GetAction(id string) *PostAction {
|
||||
for _, attachment := range o.Attachments() {
|
||||
for _, action := range attachment.Actions {
|
||||
if action != nil && action.Id == id {
|
||||
return action
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Post) GenerateActionIds() {
|
||||
if o.GetProp("attachments") != nil {
|
||||
o.AddProp("attachments", o.Attachments())
|
||||
}
|
||||
if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok {
|
||||
for _, attachment := range attachments {
|
||||
for _, action := range attachment.Actions {
|
||||
if action != nil && action.Id == "" {
|
||||
action.Id = NewId()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AddPostActionCookies(o *Post, secret []byte) *Post {
|
||||
p := o.Clone()
|
||||
|
||||
// retainedProps carry over their value from the old post, including no value
|
||||
retainProps := map[string]any{}
|
||||
removeProps := []string{}
|
||||
for _, key := range PostActionRetainPropKeys {
|
||||
value, ok := p.GetProps()[key]
|
||||
if ok {
|
||||
retainProps[key] = value
|
||||
} else {
|
||||
removeProps = append(removeProps, key)
|
||||
}
|
||||
}
|
||||
|
||||
attachments := p.Attachments()
|
||||
for _, attachment := range attachments {
|
||||
for _, action := range attachment.Actions {
|
||||
c := &PostActionCookie{
|
||||
Type: action.Type,
|
||||
ChannelId: p.ChannelId,
|
||||
DataSource: action.DataSource,
|
||||
Integration: action.Integration,
|
||||
RetainProps: retainProps,
|
||||
RemoveProps: removeProps,
|
||||
}
|
||||
|
||||
c.PostId = p.Id
|
||||
if p.RootId == "" {
|
||||
c.RootPostId = p.Id
|
||||
} else {
|
||||
c.RootPostId = p.RootId
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(c)
|
||||
action.Cookie, _ = encryptPostActionCookie(string(b), secret)
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func encryptPostActionCookie(plain string, secret []byte) (string, error) {
|
||||
if len(secret) == 0 {
|
||||
return plain, nil
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nonce := make([]byte, aesgcm.NonceSize())
|
||||
_, err = io.ReadFull(rand.Reader, nonce)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sealed := aesgcm.Seal(nil, nonce, []byte(plain), nil)
|
||||
|
||||
combined := append(nonce, sealed...) //nolint:makezero
|
||||
encoded := make([]byte, base64.StdEncoding.EncodedLen(len(combined)))
|
||||
base64.StdEncoding.Encode(encoded, combined)
|
||||
|
||||
return string(encoded), nil
|
||||
}
|
||||
|
||||
func DecryptPostActionCookie(encoded string, secret []byte) (string, error) {
|
||||
if len(secret) == 0 {
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(encoded)))
|
||||
n, err := base64.StdEncoding.Decode(decoded, []byte(encoded))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
decoded = decoded[:n]
|
||||
|
||||
nonceSize := aesgcm.NonceSize()
|
||||
if len(decoded) < nonceSize {
|
||||
return "", fmt.Errorf("cookie too short")
|
||||
}
|
||||
|
||||
nonce, decoded := decoded[:nonceSize], decoded[nonceSize:]
|
||||
plain, err := aesgcm.Open(nil, nonce, decoded, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(plain), nil
|
||||
}
|
||||
58
vendor/github.com/mattermost/mattermost/server/public/model/integrity.go
generated
vendored
Normal file
58
vendor/github.com/mattermost/mattermost/server/public/model/integrity.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type OrphanedRecord struct {
|
||||
ParentId *string `json:"parent_id"`
|
||||
ChildId *string `json:"child_id"`
|
||||
}
|
||||
|
||||
type RelationalIntegrityCheckData struct {
|
||||
ParentName string `json:"parent_name"`
|
||||
ChildName string `json:"child_name"`
|
||||
ParentIdAttr string `json:"parent_id_attr"`
|
||||
ChildIdAttr string `json:"child_id_attr"`
|
||||
Records []OrphanedRecord `json:"records"`
|
||||
}
|
||||
|
||||
type IntegrityCheckResult struct {
|
||||
Data any `json:"data"`
|
||||
Err error `json:"err"`
|
||||
}
|
||||
|
||||
func (r *IntegrityCheckResult) UnmarshalJSON(b []byte) error {
|
||||
var data map[string]any
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
if d, ok := data["data"]; ok && d != nil {
|
||||
var rdata RelationalIntegrityCheckData
|
||||
m := d.(map[string]any)
|
||||
rdata.ParentName = m["parent_name"].(string)
|
||||
rdata.ChildName = m["child_name"].(string)
|
||||
rdata.ParentIdAttr = m["parent_id_attr"].(string)
|
||||
rdata.ChildIdAttr = m["child_id_attr"].(string)
|
||||
for _, recData := range m["records"].([]any) {
|
||||
var record OrphanedRecord
|
||||
m := recData.(map[string]any)
|
||||
if val := m["parent_id"]; val != nil {
|
||||
record.ParentId = NewString(val.(string))
|
||||
}
|
||||
if val := m["child_id"]; val != nil {
|
||||
record.ChildId = NewString(val.(string))
|
||||
}
|
||||
rdata.Records = append(rdata.Records, record)
|
||||
}
|
||||
r.Data = rdata
|
||||
}
|
||||
if err, ok := data["err"]; ok && err != nil {
|
||||
r.Err = errors.New(data["err"].(string))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
20
vendor/github.com/mattermost/mattermost/server/public/model/ip_filtering.go
generated
vendored
Normal file
20
vendor/github.com/mattermost/mattermost/server/public/model/ip_filtering.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package model
|
||||
|
||||
type AllowedIPRanges []AllowedIPRange
|
||||
|
||||
type AllowedIPRange struct {
|
||||
CIDRBlock string `json:"cidr_block"`
|
||||
Description string `json:"description"`
|
||||
Enabled bool `json:"enabled"`
|
||||
OwnerID string `json:"owner_id"`
|
||||
}
|
||||
|
||||
func (air *AllowedIPRanges) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"AllowedIPRanges": air,
|
||||
}
|
||||
}
|
||||
|
||||
type GetIPAddressResponse struct {
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
135
vendor/github.com/mattermost/mattermost/server/public/model/job.go
generated
vendored
Normal file
135
vendor/github.com/mattermost/mattermost/server/public/model/job.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
JobTypeDataRetention = "data_retention"
|
||||
JobTypeMessageExport = "message_export"
|
||||
JobTypeElasticsearchPostIndexing = "elasticsearch_post_indexing"
|
||||
JobTypeElasticsearchPostAggregation = "elasticsearch_post_aggregation"
|
||||
JobTypeBlevePostIndexing = "bleve_post_indexing"
|
||||
JobTypeLdapSync = "ldap_sync"
|
||||
JobTypeMigrations = "migrations"
|
||||
JobTypePlugins = "plugins"
|
||||
JobTypeExpiryNotify = "expiry_notify"
|
||||
JobTypeProductNotices = "product_notices"
|
||||
JobTypeActiveUsers = "active_users"
|
||||
JobTypeImportProcess = "import_process"
|
||||
JobTypeImportDelete = "import_delete"
|
||||
JobTypeExportProcess = "export_process"
|
||||
JobTypeExportDelete = "export_delete"
|
||||
JobTypeCloud = "cloud"
|
||||
JobTypeResendInvitationEmail = "resend_invitation_email"
|
||||
JobTypeExtractContent = "extract_content"
|
||||
JobTypeLastAccessiblePost = "last_accessible_post"
|
||||
JobTypeLastAccessibleFile = "last_accessible_file"
|
||||
JobTypeUpgradeNotifyAdmin = "upgrade_notify_admin"
|
||||
JobTypeTrialNotifyAdmin = "trial_notify_admin"
|
||||
JobTypePostPersistentNotifications = "post_persistent_notifications"
|
||||
JobTypeInstallPluginNotifyAdmin = "install_plugin_notify_admin"
|
||||
JobTypeHostedPurchaseScreening = "hosted_purchase_screening"
|
||||
JobTypeS3PathMigration = "s3_path_migration"
|
||||
JobTypeCleanupDesktopTokens = "cleanup_desktop_tokens"
|
||||
JobTypeDeleteEmptyDraftsMigration = "delete_empty_drafts_migration"
|
||||
JobTypeRefreshPostStats = "refresh_post_stats"
|
||||
JobTypeDeleteOrphanDraftsMigration = "delete_orphan_drafts_migration"
|
||||
JobTypeExportUsersToCSV = "export_users_to_csv"
|
||||
|
||||
JobStatusPending = "pending"
|
||||
JobStatusInProgress = "in_progress"
|
||||
JobStatusSuccess = "success"
|
||||
JobStatusError = "error"
|
||||
JobStatusCancelRequested = "cancel_requested"
|
||||
JobStatusCanceled = "canceled"
|
||||
JobStatusWarning = "warning"
|
||||
)
|
||||
|
||||
var AllJobTypes = [...]string{
|
||||
JobTypeDataRetention,
|
||||
JobTypeMessageExport,
|
||||
JobTypeElasticsearchPostIndexing,
|
||||
JobTypeElasticsearchPostAggregation,
|
||||
JobTypeBlevePostIndexing,
|
||||
JobTypeLdapSync,
|
||||
JobTypeMigrations,
|
||||
JobTypePlugins,
|
||||
JobTypeExpiryNotify,
|
||||
JobTypeProductNotices,
|
||||
JobTypeActiveUsers,
|
||||
JobTypeImportProcess,
|
||||
JobTypeImportDelete,
|
||||
JobTypeExportProcess,
|
||||
JobTypeExportDelete,
|
||||
JobTypeCloud,
|
||||
JobTypeExtractContent,
|
||||
JobTypeLastAccessiblePost,
|
||||
JobTypeLastAccessibleFile,
|
||||
JobTypeCleanupDesktopTokens,
|
||||
JobTypeRefreshPostStats,
|
||||
}
|
||||
|
||||
type Job struct {
|
||||
Id string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Priority int64 `json:"priority"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
StartAt int64 `json:"start_at"`
|
||||
LastActivityAt int64 `json:"last_activity_at"`
|
||||
Status string `json:"status"`
|
||||
Progress int64 `json:"progress"`
|
||||
Data StringMap `json:"data"`
|
||||
}
|
||||
|
||||
func (j *Job) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": j.Id,
|
||||
"type": j.Type,
|
||||
"priority": j.Priority,
|
||||
"create_at": j.CreateAt,
|
||||
"start_at": j.StartAt,
|
||||
"last_activity_at": j.LastActivityAt,
|
||||
"status": j.Status,
|
||||
"progress": j.Progress,
|
||||
"data": j.Data, // TODO do we want this here
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Job) IsValid() *AppError {
|
||||
if !IsValidId(j.Id) {
|
||||
return NewAppError("Job.IsValid", "model.job.is_valid.id.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if j.CreateAt == 0 {
|
||||
return NewAppError("Job.IsValid", "model.job.is_valid.create_at.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
switch j.Status {
|
||||
case JobStatusPending,
|
||||
JobStatusInProgress,
|
||||
JobStatusSuccess,
|
||||
JobStatusError,
|
||||
JobStatusWarning,
|
||||
JobStatusCancelRequested,
|
||||
JobStatusCanceled:
|
||||
default:
|
||||
return NewAppError("Job.IsValid", "model.job.is_valid.status.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *Job) LogClone() any {
|
||||
return j.Auditable()
|
||||
}
|
||||
|
||||
type Worker interface {
|
||||
Run()
|
||||
Stop()
|
||||
JobChannel() chan<- Job
|
||||
IsEnabled(cfg *Config) bool
|
||||
}
|
||||
10
vendor/github.com/mattermost/mattermost/server/public/model/ldap.go
generated
vendored
Normal file
10
vendor/github.com/mattermost/mattermost/server/public/model/ldap.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
UserAuthServiceLdap = "ldap"
|
||||
LdapPublicCertificateName = "ldap-public.crt"
|
||||
LdapPrivateKeyName = "ldap-private.key"
|
||||
)
|
||||
455
vendor/github.com/mattermost/mattermost/server/public/model/license.go
generated
vendored
Normal file
455
vendor/github.com/mattermost/mattermost/server/public/model/license.go
generated
vendored
Normal file
@@ -0,0 +1,455 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DayInSeconds = 24 * 60 * 60
|
||||
DayInMilliseconds = DayInSeconds * 1000
|
||||
|
||||
ExpiredLicenseError = "api.license.add_license.expired.app_error"
|
||||
InvalidLicenseError = "api.license.add_license.invalid.app_error"
|
||||
LicenseGracePeriod = DayInMilliseconds * 10 //10 days
|
||||
LicenseRenewalLink = "https://mattermost.com/renew/"
|
||||
|
||||
LicenseShortSkuE10 = "E10"
|
||||
LicenseShortSkuE20 = "E20"
|
||||
LicenseShortSkuProfessional = "professional"
|
||||
LicenseShortSkuEnterprise = "enterprise"
|
||||
)
|
||||
|
||||
const (
|
||||
LicenseUpForRenewalEmailSent = "LicenseUpForRenewalEmailSent"
|
||||
)
|
||||
|
||||
var (
|
||||
trialDuration = 30*(time.Hour*24) + (time.Hour * 8) // 720 hours (30 days) + 8 hours is trial license duration
|
||||
adminTrialDuration = 30*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 720 hours (30 days) + 23 hours, 59 mins and 59 seconds
|
||||
|
||||
// a sanctioned trial's duration is either more than the upper bound,
|
||||
// or less than the lower bound
|
||||
sanctionedTrialDurationLowerBound = 31*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 744 hours (31 days) + 23 hours, 59 mins and 59 seconds
|
||||
sanctionedTrialDurationUpperBound = 29*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 696 hours (29 days) + 23 hours, 59 mins and 59 seconds
|
||||
)
|
||||
|
||||
type LicenseRecord struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
Bytes string `json:"-"`
|
||||
}
|
||||
|
||||
type License struct {
|
||||
Id string `json:"id"`
|
||||
IssuedAt int64 `json:"issued_at"`
|
||||
StartsAt int64 `json:"starts_at"`
|
||||
ExpiresAt int64 `json:"expires_at"`
|
||||
Customer *Customer `json:"customer"`
|
||||
Features *Features `json:"features"`
|
||||
SkuName string `json:"sku_name"`
|
||||
SkuShortName string `json:"sku_short_name"`
|
||||
IsTrial bool `json:"is_trial"`
|
||||
IsGovSku bool `json:"is_gov_sku"`
|
||||
SignupJWT *string `json:"signup_jwt"`
|
||||
}
|
||||
|
||||
type Customer struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Company string `json:"company"`
|
||||
}
|
||||
|
||||
type TrialLicenseRequest struct {
|
||||
ServerID string `json:"server_id"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
SiteURL string `json:"site_url"`
|
||||
SiteName string `json:"site_name"`
|
||||
Users int `json:"users"`
|
||||
TermsAccepted bool `json:"terms_accepted"`
|
||||
ReceiveEmailsAccepted bool `json:"receive_emails_accepted"`
|
||||
ContactName string `json:"contact_name"`
|
||||
ContactEmail string `json:"contact_email"`
|
||||
CompanyName string `json:"company_name"`
|
||||
CompanyCountry string `json:"company_country"`
|
||||
CompanySize string `json:"company_size"`
|
||||
}
|
||||
|
||||
// If any of the below fields are set, this is not a legacy request, and all fields should be validated
|
||||
func (tlr *TrialLicenseRequest) IsLegacy() bool {
|
||||
return tlr.CompanyCountry == "" && tlr.CompanyName == "" && tlr.CompanySize == "" && tlr.ContactName == ""
|
||||
}
|
||||
|
||||
func (tlr *TrialLicenseRequest) IsValid() bool {
|
||||
if !tlr.TermsAccepted {
|
||||
return false
|
||||
}
|
||||
|
||||
if tlr.Email == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if tlr.Users <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if tlr.CompanyCountry == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if tlr.CompanyName == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if tlr.CompanySize == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if tlr.ContactName == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type Features struct {
|
||||
Users *int `json:"users"`
|
||||
LDAP *bool `json:"ldap"`
|
||||
LDAPGroups *bool `json:"ldap_groups"`
|
||||
MFA *bool `json:"mfa"`
|
||||
GoogleOAuth *bool `json:"google_oauth"`
|
||||
Office365OAuth *bool `json:"office365_oauth"`
|
||||
OpenId *bool `json:"openid"`
|
||||
Compliance *bool `json:"compliance"`
|
||||
Cluster *bool `json:"cluster"`
|
||||
Metrics *bool `json:"metrics"`
|
||||
MHPNS *bool `json:"mhpns"`
|
||||
SAML *bool `json:"saml"`
|
||||
Elasticsearch *bool `json:"elastic_search"`
|
||||
Announcement *bool `json:"announcement"`
|
||||
ThemeManagement *bool `json:"theme_management"`
|
||||
EmailNotificationContents *bool `json:"email_notification_contents"`
|
||||
DataRetention *bool `json:"data_retention"`
|
||||
MessageExport *bool `json:"message_export"`
|
||||
CustomPermissionsSchemes *bool `json:"custom_permissions_schemes"`
|
||||
CustomTermsOfService *bool `json:"custom_terms_of_service"`
|
||||
GuestAccounts *bool `json:"guest_accounts"`
|
||||
GuestAccountsPermissions *bool `json:"guest_accounts_permissions"`
|
||||
IDLoadedPushNotifications *bool `json:"id_loaded"`
|
||||
LockTeammateNameDisplay *bool `json:"lock_teammate_name_display"`
|
||||
EnterprisePlugins *bool `json:"enterprise_plugins"`
|
||||
AdvancedLogging *bool `json:"advanced_logging"`
|
||||
Cloud *bool `json:"cloud"`
|
||||
SharedChannels *bool `json:"shared_channels"`
|
||||
RemoteClusterService *bool `json:"remote_cluster_service"`
|
||||
OutgoingOAuthConnections *bool `json:"outgoing_oauth_connections"`
|
||||
|
||||
// after we enabled more features we'll need to control them with this
|
||||
FutureFeatures *bool `json:"future_features"`
|
||||
}
|
||||
|
||||
func (f *Features) ToMap() map[string]any {
|
||||
return map[string]any{
|
||||
"ldap": *f.LDAP,
|
||||
"ldap_groups": *f.LDAPGroups,
|
||||
"mfa": *f.MFA,
|
||||
"google": *f.GoogleOAuth,
|
||||
"office365": *f.Office365OAuth,
|
||||
"openid": *f.OpenId,
|
||||
"compliance": *f.Compliance,
|
||||
"cluster": *f.Cluster,
|
||||
"metrics": *f.Metrics,
|
||||
"mhpns": *f.MHPNS,
|
||||
"saml": *f.SAML,
|
||||
"elastic_search": *f.Elasticsearch,
|
||||
"email_notification_contents": *f.EmailNotificationContents,
|
||||
"data_retention": *f.DataRetention,
|
||||
"message_export": *f.MessageExport,
|
||||
"custom_permissions_schemes": *f.CustomPermissionsSchemes,
|
||||
"guest_accounts": *f.GuestAccounts,
|
||||
"guest_accounts_permissions": *f.GuestAccountsPermissions,
|
||||
"id_loaded": *f.IDLoadedPushNotifications,
|
||||
"lock_teammate_name_display": *f.LockTeammateNameDisplay,
|
||||
"enterprise_plugins": *f.EnterprisePlugins,
|
||||
"advanced_logging": *f.AdvancedLogging,
|
||||
"cloud": *f.Cloud,
|
||||
"shared_channels": *f.SharedChannels,
|
||||
"remote_cluster_service": *f.RemoteClusterService,
|
||||
"future": *f.FutureFeatures,
|
||||
"outgoing_oauth_connections": *f.OutgoingOAuthConnections,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Features) SetDefaults() {
|
||||
if f.FutureFeatures == nil {
|
||||
f.FutureFeatures = NewBool(true)
|
||||
}
|
||||
|
||||
if f.Users == nil {
|
||||
f.Users = NewInt(0)
|
||||
}
|
||||
|
||||
if f.LDAP == nil {
|
||||
f.LDAP = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.LDAPGroups == nil {
|
||||
f.LDAPGroups = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.MFA == nil {
|
||||
f.MFA = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.GoogleOAuth == nil {
|
||||
f.GoogleOAuth = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.Office365OAuth == nil {
|
||||
f.Office365OAuth = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.OpenId == nil {
|
||||
f.OpenId = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.Compliance == nil {
|
||||
f.Compliance = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.Cluster == nil {
|
||||
f.Cluster = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.Metrics == nil {
|
||||
f.Metrics = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.MHPNS == nil {
|
||||
f.MHPNS = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.SAML == nil {
|
||||
f.SAML = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.Elasticsearch == nil {
|
||||
f.Elasticsearch = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.Announcement == nil {
|
||||
f.Announcement = NewBool(true)
|
||||
}
|
||||
|
||||
if f.ThemeManagement == nil {
|
||||
f.ThemeManagement = NewBool(true)
|
||||
}
|
||||
|
||||
if f.EmailNotificationContents == nil {
|
||||
f.EmailNotificationContents = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.DataRetention == nil {
|
||||
f.DataRetention = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.MessageExport == nil {
|
||||
f.MessageExport = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.CustomPermissionsSchemes == nil {
|
||||
f.CustomPermissionsSchemes = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.GuestAccounts == nil {
|
||||
f.GuestAccounts = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.GuestAccountsPermissions == nil {
|
||||
f.GuestAccountsPermissions = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.CustomTermsOfService == nil {
|
||||
f.CustomTermsOfService = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.IDLoadedPushNotifications == nil {
|
||||
f.IDLoadedPushNotifications = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.LockTeammateNameDisplay == nil {
|
||||
f.LockTeammateNameDisplay = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.EnterprisePlugins == nil {
|
||||
f.EnterprisePlugins = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.AdvancedLogging == nil {
|
||||
f.AdvancedLogging = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.Cloud == nil {
|
||||
f.Cloud = NewBool(false)
|
||||
}
|
||||
|
||||
if f.SharedChannels == nil {
|
||||
f.SharedChannels = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.RemoteClusterService == nil {
|
||||
f.RemoteClusterService = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
|
||||
if f.OutgoingOAuthConnections == nil {
|
||||
f.OutgoingOAuthConnections = NewBool(*f.FutureFeatures)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *License) IsExpired() bool {
|
||||
return l.ExpiresAt < GetMillis()
|
||||
}
|
||||
|
||||
func (l *License) IsPastGracePeriod() bool {
|
||||
timeDiff := GetMillis() - l.ExpiresAt
|
||||
return timeDiff > LicenseGracePeriod
|
||||
}
|
||||
|
||||
func (l *License) IsWithinExpirationPeriod() bool {
|
||||
days := l.DaysToExpiration()
|
||||
return days <= 60 && days >= 58
|
||||
}
|
||||
|
||||
func (l *License) DaysToExpiration() int {
|
||||
dif := l.ExpiresAt - GetMillis()
|
||||
d, _ := time.ParseDuration(fmt.Sprint(dif) + "ms")
|
||||
days := d.Hours() / 24
|
||||
return int(days)
|
||||
}
|
||||
|
||||
func (l *License) IsStarted() bool {
|
||||
return l.StartsAt < GetMillis()
|
||||
}
|
||||
|
||||
func (l *License) IsCloud() bool {
|
||||
return l != nil && l.Features != nil && l.Features.Cloud != nil && *l.Features.Cloud
|
||||
}
|
||||
|
||||
func (l *License) IsTrialLicense() bool {
|
||||
return l.IsTrial || (l.ExpiresAt-l.StartsAt) == trialDuration.Milliseconds() || (l.ExpiresAt-l.StartsAt) == adminTrialDuration.Milliseconds()
|
||||
}
|
||||
|
||||
func (l *License) IsSanctionedTrial() bool {
|
||||
duration := l.ExpiresAt - l.StartsAt
|
||||
|
||||
return l.IsTrialLicense() &&
|
||||
(duration >= sanctionedTrialDurationLowerBound.Milliseconds() || duration <= sanctionedTrialDurationUpperBound.Milliseconds())
|
||||
}
|
||||
|
||||
func (l *License) HasEnterpriseMarketplacePlugins() bool {
|
||||
return *l.Features.EnterprisePlugins ||
|
||||
l.SkuShortName == LicenseShortSkuE20 ||
|
||||
l.SkuShortName == LicenseShortSkuProfessional ||
|
||||
l.SkuShortName == LicenseShortSkuEnterprise
|
||||
}
|
||||
|
||||
func (l *License) HasRemoteClusterService() bool {
|
||||
if l == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// If SharedChannels is enabled then RemoteClusterService must be enabled.
|
||||
if l.HasSharedChannels() {
|
||||
return true
|
||||
}
|
||||
|
||||
return (l.Features != nil && l.Features.RemoteClusterService != nil && *l.Features.RemoteClusterService) ||
|
||||
l.SkuShortName == LicenseShortSkuProfessional ||
|
||||
l.SkuShortName == LicenseShortSkuEnterprise
|
||||
}
|
||||
|
||||
func (l *License) HasSharedChannels() bool {
|
||||
if l == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return (l.Features != nil && l.Features.SharedChannels != nil && *l.Features.SharedChannels) ||
|
||||
l.SkuShortName == LicenseShortSkuProfessional ||
|
||||
l.SkuShortName == LicenseShortSkuEnterprise
|
||||
}
|
||||
|
||||
// NewTestLicense returns a license that expires in the future and has the given features.
|
||||
func NewTestLicense(features ...string) *License {
|
||||
ret := &License{
|
||||
ExpiresAt: GetMillis() + 90*DayInMilliseconds,
|
||||
Customer: &Customer{
|
||||
Id: "some ID",
|
||||
Email: "admin@example.com",
|
||||
Name: "Main Contact Person",
|
||||
Company: "My awesome Company",
|
||||
},
|
||||
Features: &Features{},
|
||||
}
|
||||
ret.Features.SetDefaults()
|
||||
|
||||
featureMap := map[string]bool{}
|
||||
for _, feature := range features {
|
||||
featureMap[feature] = true
|
||||
}
|
||||
featureJson, _ := json.Marshal(featureMap)
|
||||
json.Unmarshal(featureJson, &ret.Features)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// NewTestLicense returns a license that expires in the future and set as false the given features.
|
||||
func NewTestLicenseWithFalseDefaults(features ...string) *License {
|
||||
ret := &License{
|
||||
ExpiresAt: GetMillis() + 90*DayInMilliseconds,
|
||||
Customer: &Customer{},
|
||||
Features: &Features{},
|
||||
}
|
||||
ret.Features.SetDefaults()
|
||||
|
||||
featureMap := map[string]bool{}
|
||||
for _, feature := range features {
|
||||
featureMap[feature] = false
|
||||
}
|
||||
featureJson, _ := json.Marshal(featureMap)
|
||||
json.Unmarshal(featureJson, &ret.Features)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func NewTestLicenseSKU(skuShortName string, features ...string) *License {
|
||||
lic := NewTestLicense(features...)
|
||||
lic.SkuShortName = skuShortName
|
||||
return lic
|
||||
}
|
||||
|
||||
func (lr *LicenseRecord) IsValid() *AppError {
|
||||
if !IsValidId(lr.Id) {
|
||||
return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if lr.CreateAt == 0 {
|
||||
return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if lr.Bytes == "" || len(lr.Bytes) > 10000 {
|
||||
return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.bytes.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lr *LicenseRecord) PreSave() {
|
||||
lr.CreateAt = GetMillis()
|
||||
}
|
||||
10
vendor/github.com/mattermost/mattermost/server/public/model/limits.go
generated
vendored
Normal file
10
vendor/github.com/mattermost/mattermost/server/public/model/limits.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type ServerLimits struct {
|
||||
MaxUsersLimit int64 `json:"maxUsersLimit"` // soft limit for max number of users.
|
||||
MaxUsersHardLimit int64 `json:"maxUsersHardLimit"` // hard limit for max number of active users.
|
||||
ActiveUserCount int64 `json:"activeUserCount"` // actual number of active users on server. Active = non deleted
|
||||
}
|
||||
194
vendor/github.com/mattermost/mattermost/server/public/model/link_metadata.go
generated
vendored
Normal file
194
vendor/github.com/mattermost/mattermost/server/public/model/link_metadata.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net/http"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/dyatlov/go-opengraph/opengraph"
|
||||
"github.com/dyatlov/go-opengraph/opengraph/types/image"
|
||||
)
|
||||
|
||||
const (
|
||||
LinkMetadataTypeImage LinkMetadataType = "image"
|
||||
LinkMetadataTypeNone LinkMetadataType = "none"
|
||||
LinkMetadataTypeOpengraph LinkMetadataType = "opengraph"
|
||||
LinkMetadataMaxImages int = 5
|
||||
)
|
||||
|
||||
type LinkMetadataType string
|
||||
|
||||
// LinkMetadata stores arbitrary data about a link posted in a message. This includes dimensions of linked images
|
||||
// and OpenGraph metadata.
|
||||
type LinkMetadata struct {
|
||||
// Hash is a value computed from the URL and Timestamp for use as a primary key in the database.
|
||||
Hash int64
|
||||
|
||||
URL string
|
||||
Timestamp int64
|
||||
Type LinkMetadataType
|
||||
|
||||
// Data is the actual metadata for the link. It should contain data of one of the following types:
|
||||
// - *model.PostImage if the linked content is an image
|
||||
// - *opengraph.OpenGraph if the linked content is an HTML document
|
||||
// - nil if the linked content has no metadata
|
||||
Data any
|
||||
}
|
||||
|
||||
// truncateText ensure string is 300 chars, truncate and add ellipsis
|
||||
// if it was bigger.
|
||||
func truncateText(original string) string {
|
||||
if utf8.RuneCountInString(original) > 300 {
|
||||
return fmt.Sprintf("%.300s[...]", original)
|
||||
}
|
||||
return original
|
||||
}
|
||||
|
||||
func firstNImages(images []*image.Image, maxImages int) []*image.Image {
|
||||
if maxImages < 0 { // don't break stuff, if it's weird, go for sane defaults
|
||||
maxImages = LinkMetadataMaxImages
|
||||
}
|
||||
numImages := len(images)
|
||||
if numImages > maxImages {
|
||||
return images[0:maxImages]
|
||||
}
|
||||
return images
|
||||
}
|
||||
|
||||
// TruncateOpenGraph ensure OpenGraph metadata doesn't grow too big by
|
||||
// shortening strings, trimming fields and reducing the number of
|
||||
// images.
|
||||
func TruncateOpenGraph(ogdata *opengraph.OpenGraph) *opengraph.OpenGraph {
|
||||
if ogdata != nil {
|
||||
empty := &opengraph.OpenGraph{}
|
||||
ogdata.Title = truncateText(ogdata.Title)
|
||||
ogdata.Description = truncateText(ogdata.Description)
|
||||
ogdata.SiteName = truncateText(ogdata.SiteName)
|
||||
ogdata.Article = empty.Article
|
||||
ogdata.Book = empty.Book
|
||||
ogdata.Profile = empty.Profile
|
||||
ogdata.Determiner = empty.Determiner
|
||||
ogdata.Locale = empty.Locale
|
||||
ogdata.LocalesAlternate = empty.LocalesAlternate
|
||||
ogdata.Images = firstNImages(ogdata.Images, LinkMetadataMaxImages)
|
||||
ogdata.Audios = empty.Audios
|
||||
ogdata.Videos = empty.Videos
|
||||
}
|
||||
return ogdata
|
||||
}
|
||||
|
||||
func (o *LinkMetadata) PreSave() {
|
||||
o.Hash = GenerateLinkMetadataHash(o.URL, o.Timestamp)
|
||||
}
|
||||
|
||||
func (o *LinkMetadata) IsValid() *AppError {
|
||||
if o.URL == "" {
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.url.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.Timestamp == 0 || !isRoundedToNearestHour(o.Timestamp) {
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.timestamp.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
switch o.Type {
|
||||
case LinkMetadataTypeImage:
|
||||
if o.Data == nil {
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if _, ok := o.Data.(*PostImage); !ok {
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data_type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
case LinkMetadataTypeNone:
|
||||
if o.Data != nil {
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data_type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
case LinkMetadataTypeOpengraph:
|
||||
if o.Data == nil {
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if _, ok := o.Data.(*opengraph.OpenGraph); !ok {
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data_type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
default:
|
||||
return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeserializeDataToConcreteType converts o.Data from JSON into properly structured data. This is intended to be used
|
||||
// after getting a LinkMetadata object that has been stored in the database.
|
||||
func (o *LinkMetadata) DeserializeDataToConcreteType() error {
|
||||
var b []byte
|
||||
switch t := o.Data.(type) {
|
||||
case []byte:
|
||||
// MySQL uses a byte slice for JSON
|
||||
b = t
|
||||
case string:
|
||||
// Postgres uses a string for JSON
|
||||
b = []byte(t)
|
||||
}
|
||||
|
||||
if b == nil {
|
||||
// Data doesn't need to be fixed
|
||||
return nil
|
||||
}
|
||||
|
||||
var data any
|
||||
var err error
|
||||
|
||||
switch o.Type {
|
||||
case LinkMetadataTypeImage:
|
||||
image := &PostImage{}
|
||||
|
||||
err = json.Unmarshal(b, &image)
|
||||
|
||||
data = image
|
||||
case LinkMetadataTypeOpengraph:
|
||||
og := &opengraph.OpenGraph{}
|
||||
|
||||
json.Unmarshal(b, &og)
|
||||
|
||||
data = og
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Data = data
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FloorToNearestHour takes a timestamp (in milliseconds) and returns it rounded to the previous hour in UTC.
|
||||
func FloorToNearestHour(ms int64) int64 {
|
||||
t := time.Unix(0, ms*int64(1000*1000)).UTC()
|
||||
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, time.UTC).UnixNano() / int64(time.Millisecond)
|
||||
}
|
||||
|
||||
// isRoundedToNearestHour returns true if the given timestamp (in milliseconds) has been rounded to the nearest hour in UTC.
|
||||
func isRoundedToNearestHour(ms int64) bool {
|
||||
return FloorToNearestHour(ms) == ms
|
||||
}
|
||||
|
||||
// GenerateLinkMetadataHash generates a unique hash for a given URL and timestamp for use as a database key.
|
||||
func GenerateLinkMetadataHash(url string, timestamp int64) int64 {
|
||||
hash := fnv.New32()
|
||||
|
||||
// Note that we ignore write errors here because the Hash interface says that its Write will never return an error
|
||||
binary.Write(hash, binary.LittleEndian, timestamp)
|
||||
hash.Write([]byte(url))
|
||||
|
||||
return int64(hash.Sum32())
|
||||
}
|
||||
444
vendor/github.com/mattermost/mattermost/server/public/model/manifest.go
generated
vendored
Normal file
444
vendor/github.com/mattermost/mattermost/server/public/model/manifest.go
generated
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type PluginOption struct {
|
||||
// The display name for the option.
|
||||
DisplayName string `json:"display_name" yaml:"display_name"`
|
||||
|
||||
// The string value for the option.
|
||||
Value string `json:"value" yaml:"value"`
|
||||
}
|
||||
|
||||
type PluginSettingType int
|
||||
|
||||
const (
|
||||
Bool PluginSettingType = iota
|
||||
Dropdown
|
||||
Generated
|
||||
Radio
|
||||
Text
|
||||
LongText
|
||||
Number
|
||||
Username
|
||||
Custom
|
||||
)
|
||||
|
||||
type PluginSetting struct {
|
||||
// The key that the setting will be assigned to in the configuration file.
|
||||
Key string `json:"key" yaml:"key"`
|
||||
|
||||
// The display name for the setting.
|
||||
DisplayName string `json:"display_name" yaml:"display_name"`
|
||||
|
||||
// The type of the setting.
|
||||
//
|
||||
// "bool" will result in a boolean true or false setting.
|
||||
//
|
||||
// "dropdown" will result in a string setting that allows the user to select from a list of
|
||||
// pre-defined options.
|
||||
//
|
||||
// "generated" will result in a string setting that is set to a random, cryptographically secure
|
||||
// string.
|
||||
//
|
||||
// "radio" will result in a string setting that allows the user to select from a short selection
|
||||
// of pre-defined options.
|
||||
//
|
||||
// "text" will result in a string setting that can be typed in manually.
|
||||
//
|
||||
// "longtext" will result in a multi line string that can be typed in manually.
|
||||
//
|
||||
// "number" will result in integer setting that can be typed in manually.
|
||||
//
|
||||
// "username" will result in a text setting that will autocomplete to a username.
|
||||
//
|
||||
// "custom" will result in a custom defined setting and will load the custom component registered for the Web App System Console.
|
||||
Type string `json:"type" yaml:"type"`
|
||||
|
||||
// The help text to display to the user. Supports Markdown formatting.
|
||||
HelpText string `json:"help_text" yaml:"help_text"`
|
||||
|
||||
// The help text to display alongside the "Regenerate" button for settings of the "generated" type.
|
||||
RegenerateHelpText string `json:"regenerate_help_text,omitempty" yaml:"regenerate_help_text,omitempty"`
|
||||
|
||||
// The placeholder to display for "generated", "text", "longtext", "number" and "username" types when blank.
|
||||
Placeholder string `json:"placeholder" yaml:"placeholder"`
|
||||
|
||||
// The default value of the setting.
|
||||
Default any `json:"default" yaml:"default"`
|
||||
|
||||
// For "radio" or "dropdown" settings, this is the list of pre-defined options that the user can choose
|
||||
// from.
|
||||
Options []*PluginOption `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
|
||||
// The intended hosting environment for this plugin setting. Can be "cloud" or "on-prem". When this field is set,
|
||||
// and the opposite environment is running the plugin, the setting will be hidden in the admin console UI.
|
||||
// Note that this functionality is entirely client-side, so the plugin needs to handle the case of invalid submissions.
|
||||
Hosting string `json:"hosting"`
|
||||
}
|
||||
|
||||
type PluginSettingsSchema struct {
|
||||
// Optional text to display above the settings. Supports Markdown formatting.
|
||||
Header string `json:"header" yaml:"header"`
|
||||
|
||||
// Optional text to display below the settings. Supports Markdown formatting.
|
||||
Footer string `json:"footer" yaml:"footer"`
|
||||
|
||||
// A list of setting definitions.
|
||||
Settings []*PluginSetting `json:"settings" yaml:"settings"`
|
||||
}
|
||||
|
||||
// The plugin manifest defines the metadata required to load and present your plugin. The manifest
|
||||
// file should be named plugin.json or plugin.yaml and placed in the top of your
|
||||
// plugin bundle.
|
||||
//
|
||||
// Example plugin.json:
|
||||
//
|
||||
// {
|
||||
// "id": "com.mycompany.myplugin",
|
||||
// "name": "My Plugin",
|
||||
// "description": "This is my plugin",
|
||||
// "homepage_url": "https://example.com",
|
||||
// "support_url": "https://example.com/support",
|
||||
// "release_notes_url": "https://example.com/releases/v0.0.1",
|
||||
// "icon_path": "assets/logo.svg",
|
||||
// "version": "0.1.0",
|
||||
// "min_server_version": "5.6.0",
|
||||
// "server": {
|
||||
// "executables": {
|
||||
// "linux-amd64": "server/dist/plugin-linux-amd64",
|
||||
// "darwin-amd64": "server/dist/plugin-darwin-amd64",
|
||||
// "windows-amd64": "server/dist/plugin-windows-amd64.exe"
|
||||
// }
|
||||
// },
|
||||
// "webapp": {
|
||||
// "bundle_path": "webapp/dist/main.js"
|
||||
// },
|
||||
// "settings_schema": {
|
||||
// "header": "Some header text",
|
||||
// "footer": "Some footer text",
|
||||
// "settings": [{
|
||||
// "key": "someKey",
|
||||
// "display_name": "Enable Extra Feature",
|
||||
// "type": "bool",
|
||||
// "help_text": "When true, an extra feature will be enabled!",
|
||||
// "default": "false"
|
||||
// }]
|
||||
// },
|
||||
// "props": {
|
||||
// "someKey": "someData"
|
||||
// }
|
||||
// }
|
||||
type Manifest struct {
|
||||
// The id is a globally unique identifier that represents your plugin. Ids must be at least
|
||||
// 3 characters, at most 190 characters and must match ^[a-zA-Z0-9-_\.]+$.
|
||||
// Reverse-DNS notation using a name you control is a good option, e.g. "com.mycompany.myplugin".
|
||||
Id string `json:"id" yaml:"id"`
|
||||
|
||||
// The name to be displayed for the plugin.
|
||||
Name string `json:"name" yaml:"name"`
|
||||
|
||||
// A description of what your plugin is and does.
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
|
||||
// HomepageURL is an optional link to learn more about the plugin.
|
||||
HomepageURL string `json:"homepage_url,omitempty" yaml:"homepage_url,omitempty"`
|
||||
|
||||
// SupportURL is an optional URL where plugin issues can be reported.
|
||||
SupportURL string `json:"support_url,omitempty" yaml:"support_url,omitempty"`
|
||||
|
||||
// ReleaseNotesURL is an optional URL where a changelog for the release can be found.
|
||||
ReleaseNotesURL string `json:"release_notes_url,omitempty" yaml:"release_notes_url,omitempty"`
|
||||
|
||||
// A relative file path in the bundle that points to the plugins svg icon for use with the Plugin Marketplace.
|
||||
// This should be relative to the root of your bundle and the location of the manifest file. Bitmap image formats are not supported.
|
||||
IconPath string `json:"icon_path,omitempty" yaml:"icon_path,omitempty"`
|
||||
|
||||
// A version number for your plugin. Semantic versioning is recommended: http://semver.org
|
||||
Version string `json:"version" yaml:"version"`
|
||||
|
||||
// The minimum Mattermost server version required for your plugin.
|
||||
//
|
||||
// Minimum server version: 5.6
|
||||
MinServerVersion string `json:"min_server_version,omitempty" yaml:"min_server_version,omitempty"`
|
||||
|
||||
// Server defines the server-side portion of your plugin.
|
||||
Server *ManifestServer `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
|
||||
// If your plugin extends the web app, you'll need to define webapp.
|
||||
Webapp *ManifestWebapp `json:"webapp,omitempty" yaml:"webapp,omitempty"`
|
||||
|
||||
// To allow administrators to configure your plugin via the Mattermost system console, you can
|
||||
// provide your settings schema.
|
||||
SettingsSchema *PluginSettingsSchema `json:"settings_schema,omitempty" yaml:"settings_schema,omitempty"`
|
||||
|
||||
// Plugins can store any kind of data in Props to allow other plugins to use it.
|
||||
Props map[string]any `json:"props,omitempty" yaml:"props,omitempty"`
|
||||
}
|
||||
|
||||
type ManifestServer struct {
|
||||
// Executables are the paths to your executable binaries, specifying multiple entry
|
||||
// points for different platforms when bundled together in a single plugin.
|
||||
Executables map[string]string `json:"executables,omitempty" yaml:"executables,omitempty"`
|
||||
|
||||
// Executable is the path to your executable binary. This should be relative to the root
|
||||
// of your bundle and the location of the manifest file.
|
||||
//
|
||||
// On Windows, this file must have a ".exe" extension.
|
||||
//
|
||||
// If your plugin is compiled for multiple platforms, consider bundling them together
|
||||
// and using the Executables field instead.
|
||||
Executable string `json:"executable" yaml:"executable"`
|
||||
}
|
||||
|
||||
type ManifestWebapp struct {
|
||||
// The path to your webapp bundle. This should be relative to the root of your bundle and the
|
||||
// location of the manifest file.
|
||||
BundlePath string `json:"bundle_path" yaml:"bundle_path"`
|
||||
|
||||
// BundleHash is the 64-bit FNV-1a hash of the webapp bundle, computed when the plugin is loaded
|
||||
BundleHash []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Manifest) HasClient() bool {
|
||||
return m.Webapp != nil
|
||||
}
|
||||
|
||||
func (m *Manifest) ClientManifest() *Manifest {
|
||||
cm := new(Manifest)
|
||||
*cm = *m
|
||||
cm.Name = ""
|
||||
cm.Description = ""
|
||||
cm.Server = nil
|
||||
if cm.Webapp != nil {
|
||||
cm.Webapp = new(ManifestWebapp)
|
||||
*cm.Webapp = *m.Webapp
|
||||
cm.Webapp.BundlePath = "/static/" + m.Id + "/" + fmt.Sprintf("%s_%x_bundle.js", m.Id, m.Webapp.BundleHash)
|
||||
}
|
||||
return cm
|
||||
}
|
||||
|
||||
// GetExecutableForRuntime returns the path to the executable for the given runtime architecture.
|
||||
//
|
||||
// If the manifest defines multiple executables, but none match, or if only a single executable
|
||||
// is defined, the Executable field will be returned. This method does not guarantee that the
|
||||
// resulting binary can actually execute on the given platform.
|
||||
func (m *Manifest) GetExecutableForRuntime(goOs, goArch string) string {
|
||||
server := m.Server
|
||||
|
||||
if server == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var executable string
|
||||
if len(server.Executables) > 0 {
|
||||
osArch := fmt.Sprintf("%s-%s", goOs, goArch)
|
||||
executable = server.Executables[osArch]
|
||||
}
|
||||
|
||||
if executable == "" {
|
||||
executable = server.Executable
|
||||
}
|
||||
|
||||
return executable
|
||||
}
|
||||
|
||||
func (m *Manifest) HasServer() bool {
|
||||
return m.Server != nil
|
||||
}
|
||||
|
||||
func (m *Manifest) HasWebapp() bool {
|
||||
return m.Webapp != nil
|
||||
}
|
||||
|
||||
func (m *Manifest) MeetMinServerVersion(serverVersion string) (bool, error) {
|
||||
minServerVersion, err := semver.Parse(m.MinServerVersion)
|
||||
if err != nil {
|
||||
return false, errors.New("failed to parse MinServerVersion")
|
||||
}
|
||||
sv := semver.MustParse(serverVersion)
|
||||
if sv.LT(minServerVersion) {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *Manifest) IsValid() error {
|
||||
if !IsValidPluginId(m.Id) {
|
||||
return errors.New("invalid plugin ID")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(m.Name) == "" {
|
||||
return errors.New("a plugin name is needed")
|
||||
}
|
||||
|
||||
if m.HomepageURL != "" && !IsValidHTTPURL(m.HomepageURL) {
|
||||
return errors.New("invalid HomepageURL")
|
||||
}
|
||||
|
||||
if m.SupportURL != "" && !IsValidHTTPURL(m.SupportURL) {
|
||||
return errors.New("invalid SupportURL")
|
||||
}
|
||||
|
||||
if m.ReleaseNotesURL != "" && !IsValidHTTPURL(m.ReleaseNotesURL) {
|
||||
return errors.New("invalid ReleaseNotesURL")
|
||||
}
|
||||
|
||||
if m.Version != "" {
|
||||
_, err := semver.Parse(m.Version)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse Version")
|
||||
}
|
||||
}
|
||||
|
||||
if m.MinServerVersion != "" {
|
||||
_, err := semver.Parse(m.MinServerVersion)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse MinServerVersion")
|
||||
}
|
||||
}
|
||||
|
||||
if m.SettingsSchema != nil {
|
||||
err := m.SettingsSchema.isValid()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid settings schema")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PluginSettingsSchema) isValid() error {
|
||||
for _, setting := range s.Settings {
|
||||
err := setting.isValid()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PluginSetting) isValid() error {
|
||||
pluginSettingType, err := convertTypeToPluginSettingType(s.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.RegenerateHelpText != "" && pluginSettingType != Generated {
|
||||
return errors.New("should not set RegenerateHelpText for setting type that is not generated")
|
||||
}
|
||||
|
||||
if s.Placeholder != "" && !(pluginSettingType == Generated ||
|
||||
pluginSettingType == Text ||
|
||||
pluginSettingType == LongText ||
|
||||
pluginSettingType == Number ||
|
||||
pluginSettingType == Username ||
|
||||
pluginSettingType == Custom) {
|
||||
return errors.New("should not set Placeholder for setting type not in text, generated, number, username, or custom")
|
||||
}
|
||||
|
||||
if s.Options != nil {
|
||||
if pluginSettingType != Radio && pluginSettingType != Dropdown {
|
||||
return errors.New("should not set Options for setting type not in radio or dropdown")
|
||||
}
|
||||
|
||||
for _, option := range s.Options {
|
||||
if option.DisplayName == "" || option.Value == "" {
|
||||
return errors.New("should not have empty Displayname or Value for any option")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertTypeToPluginSettingType(t string) (PluginSettingType, error) {
|
||||
var settingType PluginSettingType
|
||||
switch t {
|
||||
case "bool":
|
||||
return Bool, nil
|
||||
case "dropdown":
|
||||
return Dropdown, nil
|
||||
case "generated":
|
||||
return Generated, nil
|
||||
case "radio":
|
||||
return Radio, nil
|
||||
case "text":
|
||||
return Text, nil
|
||||
case "number":
|
||||
return Number, nil
|
||||
case "longtext":
|
||||
return LongText, nil
|
||||
case "username":
|
||||
return Username, nil
|
||||
case "custom":
|
||||
return Custom, nil
|
||||
default:
|
||||
return settingType, errors.New("invalid setting type: " + t)
|
||||
}
|
||||
}
|
||||
|
||||
// FindManifest will find and parse the manifest in a given directory.
|
||||
//
|
||||
// In all cases other than a does-not-exist error, path is set to the path of the manifest file that was
|
||||
// found.
|
||||
//
|
||||
// Manifests are JSON or YAML files named plugin.json, plugin.yaml, or plugin.yml.
|
||||
func FindManifest(dir string) (manifest *Manifest, path string, err error) {
|
||||
for _, name := range []string{"plugin.yml", "plugin.yaml"} {
|
||||
path = filepath.Join(dir, name)
|
||||
f, ferr := os.Open(path)
|
||||
if ferr != nil {
|
||||
if !os.IsNotExist(ferr) {
|
||||
return nil, "", ferr
|
||||
}
|
||||
continue
|
||||
}
|
||||
b, ioerr := io.ReadAll(f)
|
||||
f.Close()
|
||||
if ioerr != nil {
|
||||
return nil, path, ioerr
|
||||
}
|
||||
var parsed Manifest
|
||||
err = yaml.Unmarshal(b, &parsed)
|
||||
if err != nil {
|
||||
return nil, path, err
|
||||
}
|
||||
manifest = &parsed
|
||||
manifest.Id = strings.ToLower(manifest.Id)
|
||||
return manifest, path, nil
|
||||
}
|
||||
|
||||
path = filepath.Join(dir, "plugin.json")
|
||||
f, ferr := os.Open(path)
|
||||
if ferr != nil {
|
||||
if os.IsNotExist(ferr) {
|
||||
path = ""
|
||||
}
|
||||
return nil, path, ferr
|
||||
}
|
||||
defer f.Close()
|
||||
var parsed Manifest
|
||||
err = json.NewDecoder(f).Decode(&parsed)
|
||||
if err != nil {
|
||||
return nil, path, err
|
||||
}
|
||||
manifest = &parsed
|
||||
manifest.Id = strings.ToLower(manifest.Id)
|
||||
return manifest, path, nil
|
||||
}
|
||||
129
vendor/github.com/mattermost/mattermost/server/public/model/marketplace_plugin.go
generated
vendored
Normal file
129
vendor/github.com/mattermost/mattermost/server/public/model/marketplace_plugin.go
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// BaseMarketplacePlugin is a Mattermost plugin received from the Marketplace server.
|
||||
type BaseMarketplacePlugin struct {
|
||||
HomepageURL string `json:"homepage_url"`
|
||||
IconData string `json:"icon_data"`
|
||||
DownloadURL string `json:"download_url"`
|
||||
ReleaseNotesURL string `json:"release_notes_url"`
|
||||
Labels []MarketplaceLabel `json:"labels,omitempty"`
|
||||
Hosting string `json:"hosting"` // Indicated if the plugin is limited to a certain hosting type
|
||||
AuthorType string `json:"author_type"` // The maintainer of the plugin
|
||||
ReleaseStage string `json:"release_stage"` // The stage in the software release cycle that the plugin is in
|
||||
Enterprise bool `json:"enterprise"` // Indicated if the plugin is an enterprise plugin
|
||||
Signature string `json:"signature"` // Signature represents a signature of a plugin saved in base64 encoding.
|
||||
Manifest *Manifest `json:"manifest"`
|
||||
}
|
||||
|
||||
// MarketplaceLabel represents a label shown in the Marketplace UI.
|
||||
type MarketplaceLabel struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
URL string `json:"url"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
// MarketplacePlugin is a state aware Marketplace plugin.
|
||||
type MarketplacePlugin struct {
|
||||
*BaseMarketplacePlugin
|
||||
InstalledVersion string `json:"installed_version"`
|
||||
}
|
||||
|
||||
// BaseMarketplacePluginsFromReader decodes a json-encoded list of plugins from the given io.Reader.
|
||||
func BaseMarketplacePluginsFromReader(reader io.Reader) ([]*BaseMarketplacePlugin, error) {
|
||||
plugins := []*BaseMarketplacePlugin{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
|
||||
if err := decoder.Decode(&plugins); err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
// MarketplacePluginsFromReader decodes a json-encoded list of plugins from the given io.Reader.
|
||||
func MarketplacePluginsFromReader(reader io.Reader) ([]*MarketplacePlugin, error) {
|
||||
plugins := []*MarketplacePlugin{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
|
||||
if err := decoder.Decode(&plugins); err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
// DecodeSignature Decodes signature and returns ReadSeeker.
|
||||
func (plugin *BaseMarketplacePlugin) DecodeSignature() (io.ReadSeeker, error) {
|
||||
signatureBytes, err := base64.StdEncoding.DecodeString(plugin.Signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to decode base64 signature.")
|
||||
}
|
||||
return bytes.NewReader(signatureBytes), nil
|
||||
}
|
||||
|
||||
// MarketplacePluginFilter describes the parameters to request a list of plugins.
|
||||
type MarketplacePluginFilter struct {
|
||||
Page int
|
||||
PerPage int
|
||||
Filter string
|
||||
ServerVersion string
|
||||
BuildEnterpriseReady bool
|
||||
EnterprisePlugins bool
|
||||
Cloud bool
|
||||
LocalOnly bool
|
||||
Platform string
|
||||
PluginId string
|
||||
ReturnAllVersions bool
|
||||
RemoteOnly bool
|
||||
}
|
||||
|
||||
// ApplyToURL modifies the given url to include query string parameters for the request.
|
||||
func (filter *MarketplacePluginFilter) ApplyToURL(u *url.URL) {
|
||||
q := u.Query()
|
||||
q.Add("page", strconv.Itoa(filter.Page))
|
||||
if filter.PerPage > 0 {
|
||||
q.Add("per_page", strconv.Itoa(filter.PerPage))
|
||||
}
|
||||
q.Add("filter", filter.Filter)
|
||||
q.Add("server_version", filter.ServerVersion)
|
||||
q.Add("build_enterprise_ready", strconv.FormatBool(filter.BuildEnterpriseReady))
|
||||
q.Add("enterprise_plugins", strconv.FormatBool(filter.EnterprisePlugins))
|
||||
q.Add("cloud", strconv.FormatBool(filter.Cloud))
|
||||
q.Add("local_only", strconv.FormatBool(filter.LocalOnly))
|
||||
q.Add("remote_only", strconv.FormatBool(filter.RemoteOnly))
|
||||
q.Add("platform", filter.Platform)
|
||||
q.Add("plugin_id", filter.PluginId)
|
||||
q.Add("return_all_versions", strconv.FormatBool(filter.ReturnAllVersions))
|
||||
u.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
// InstallMarketplacePluginRequest struct describes parameters of the requested plugin.
|
||||
type InstallMarketplacePluginRequest struct {
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// PluginRequestFromReader decodes a json-encoded plugin request from the given io.Reader.
|
||||
func PluginRequestFromReader(reader io.Reader) (*InstallMarketplacePluginRequest, error) {
|
||||
var r *InstallMarketplacePluginRequest
|
||||
err := json.NewDecoder(reader).Decode(&r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
56
vendor/github.com/mattermost/mattermost/server/public/model/member_invite.go
generated
vendored
Normal file
56
vendor/github.com/mattermost/mattermost/server/public/model/member_invite.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type MemberInvite struct {
|
||||
Emails []string `json:"emails"`
|
||||
ChannelIds []string `json:"channelIds,omitempty"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (i *MemberInvite) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"emails": i.Emails,
|
||||
"channel_ids": i.ChannelIds,
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid validates that the invitation info is loaded correctly and with the correct structure
|
||||
func (i *MemberInvite) IsValid() *AppError {
|
||||
if len(i.Emails) == 0 {
|
||||
return NewAppError("MemberInvite.IsValid", "model.member.is_valid.emails.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(i.ChannelIds) > 0 {
|
||||
for _, channel := range i.ChannelIds {
|
||||
if len(channel) != 26 {
|
||||
return NewAppError("MemberInvite.IsValid", "model.member.is_valid.channel.app_error", nil, "channel="+channel, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *MemberInvite) UnmarshalJSON(b []byte) error {
|
||||
var emails []string
|
||||
if err := json.Unmarshal(b, &emails); err == nil {
|
||||
*i = MemberInvite{}
|
||||
i.Emails = emails
|
||||
return nil
|
||||
}
|
||||
|
||||
type TempMemberInvite MemberInvite
|
||||
var o2 TempMemberInvite
|
||||
if err := json.Unmarshal(b, &o2); err != nil {
|
||||
return err
|
||||
}
|
||||
*i = MemberInvite(o2)
|
||||
return nil
|
||||
}
|
||||
80
vendor/github.com/mattermost/mattermost/server/public/model/mention_map.go
generated
vendored
Normal file
80
vendor/github.com/mattermost/mattermost/server/public/model/mention_map.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type UserMentionMap map[string]string
|
||||
type ChannelMentionMap map[string]string
|
||||
|
||||
const (
|
||||
userMentionsKey = "user_mentions"
|
||||
userMentionsIdsKey = "user_mentions_ids"
|
||||
channelMentionsKey = "channel_mentions"
|
||||
channelMentionsIdsKey = "channel_mentions_ids"
|
||||
)
|
||||
|
||||
func UserMentionMapFromURLValues(values url.Values) (UserMentionMap, error) {
|
||||
return mentionsFromURLValues(values, userMentionsKey, userMentionsIdsKey)
|
||||
}
|
||||
|
||||
func (m UserMentionMap) ToURLValues() url.Values {
|
||||
return mentionsToURLValues(m, userMentionsKey, userMentionsIdsKey)
|
||||
}
|
||||
|
||||
func ChannelMentionMapFromURLValues(values url.Values) (ChannelMentionMap, error) {
|
||||
return mentionsFromURLValues(values, channelMentionsKey, channelMentionsIdsKey)
|
||||
}
|
||||
|
||||
func (m ChannelMentionMap) ToURLValues() url.Values {
|
||||
return mentionsToURLValues(m, channelMentionsKey, channelMentionsIdsKey)
|
||||
}
|
||||
|
||||
func mentionsFromURLValues(values url.Values, mentionKey, idKey string) (map[string]string, error) {
|
||||
mentions, mentionsOk := values[mentionKey]
|
||||
ids, idsOk := values[idKey]
|
||||
|
||||
if !mentionsOk && !idsOk {
|
||||
return map[string]string{}, nil
|
||||
}
|
||||
|
||||
if !mentionsOk {
|
||||
return nil, fmt.Errorf("%s key not found", mentionKey)
|
||||
}
|
||||
|
||||
if !idsOk {
|
||||
return nil, fmt.Errorf("%s key not found", idKey)
|
||||
}
|
||||
|
||||
if len(mentions) != len(ids) {
|
||||
return nil, fmt.Errorf("keys %s and %s have different length", mentionKey, idKey)
|
||||
}
|
||||
|
||||
mentionsMap := make(map[string]string)
|
||||
for i, mention := range mentions {
|
||||
id := ids[i]
|
||||
|
||||
if oldId, ok := mentionsMap[mention]; ok && oldId != id {
|
||||
return nil, fmt.Errorf("key %s has two different values: %s and %s", mention, oldId, id)
|
||||
}
|
||||
|
||||
mentionsMap[mention] = id
|
||||
}
|
||||
|
||||
return mentionsMap, nil
|
||||
}
|
||||
|
||||
func mentionsToURLValues(mentions map[string]string, mentionKey, idKey string) url.Values {
|
||||
values := url.Values{}
|
||||
|
||||
for mention, id := range mentions {
|
||||
values.Add(mentionKey, mention)
|
||||
values.Add(idKey, id)
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
50
vendor/github.com/mattermost/mattermost/server/public/model/message_export.go
generated
vendored
Normal file
50
vendor/github.com/mattermost/mattermost/server/public/model/message_export.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type MessageExport struct {
|
||||
TeamId *string
|
||||
TeamName *string
|
||||
TeamDisplayName *string
|
||||
|
||||
ChannelId *string
|
||||
ChannelName *string
|
||||
ChannelDisplayName *string
|
||||
ChannelType *ChannelType
|
||||
|
||||
UserId *string
|
||||
UserEmail *string
|
||||
Username *string
|
||||
IsBot bool
|
||||
|
||||
PostId *string
|
||||
PostCreateAt *int64
|
||||
PostUpdateAt *int64
|
||||
PostDeleteAt *int64
|
||||
PostMessage *string
|
||||
PostType *string
|
||||
PostRootId *string
|
||||
PostProps *string
|
||||
PostOriginalId *string
|
||||
PostFileIds StringArray
|
||||
}
|
||||
|
||||
type MessageExportCursor struct {
|
||||
LastPostUpdateAt int64
|
||||
LastPostId string
|
||||
}
|
||||
|
||||
// PreviewID returns the value of the post's previewed_post prop, if present, or an empty string.
|
||||
func (m *MessageExport) PreviewID() string {
|
||||
var previewID string
|
||||
props := map[string]any{}
|
||||
if m.PostProps != nil && json.Unmarshal([]byte(*m.PostProps), &props) == nil {
|
||||
if val, ok := props[PostPropsPreviewedPost]; ok {
|
||||
previewID = val.(string)
|
||||
}
|
||||
}
|
||||
return previewID
|
||||
}
|
||||
114
vendor/github.com/mattermost/mattermost/server/public/model/metrics.go
generated
vendored
Normal file
114
vendor/github.com/mattermost/mattermost/server/public/model/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
)
|
||||
|
||||
type MetricType string
|
||||
|
||||
const (
|
||||
ClientTimeToFirstByte MetricType = "TTFB"
|
||||
ClientFirstContentfulPaint MetricType = "FCP"
|
||||
ClientLargestContentfulPaint MetricType = "LCP"
|
||||
ClientInteractionToNextPaint MetricType = "INP"
|
||||
ClientCumulativeLayoutShift MetricType = "CLS"
|
||||
ClientLongTasks MetricType = "long_tasks"
|
||||
ClientChannelSwitchDuration MetricType = "channel_switch"
|
||||
ClientTeamSwitchDuration MetricType = "team_switch"
|
||||
ClientRHSLoadDuration MetricType = "rhs_load"
|
||||
|
||||
performanceReportTTLMilliseconds = 300 * 1000 // 300 seconds/5 minutes
|
||||
)
|
||||
|
||||
var (
|
||||
performanceReportVersion = semver.MustParse("0.1.0")
|
||||
acceptedPlatforms = sliceToMapKey("linux", "macos", "ios", "android", "windows", "other")
|
||||
acceptedAgents = sliceToMapKey("desktop", "firefox", "chrome", "safari", "edge", "other")
|
||||
)
|
||||
|
||||
type MetricSample struct {
|
||||
Metric MetricType `json:"metric"`
|
||||
Value float64 `json:"value"`
|
||||
Timestamp float64 `json:"timestamp,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// PerformanceReport is a set of samples collected from a client
|
||||
type PerformanceReport struct {
|
||||
Version string `json:"version"`
|
||||
ClientID string `json:"client_id"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
Start float64 `json:"start"`
|
||||
End float64 `json:"end"`
|
||||
Counters []*MetricSample `json:"counters"`
|
||||
Histograms []*MetricSample `json:"histograms"`
|
||||
}
|
||||
|
||||
func (r *PerformanceReport) IsValid() error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("the report is nil")
|
||||
}
|
||||
|
||||
reportVersion, err := semver.ParseTolerant(r.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if reportVersion.Major != performanceReportVersion.Major || reportVersion.Minor > performanceReportVersion.Minor {
|
||||
return fmt.Errorf("report version is not supported: server version: %s, report version: %s", performanceReportVersion.String(), r.Version)
|
||||
}
|
||||
|
||||
if r.Start > r.End {
|
||||
return fmt.Errorf("report timestamps are erroneous")
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
if r.End < float64(now-performanceReportTTLMilliseconds) {
|
||||
return fmt.Errorf("report is outdated: %f", r.End)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *PerformanceReport) ProcessLabels() map[string]string {
|
||||
var platform, agent string
|
||||
var ok bool
|
||||
|
||||
// check if the platform is specified
|
||||
platform, ok = r.Labels["platform"]
|
||||
if !ok {
|
||||
platform = "other"
|
||||
}
|
||||
platform = strings.ToLower(platform)
|
||||
|
||||
// check if platform is one of the accepted platforms
|
||||
_, ok = acceptedPlatforms[platform]
|
||||
if !ok {
|
||||
platform = "other"
|
||||
}
|
||||
|
||||
// check if the agent is specified
|
||||
agent, ok = r.Labels["agent"]
|
||||
if !ok {
|
||||
agent = "other"
|
||||
}
|
||||
agent = strings.ToLower(agent)
|
||||
|
||||
// check if agent is one of the accepted agents
|
||||
_, ok = acceptedAgents[agent]
|
||||
if !ok {
|
||||
agent = "other"
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
"platform": platform,
|
||||
"agent": agent,
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/mattermost/mattermost/server/public/model/mfa_secret.go
generated
vendored
Normal file
9
vendor/github.com/mattermost/mattermost/server/public/model/mfa_secret.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type MfaSecret struct {
|
||||
Secret string `json:"secret"`
|
||||
QRCode string `json:"qr_code"`
|
||||
}
|
||||
50
vendor/github.com/mattermost/mattermost/server/public/model/migration.go
generated
vendored
Normal file
50
vendor/github.com/mattermost/mattermost/server/public/model/migration.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
AdvancedPermissionsMigrationKey = "AdvancedPermissionsMigrationComplete"
|
||||
MigrationKeyAdvancedPermissionsPhase2 = "migration_advanced_permissions_phase_2"
|
||||
|
||||
MigrationKeyEmojiPermissionsSplit = "emoji_permissions_split"
|
||||
MigrationKeyWebhookPermissionsSplit = "webhook_permissions_split"
|
||||
MigrationKeyListJoinPublicPrivateTeams = "list_join_public_private_teams"
|
||||
MigrationKeyRemovePermanentDeleteUser = "remove_permanent_delete_user"
|
||||
MigrationKeyAddBotPermissions = "add_bot_permissions"
|
||||
MigrationKeyApplyChannelManageDeleteToChannelUser = "apply_channel_manage_delete_to_channel_user"
|
||||
MigrationKeyRemoveChannelManageDeleteFromTeamUser = "remove_channel_manage_delete_from_team_user"
|
||||
MigrationKeyViewMembersNewPermission = "view_members_new_permission"
|
||||
MigrationKeyAddManageGuestsPermissions = "add_manage_guests_permissions"
|
||||
MigrationKeyChannelModerationsPermissions = "channel_moderations_permissions"
|
||||
MigrationKeyAddUseGroupMentionsPermission = "add_use_group_mentions_permission"
|
||||
MigrationKeyAddSystemConsolePermissions = "add_system_console_permissions"
|
||||
MigrationKeySidebarCategoriesPhase2 = "migration_sidebar_categories_phase_2"
|
||||
MigrationKeyAddConvertChannelPermissions = "add_convert_channel_permissions"
|
||||
MigrationKeyAddSystemRolesPermissions = "add_system_roles_permissions"
|
||||
MigrationKeyAddBillingPermissions = "add_billing_permissions"
|
||||
MigrationKeyAddManageSharedChannelPermissions = "manage_shared_channel_permissions"
|
||||
MigrationKeyAddManageSecureConnectionsPermissions = "manage_secure_connections_permissions"
|
||||
MigrationKeyAddDownloadComplianceExportResults = "download_compliance_export_results"
|
||||
MigrationKeyAddComplianceSubsectionPermissions = "compliance_subsection_permissions"
|
||||
MigrationKeyAddExperimentalSubsectionPermissions = "experimental_subsection_permissions"
|
||||
MigrationKeyAddAuthenticationSubsectionPermissions = "authentication_subsection_permissions"
|
||||
MigrationKeyAddSiteSubsectionPermissions = "site_subsection_permissions"
|
||||
MigrationKeyAddEnvironmentSubsectionPermissions = "environment_subsection_permissions"
|
||||
MigrationKeyAddReportingSubsectionPermissions = "reporting_subsection_permissions"
|
||||
MigrationKeyAddTestEmailAncillaryPermission = "test_email_ancillary_permission"
|
||||
MigrationKeyAddAboutSubsectionPermissions = "about_subsection_permissions"
|
||||
MigrationKeyAddIntegrationsSubsectionPermissions = "integrations_subsection_permissions"
|
||||
MigrationKeyAddPlaybooksPermissions = "playbooks_permissions"
|
||||
MigrationKeyAddCustomUserGroupsPermissions = "custom_groups_permissions"
|
||||
MigrationKeyAddPlayboosksManageRolesPermissions = "playbooks_manage_roles"
|
||||
MigrationKeyAddProductsBoardsPermissions = "products_boards"
|
||||
MigrationKeyAddCustomUserGroupsPermissionRestore = "custom_groups_permission_restore"
|
||||
MigrationKeyAddReadChannelContentPermissions = "read_channel_content_permissions"
|
||||
MigrationKeyS3Path = "s3_path_migration"
|
||||
MigrationKeyDeleteEmptyDrafts = "delete_empty_drafts_migration"
|
||||
MigrationKeyDeleteOrphanDrafts = "delete_orphan_drafts_migration"
|
||||
MigrationKeyAddIPFilteringPermissions = "add_ip_filtering_permissions"
|
||||
MigrationKeyAddOutgoingOAuthConnectionsPermissions = "add_outgoing_oauth_connections_permissions"
|
||||
MigrationKeyAddChannelBookmarksPermissions = "add_channel_bookmarks_permissions"
|
||||
)
|
||||
39
vendor/github.com/mattermost/mattermost/server/public/model/notification.go
generated
vendored
Normal file
39
vendor/github.com/mattermost/mattermost/server/public/model/notification.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type NotificationStatus string
|
||||
type NotificationType string
|
||||
type NotificationReason string
|
||||
|
||||
const (
|
||||
NotificationStatusSuccess NotificationStatus = "success"
|
||||
NotificationStatusError NotificationStatus = "error"
|
||||
NotificationStatusNotSent NotificationStatus = "not_sent"
|
||||
NotificationStatusUnsupported NotificationStatus = "unsupported"
|
||||
|
||||
NotificationTypeAll NotificationType = "all"
|
||||
NotificationTypeEmail NotificationType = "email"
|
||||
NotificationTypeWebsocket NotificationType = "websocket"
|
||||
NotificationTypePush NotificationType = "push"
|
||||
|
||||
NotificationReasonFetchError NotificationReason = "fetch_error"
|
||||
NotificationReasonParseError NotificationReason = "json_parse_error"
|
||||
NotificationReasonPushProxyError NotificationReason = "push_proxy_error"
|
||||
NotificationReasonPushProxySendError NotificationReason = "push_proxy_send_error"
|
||||
NotificationReasonRejectedByPlugin NotificationReason = "rejected_by_plugin"
|
||||
NotificationReasonSessionExpired NotificationReason = "session_expired"
|
||||
NotificationReasonChannelMuted NotificationReason = "channel_muted"
|
||||
NotificationReasonSystemMessage NotificationReason = "system_message"
|
||||
NotificationReasonLevelSetToNone NotificationReason = "notify_level_none"
|
||||
NotificationReasonNotMentioned NotificationReason = "not_mentioned"
|
||||
NotificationReasonUserStatus NotificationReason = "user_status"
|
||||
NotificationReasonUserIsActive NotificationReason = "user_is_active"
|
||||
NotificationReasonMissingProfile NotificationReason = "missing_profile"
|
||||
NotificationReasonEmailNotVerified NotificationReason = "email_not_verified"
|
||||
NotificationReasonEmailSendError NotificationReason = "email_send_error"
|
||||
NotificationReasonTooManyUsersInChannel NotificationReason = "too_many_users_in_channel"
|
||||
NotificationReasonResolvePersistentNotificationError NotificationReason = "resolve_persistent_notification_error"
|
||||
NotificationReasonMissingThreadMembership NotificationReason = "missing_thread_membership"
|
||||
)
|
||||
82
vendor/github.com/mattermost/mattermost/server/public/model/notify_admin.go
generated
vendored
Normal file
82
vendor/github.com/mattermost/mattermost/server/public/model/notify_admin.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MattermostFeature string
|
||||
|
||||
const (
|
||||
PaidFeatureGuestAccounts = MattermostFeature("mattermost.feature.guest_accounts")
|
||||
PaidFeatureCustomUsergroups = MattermostFeature("mattermost.feature.custom_user_groups")
|
||||
PaidFeatureCreateMultipleTeams = MattermostFeature("mattermost.feature.create_multiple_teams")
|
||||
PaidFeatureStartcall = MattermostFeature("mattermost.feature.start_call")
|
||||
PaidFeaturePlaybooksRetrospective = MattermostFeature("mattermost.feature.playbooks_retro")
|
||||
PaidFeatureUnlimitedMessages = MattermostFeature("mattermost.feature.unlimited_messages")
|
||||
PaidFeatureUnlimitedFileStorage = MattermostFeature("mattermost.feature.unlimited_file_storage")
|
||||
PaidFeatureAllProfessionalfeatures = MattermostFeature("mattermost.feature.all_professional")
|
||||
PaidFeatureAllEnterprisefeatures = MattermostFeature("mattermost.feature.all_enterprise")
|
||||
UpgradeDowngradedWorkspace = MattermostFeature("mattermost.feature.upgrade_downgraded_workspace")
|
||||
PluginFeature = MattermostFeature("mattermost.feature.plugin")
|
||||
PaidFeatureHighlightWithoutNotification = MattermostFeature("mattermost.feature.highlight_without_notification")
|
||||
)
|
||||
|
||||
var validSKUs = map[string]struct{}{
|
||||
LicenseShortSkuProfessional: {},
|
||||
LicenseShortSkuEnterprise: {},
|
||||
}
|
||||
|
||||
// These are the features a non admin would typically ping an admin about
|
||||
var paidFeatures = map[MattermostFeature]struct{}{
|
||||
PaidFeatureGuestAccounts: {},
|
||||
PaidFeatureCustomUsergroups: {},
|
||||
PaidFeatureCreateMultipleTeams: {},
|
||||
PaidFeatureStartcall: {},
|
||||
PaidFeaturePlaybooksRetrospective: {},
|
||||
PaidFeatureUnlimitedMessages: {},
|
||||
PaidFeatureUnlimitedFileStorage: {},
|
||||
PaidFeatureAllProfessionalfeatures: {},
|
||||
PaidFeatureAllEnterprisefeatures: {},
|
||||
UpgradeDowngradedWorkspace: {},
|
||||
PaidFeatureHighlightWithoutNotification: {},
|
||||
}
|
||||
|
||||
type NotifyAdminToUpgradeRequest struct {
|
||||
TrialNotification bool `json:"trial_notification"`
|
||||
RequiredPlan string `json:"required_plan"`
|
||||
RequiredFeature MattermostFeature `json:"required_feature"`
|
||||
}
|
||||
|
||||
type NotifyAdminData struct {
|
||||
CreateAt int64 `json:"create_at,omitempty"`
|
||||
UserId string `json:"user_id"`
|
||||
RequiredPlan string `json:"required_plan"`
|
||||
RequiredFeature MattermostFeature `json:"required_feature"`
|
||||
Trial bool `json:"trial"`
|
||||
SentAt sql.NullInt64 `json:"sent_at"`
|
||||
}
|
||||
|
||||
func (nad *NotifyAdminData) IsValid() *AppError {
|
||||
if strings.HasPrefix(string(nad.RequiredFeature), string(PluginFeature)) {
|
||||
return nil
|
||||
}
|
||||
if _, planOk := validSKUs[nad.RequiredPlan]; !planOk {
|
||||
return NewAppError("NotifyAdmin.IsValid", fmt.Sprintf("Invalid plan, %s provided", nad.RequiredPlan), nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if _, featureOk := paidFeatures[nad.RequiredFeature]; !featureOk {
|
||||
return NewAppError("NotifyAdmin.IsValid", fmt.Sprintf("Invalid feature, %s provided", nad.RequiredFeature), nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nad *NotifyAdminData) PreSave() {
|
||||
nad.CreateAt = GetMillis()
|
||||
}
|
||||
147
vendor/github.com/mattermost/mattermost/server/public/model/oauth.go
generated
vendored
Normal file
147
vendor/github.com/mattermost/mattermost/server/public/model/oauth.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
OAuthActionSignup = "signup"
|
||||
OAuthActionLogin = "login"
|
||||
OAuthActionEmailToSSO = "email_to_sso"
|
||||
OAuthActionSSOToEmail = "sso_to_email"
|
||||
OAuthActionMobile = "mobile"
|
||||
)
|
||||
|
||||
type OAuthApp struct {
|
||||
Id string `json:"id"`
|
||||
CreatorId string `json:"creator_id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
IconURL string `json:"icon_url"`
|
||||
CallbackUrls StringArray `json:"callback_urls"`
|
||||
Homepage string `json:"homepage"`
|
||||
IsTrusted bool `json:"is_trusted"`
|
||||
MattermostAppID string `json:"mattermost_app_id"`
|
||||
}
|
||||
|
||||
func (a *OAuthApp) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": a.Id,
|
||||
"creator_id": a.CreatorId,
|
||||
"create_at": a.CreateAt,
|
||||
"update_at": a.UpdateAt,
|
||||
"name": a.Name,
|
||||
"description": a.Description,
|
||||
"icon_url": a.IconURL,
|
||||
"callback_urls:": a.CallbackUrls,
|
||||
"homepage": a.Homepage,
|
||||
"is_trusted": a.IsTrusted,
|
||||
"mattermost_app_id": a.MattermostAppID,
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid validates the app and returns an error if it isn't configured
|
||||
// correctly.
|
||||
func (a *OAuthApp) IsValid() *AppError {
|
||||
if !IsValidId(a.Id) {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.app_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if a.CreateAt == 0 {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.create_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if a.UpdateAt == 0 {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.update_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(a.CreatorId) {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.creator_id.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if a.ClientSecret == "" || len(a.ClientSecret) > 128 {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.client_secret.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if a.Name == "" || len(a.Name) > 64 {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.name.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(a.CallbackUrls) == 0 || len(fmt.Sprintf("%s", a.CallbackUrls)) > 1024 {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
for _, callback := range a.CallbackUrls {
|
||||
if !IsValidHTTPURL(callback) {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if a.Homepage == "" || len(a.Homepage) > 256 || !IsValidHTTPURL(a.Homepage) {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(a.Description) > 512 {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if a.IconURL != "" {
|
||||
if len(a.IconURL) > 512 || !IsValidHTTPURL(a.IconURL) {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if len(a.MattermostAppID) > 32 {
|
||||
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.mattermost_app_id.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PreSave will set the Id and ClientSecret if missing. It will also fill
|
||||
// in the CreateAt, UpdateAt times. It should be run before saving the app to the db.
|
||||
func (a *OAuthApp) PreSave() {
|
||||
if a.Id == "" {
|
||||
a.Id = NewId()
|
||||
}
|
||||
|
||||
if a.ClientSecret == "" {
|
||||
a.ClientSecret = NewId()
|
||||
}
|
||||
|
||||
a.CreateAt = GetMillis()
|
||||
a.UpdateAt = a.CreateAt
|
||||
}
|
||||
|
||||
// PreUpdate should be run before updating the app in the db.
|
||||
func (a *OAuthApp) PreUpdate() {
|
||||
a.UpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
// Generate a valid strong etag so the browser can cache the results
|
||||
func (a *OAuthApp) Etag() string {
|
||||
return Etag(a.Id, a.UpdateAt)
|
||||
}
|
||||
|
||||
// Remove any private data from the app object
|
||||
func (a *OAuthApp) Sanitize() {
|
||||
a.ClientSecret = ""
|
||||
}
|
||||
|
||||
func (a *OAuthApp) IsValidRedirectURL(url string) bool {
|
||||
for _, u := range a.CallbackUrls {
|
||||
if u == url {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
32
vendor/github.com/mattermost/mattermost/server/public/model/onboarding.go
generated
vendored
Normal file
32
vendor/github.com/mattermost/mattermost/server/public/model/onboarding.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
// CompleteOnboardingRequest describes parameters of the requested plugin.
|
||||
type CompleteOnboardingRequest struct {
|
||||
Organization string `json:"organization"` // Organization is the name of the organization
|
||||
InstallPlugins []string `json:"install_plugins"` // InstallPlugins is a list of plugins to be installed
|
||||
}
|
||||
|
||||
func (r *CompleteOnboardingRequest) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"install_plugins": r.InstallPlugins,
|
||||
}
|
||||
}
|
||||
|
||||
// CompleteOnboardingRequest decodes a json-encoded request from the given io.Reader.
|
||||
func CompleteOnboardingRequestFromReader(reader io.Reader) (*CompleteOnboardingRequest, error) {
|
||||
var r *CompleteOnboardingRequest
|
||||
err := json.NewDecoder(reader).Decode(&r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
230
vendor/github.com/mattermost/mattermost/server/public/model/outgoing_oauth_connection.go
generated
vendored
Normal file
230
vendor/github.com/mattermost/mattermost/server/public/model/outgoing_oauth_connection.go
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type OutgoingOAuthConnectionGrantType string
|
||||
|
||||
func (gt OutgoingOAuthConnectionGrantType) IsValid() bool {
|
||||
return gt == OutgoingOAuthConnectionGrantTypeClientCredentials || gt == OutgoingOAuthConnectionGrantTypePassword
|
||||
}
|
||||
|
||||
const (
|
||||
OutgoingOAuthConnectionGrantTypeClientCredentials OutgoingOAuthConnectionGrantType = "client_credentials"
|
||||
OutgoingOAuthConnectionGrantTypePassword OutgoingOAuthConnectionGrantType = "password"
|
||||
|
||||
defaultGetConnectionsLimit = 50
|
||||
)
|
||||
|
||||
type OutgoingOAuthConnection struct {
|
||||
Id string `json:"id"`
|
||||
CreatorId string `json:"creator_id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
Name string `json:"name"`
|
||||
ClientId string `json:"client_id,omitempty"`
|
||||
ClientSecret string `json:"client_secret,omitempty"`
|
||||
CredentialsUsername *string `json:"credentials_username,omitempty"`
|
||||
CredentialsPassword *string `json:"credentials_password,omitempty"`
|
||||
OAuthTokenURL string `json:"oauth_token_url"`
|
||||
GrantType OutgoingOAuthConnectionGrantType `json:"grant_type"`
|
||||
Audiences StringArray `json:"audiences"`
|
||||
}
|
||||
|
||||
func (oa *OutgoingOAuthConnection) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": oa.Id,
|
||||
"creator_id": oa.CreatorId,
|
||||
"create_at": oa.CreateAt,
|
||||
"update_at": oa.UpdateAt,
|
||||
"name": oa.Name,
|
||||
"grant_type": oa.GrantType,
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize removes any sensitive fields from the OutgoingOAuthConnection object.
|
||||
func (oa *OutgoingOAuthConnection) Sanitize() {
|
||||
oa.ClientSecret = ""
|
||||
oa.CredentialsPassword = nil
|
||||
}
|
||||
|
||||
// Patch updates the OutgoingOAuthConnection object with the non-empty fields from the given connection.
|
||||
func (oa *OutgoingOAuthConnection) Patch(conn *OutgoingOAuthConnection) {
|
||||
if conn == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if conn.Name != "" {
|
||||
oa.Name = conn.Name
|
||||
}
|
||||
if conn.ClientId != "" {
|
||||
oa.ClientId = conn.ClientId
|
||||
}
|
||||
if conn.ClientSecret != "" {
|
||||
oa.ClientSecret = conn.ClientSecret
|
||||
}
|
||||
if conn.OAuthTokenURL != "" {
|
||||
oa.OAuthTokenURL = conn.OAuthTokenURL
|
||||
}
|
||||
if conn.GrantType != "" {
|
||||
oa.GrantType = conn.GrantType
|
||||
}
|
||||
if len(conn.Audiences) > 0 {
|
||||
oa.Audiences = conn.Audiences
|
||||
}
|
||||
if conn.CredentialsUsername != nil {
|
||||
oa.CredentialsUsername = conn.CredentialsUsername
|
||||
}
|
||||
if conn.CredentialsPassword != nil {
|
||||
oa.CredentialsPassword = conn.CredentialsPassword
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid validates the object and returns an error if it isn't properly configured
|
||||
func (oa *OutgoingOAuthConnection) IsValid() *AppError {
|
||||
if !IsValidId(oa.Id) {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.id.error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if oa.CreateAt == 0 {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.create_at.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if oa.UpdateAt == 0 {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.update_at.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(oa.CreatorId) {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.creator_id.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if oa.Name == "" || utf8.RuneCountInString(oa.Name) > 64 {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.name.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if oa.ClientId == "" || utf8.RuneCountInString(oa.ClientId) > 255 {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.client_id.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if oa.ClientSecret == "" || utf8.RuneCountInString(oa.ClientSecret) > 255 {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.client_secret.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidHTTPURL(oa.OAuthTokenURL) || utf8.RuneCountInString(oa.OAuthTokenURL) > 256 {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.oauth_token_url.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if err := oa.HasValidGrantType(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(oa.Audiences) == 0 {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.audience.empty", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(oa.Audiences) > 0 {
|
||||
for _, audience := range oa.Audiences {
|
||||
if !IsValidHTTPURL(audience) {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.audience.error", map[string]any{"Url": audience}, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasValidGrantType validates the grant type and its parameters returning an error if it isn't properly configured
|
||||
func (oa *OutgoingOAuthConnection) HasValidGrantType() *AppError {
|
||||
if !oa.GrantType.IsValid() {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.grant_type.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if oa.GrantType == OutgoingOAuthConnectionGrantTypePassword && (oa.CredentialsUsername == nil || oa.CredentialsPassword == nil) {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.password_credentials.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if oa.GrantType == OutgoingOAuthConnectionGrantTypePassword && (*oa.CredentialsUsername == "" || *oa.CredentialsPassword == "") {
|
||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.password_credentials.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PreSave will set the Id if empty, ensuring the object has one and the create/update times.
|
||||
func (oa *OutgoingOAuthConnection) PreSave() {
|
||||
if oa.Id == "" {
|
||||
oa.Id = NewId()
|
||||
}
|
||||
|
||||
oa.CreateAt = GetMillis()
|
||||
oa.UpdateAt = oa.CreateAt
|
||||
}
|
||||
|
||||
// PreUpdate will set the update time to now.
|
||||
func (oa *OutgoingOAuthConnection) PreUpdate() {
|
||||
oa.UpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
// Etag returns the ETag for the cache.
|
||||
func (oa *OutgoingOAuthConnection) Etag() string {
|
||||
return Etag(oa.Id, oa.UpdateAt)
|
||||
}
|
||||
|
||||
// OutgoingOAuthConnectionGetConnectionsFilter is used to filter outgoing connections
|
||||
type OutgoingOAuthConnectionGetConnectionsFilter struct {
|
||||
OffsetId string
|
||||
Limit int
|
||||
Audience string
|
||||
|
||||
// TeamId is not used as a filter but as a way to check if the current user has permission to
|
||||
// access the outgoing oauth connection for the given team in order to use them in the slash
|
||||
// commands and outgoing webhooks.
|
||||
TeamId string
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values for the filter
|
||||
func (oaf *OutgoingOAuthConnectionGetConnectionsFilter) SetDefaults() {
|
||||
if oaf.Limit == 0 {
|
||||
oaf.Limit = defaultGetConnectionsLimit
|
||||
}
|
||||
}
|
||||
|
||||
// ToURLValues converts the filter to url.Values
|
||||
func (oaf *OutgoingOAuthConnectionGetConnectionsFilter) ToURLValues() url.Values {
|
||||
v := url.Values{}
|
||||
|
||||
if oaf.Limit > 0 {
|
||||
v.Set("limit", fmt.Sprintf("%d", oaf.Limit))
|
||||
}
|
||||
|
||||
if oaf.OffsetId != "" {
|
||||
v.Set("offset_id", oaf.OffsetId)
|
||||
}
|
||||
|
||||
if oaf.Audience != "" {
|
||||
v.Set("audience", oaf.Audience)
|
||||
}
|
||||
|
||||
if oaf.TeamId != "" {
|
||||
v.Set("team_id", oaf.TeamId)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// OutgoingOAuthConnectionToken is used to return the token for an outgoing connection oauth
|
||||
// authentication request
|
||||
type OutgoingOAuthConnectionToken struct {
|
||||
AccessToken string
|
||||
TokenType string
|
||||
}
|
||||
|
||||
func (ooct *OutgoingOAuthConnectionToken) AsHeaderValue() string {
|
||||
return ooct.TokenType + " " + ooct.AccessToken
|
||||
}
|
||||
244
vendor/github.com/mattermost/mattermost/server/public/model/outgoing_webhook.go
generated
vendored
Normal file
244
vendor/github.com/mattermost/mattermost/server/public/model/outgoing_webhook.go
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OutgoingWebhook struct {
|
||||
Id string `json:"id"`
|
||||
Token string `json:"token"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
CreatorId string `json:"creator_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
TeamId string `json:"team_id"`
|
||||
TriggerWords StringArray `json:"trigger_words"`
|
||||
TriggerWhen int `json:"trigger_when"`
|
||||
CallbackURLs StringArray `json:"callback_urls"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Description string `json:"description"`
|
||||
ContentType string `json:"content_type"`
|
||||
Username string `json:"username"`
|
||||
IconURL string `json:"icon_url"`
|
||||
}
|
||||
|
||||
func (o *OutgoingWebhook) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": o.Id,
|
||||
"create_at": o.CreateAt,
|
||||
"update_at": o.UpdateAt,
|
||||
"delete_at": o.DeleteAt,
|
||||
"creator_id": o.CreatorId,
|
||||
"channel_id": o.ChannelId,
|
||||
"team_id": o.TeamId,
|
||||
"trigger_words": o.TriggerWords,
|
||||
"trigger_when": o.TriggerWhen,
|
||||
"callback_urls": o.CallbackURLs,
|
||||
"display_name": o.DisplayName,
|
||||
"description": o.Description,
|
||||
"content_type": o.ContentType,
|
||||
"username": o.Username,
|
||||
"icon_url": o.IconURL,
|
||||
}
|
||||
}
|
||||
|
||||
type OutgoingWebhookPayload struct {
|
||||
Token string `json:"token"`
|
||||
TeamId string `json:"team_id"`
|
||||
TeamDomain string `json:"team_domain"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
UserId string `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
PostId string `json:"post_id"`
|
||||
Text string `json:"text"`
|
||||
TriggerWord string `json:"trigger_word"`
|
||||
FileIds string `json:"file_ids"`
|
||||
}
|
||||
|
||||
type OutgoingWebhookResponse struct {
|
||||
Text *string `json:"text"`
|
||||
Username string `json:"username"`
|
||||
IconURL string `json:"icon_url"`
|
||||
Props StringInterface `json:"props"`
|
||||
Attachments []*SlackAttachment `json:"attachments"`
|
||||
Type string `json:"type"`
|
||||
ResponseType string `json:"response_type"`
|
||||
Priority *PostPriority `json:"priority"`
|
||||
}
|
||||
|
||||
const OutgoingHookResponseTypeComment = "comment"
|
||||
|
||||
func (o *OutgoingWebhookPayload) ToFormValues() string {
|
||||
v := url.Values{}
|
||||
v.Set("token", o.Token)
|
||||
v.Set("team_id", o.TeamId)
|
||||
v.Set("team_domain", o.TeamDomain)
|
||||
v.Set("channel_id", o.ChannelId)
|
||||
v.Set("channel_name", o.ChannelName)
|
||||
v.Set("timestamp", strconv.FormatInt(o.Timestamp/1000, 10))
|
||||
v.Set("user_id", o.UserId)
|
||||
v.Set("user_name", o.UserName)
|
||||
v.Set("post_id", o.PostId)
|
||||
v.Set("text", o.Text)
|
||||
v.Set("trigger_word", o.TriggerWord)
|
||||
v.Set("file_ids", o.FileIds)
|
||||
|
||||
return v.Encode()
|
||||
}
|
||||
|
||||
func (o *OutgoingWebhook) IsValid() *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Token) != 26 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.token.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.UpdateAt == 0 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.CreatorId) {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.ChannelId != "" && !IsValidId(o.ChannelId) {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.TeamId) {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(fmt.Sprintf("%s", o.TriggerWords)) > 1024 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.words.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.TriggerWords) != 0 {
|
||||
for _, triggerWord := range o.TriggerWords {
|
||||
if triggerWord == "" {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.trigger_words.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(o.CallbackURLs) == 0 || len(fmt.Sprintf("%s", o.CallbackURLs)) > 1024 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.callback.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
for _, callback := range o.CallbackURLs {
|
||||
if !IsValidHTTPURL(callback) {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.url.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if len(o.DisplayName) > 64 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.display_name.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Description) > 500 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.description.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.ContentType) > 128 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.TriggerWhen > 1 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.Username) > 64 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.username.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(o.IconURL) > 1024 {
|
||||
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.icon_url.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OutgoingWebhook) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
if o.Token == "" {
|
||||
o.Token = NewId()
|
||||
}
|
||||
|
||||
o.CreateAt = GetMillis()
|
||||
o.UpdateAt = o.CreateAt
|
||||
}
|
||||
|
||||
func (o *OutgoingWebhook) PreUpdate() {
|
||||
o.UpdateAt = GetMillis()
|
||||
}
|
||||
|
||||
func (o *OutgoingWebhook) TriggerWordExactMatch(word string) bool {
|
||||
if word == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, trigger := range o.TriggerWords {
|
||||
if trigger == word {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool {
|
||||
if word == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, trigger := range o.TriggerWords {
|
||||
if strings.HasPrefix(word, trigger) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *OutgoingWebhook) GetTriggerWord(word string, isExactMatch bool) (triggerWord string) {
|
||||
if word == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if isExactMatch {
|
||||
for _, trigger := range o.TriggerWords {
|
||||
if trigger == word {
|
||||
triggerWord = trigger
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, trigger := range o.TriggerWords {
|
||||
if strings.HasPrefix(word, trigger) {
|
||||
triggerWord = trigger
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return triggerWord
|
||||
}
|
||||
31
vendor/github.com/mattermost/mattermost/server/public/model/permalink.go
generated
vendored
Normal file
31
vendor/github.com/mattermost/mattermost/server/public/model/permalink.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type Permalink struct {
|
||||
PreviewPost *PreviewPost `json:"preview_post"`
|
||||
}
|
||||
|
||||
type PreviewPost struct {
|
||||
PostID string `json:"post_id"`
|
||||
Post *Post `json:"post"`
|
||||
TeamName string `json:"team_name"`
|
||||
ChannelDisplayName string `json:"channel_display_name"`
|
||||
ChannelType ChannelType `json:"channel_type"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
}
|
||||
|
||||
func NewPreviewPost(post *Post, team *Team, channel *Channel) *PreviewPost {
|
||||
if post == nil {
|
||||
return nil
|
||||
}
|
||||
return &PreviewPost{
|
||||
PostID: post.Id,
|
||||
Post: post,
|
||||
TeamName: team.Name,
|
||||
ChannelDisplayName: channel.DisplayName,
|
||||
ChannelType: channel.Type,
|
||||
ChannelID: channel.Id,
|
||||
}
|
||||
}
|
||||
2566
vendor/github.com/mattermost/mattermost/server/public/model/permission.go
generated
vendored
Normal file
2566
vendor/github.com/mattermost/mattermost/server/public/model/permission.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
28
vendor/github.com/mattermost/mattermost/server/public/model/plugin_cluster_event.go
generated
vendored
Normal file
28
vendor/github.com/mattermost/mattermost/server/public/model/plugin_cluster_event.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
PluginClusterEventSendTypeReliable = ClusterSendReliable
|
||||
PluginClusterEventSendTypeBestEffort = ClusterSendBestEffort
|
||||
)
|
||||
|
||||
// PluginClusterEvent is used to allow intra-cluster plugin communication.
|
||||
type PluginClusterEvent struct {
|
||||
// Id is the unique identifier for the event.
|
||||
Id string
|
||||
// Data is the event payload.
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// PluginClusterEventSendOptions defines some properties that apply when sending
|
||||
// plugin events across a cluster.
|
||||
type PluginClusterEventSendOptions struct {
|
||||
// SendType defines the type of communication channel used to send the event.
|
||||
SendType string
|
||||
// TargetId identifies the cluster node to which the event should be sent.
|
||||
// It should match the cluster id of the receiving instance.
|
||||
// If empty, the event gets broadcasted to all other nodes.
|
||||
TargetId string
|
||||
}
|
||||
13
vendor/github.com/mattermost/mattermost/server/public/model/plugin_constants.go
generated
vendored
Normal file
13
vendor/github.com/mattermost/mattermost/server/public/model/plugin_constants.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
PluginIdPlaybooks = "playbooks"
|
||||
PluginIdFocalboard = "focalboard"
|
||||
PluginIdApps = "com.mattermost.apps"
|
||||
PluginIdCalls = "com.mattermost.calls"
|
||||
PluginIdNPS = "com.mattermost.nps"
|
||||
PluginIdChannelExport = "com.mattermost.plugin-channel-export"
|
||||
)
|
||||
9
vendor/github.com/mattermost/mattermost/server/public/model/plugin_event_data.go
generated
vendored
Normal file
9
vendor/github.com/mattermost/mattermost/server/public/model/plugin_event_data.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
// PluginEventData used to notify peers about plugin changes.
|
||||
type PluginEventData struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
33
vendor/github.com/mattermost/mattermost/server/public/model/plugin_key_value.go
generated
vendored
Normal file
33
vendor/github.com/mattermost/mattermost/server/public/model/plugin_key_value.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
KeyValuePluginIdMaxRunes = 190
|
||||
KeyValueKeyMaxRunes = 150
|
||||
)
|
||||
|
||||
type PluginKeyValue struct {
|
||||
PluginId string `json:"plugin_id"`
|
||||
Key string `json:"key" db:"PKey"`
|
||||
Value []byte `json:"value" db:"PValue"`
|
||||
ExpireAt int64 `json:"expire_at"`
|
||||
}
|
||||
|
||||
func (kv *PluginKeyValue) IsValid() *AppError {
|
||||
if kv.PluginId == "" || utf8.RuneCountInString(kv.PluginId) > KeyValuePluginIdMaxRunes {
|
||||
return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.plugin_id.app_error", map[string]any{"Max": KeyValueKeyMaxRunes, "Min": 0}, "key="+kv.Key, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if kv.Key == "" || utf8.RuneCountInString(kv.Key) > KeyValueKeyMaxRunes {
|
||||
return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.key.app_error", map[string]any{"Max": KeyValueKeyMaxRunes, "Min": 0}, "key="+kv.Key, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
47
vendor/github.com/mattermost/mattermost/server/public/model/plugin_kvset_options.go
generated
vendored
Normal file
47
vendor/github.com/mattermost/mattermost/server/public/model/plugin_kvset_options.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// PluginKVSetOptions contains information on how to store a value in the plugin KV store.
|
||||
type PluginKVSetOptions struct {
|
||||
Atomic bool // Only store the value if the current value matches the oldValue
|
||||
OldValue []byte // The value to compare with the current value. Only used when Atomic is true
|
||||
ExpireInSeconds int64 // Set an expire counter
|
||||
}
|
||||
|
||||
// IsValid returns nil if the chosen options are valid.
|
||||
func (opt *PluginKVSetOptions) IsValid() *AppError {
|
||||
if !opt.Atomic && opt.OldValue != nil {
|
||||
return NewAppError(
|
||||
"PluginKVSetOptions.IsValid",
|
||||
"model.plugin_kvset_options.is_valid.old_value.app_error",
|
||||
nil,
|
||||
"",
|
||||
http.StatusBadRequest,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPluginKeyValueFromOptions return a PluginKeyValue given a pluginID, a KV pair and options.
|
||||
func NewPluginKeyValueFromOptions(pluginId, key string, value []byte, opt PluginKVSetOptions) (*PluginKeyValue, *AppError) {
|
||||
expireAt := int64(0)
|
||||
if opt.ExpireInSeconds != 0 {
|
||||
expireAt = GetMillis() + (opt.ExpireInSeconds * 1000)
|
||||
}
|
||||
|
||||
kv := &PluginKeyValue{
|
||||
PluginId: pluginId,
|
||||
Key: key,
|
||||
Value: value,
|
||||
ExpireAt: expireAt,
|
||||
}
|
||||
|
||||
return kv, nil
|
||||
}
|
||||
9
vendor/github.com/mattermost/mattermost/server/public/model/plugin_on_install_event.go
generated
vendored
Normal file
9
vendor/github.com/mattermost/mattermost/server/public/model/plugin_on_install_event.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
// OnInstallEvent is sent to the plugin when it gets installed.
|
||||
type OnInstallEvent struct {
|
||||
UserId string // The user who installed the plugin
|
||||
}
|
||||
59
vendor/github.com/mattermost/mattermost/server/public/model/plugin_reattach.go
generated
vendored
Normal file
59
vendor/github.com/mattermost/mattermost/server/public/model/plugin_reattach.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
// PluginReattachConfig is a serializable version of go-plugin's ReattachConfig.
|
||||
type PluginReattachConfig struct {
|
||||
Protocol string
|
||||
ProtocolVersion int
|
||||
Addr net.UnixAddr
|
||||
Pid int
|
||||
Test bool
|
||||
}
|
||||
|
||||
func NewPluginReattachConfig(pluginReattachmentConfig *plugin.ReattachConfig) *PluginReattachConfig {
|
||||
return &PluginReattachConfig{
|
||||
Protocol: string(pluginReattachmentConfig.Protocol),
|
||||
ProtocolVersion: pluginReattachmentConfig.ProtocolVersion,
|
||||
Addr: net.UnixAddr{
|
||||
Name: pluginReattachmentConfig.Addr.String(),
|
||||
Net: pluginReattachmentConfig.Addr.Network(),
|
||||
},
|
||||
Pid: pluginReattachmentConfig.Pid,
|
||||
Test: pluginReattachmentConfig.Test,
|
||||
}
|
||||
}
|
||||
|
||||
func (prc *PluginReattachConfig) ToHashicorpPluginReattachmentConfig() *plugin.ReattachConfig {
|
||||
addr := prc.Addr
|
||||
|
||||
return &plugin.ReattachConfig{
|
||||
Protocol: plugin.Protocol(prc.Protocol),
|
||||
ProtocolVersion: prc.ProtocolVersion,
|
||||
Addr: &addr,
|
||||
Pid: prc.Pid,
|
||||
ReattachFunc: nil,
|
||||
Test: prc.Test,
|
||||
}
|
||||
}
|
||||
|
||||
type PluginReattachRequest struct {
|
||||
Manifest *Manifest
|
||||
PluginReattachConfig *PluginReattachConfig
|
||||
}
|
||||
|
||||
func (prr *PluginReattachRequest) IsValid() *AppError {
|
||||
if prr.Manifest == nil {
|
||||
return NewAppError("PluginReattachRequest.IsValid", "plugin_reattach_request.is_valid.manifest.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
if prr.PluginReattachConfig == nil {
|
||||
return NewAppError("PluginReattachRequest.IsValid", "plugin_reattach_request.is_valid.plugin_reattach_config.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
27
vendor/github.com/mattermost/mattermost/server/public/model/plugin_status.go
generated
vendored
Normal file
27
vendor/github.com/mattermost/mattermost/server/public/model/plugin_status.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
PluginStateNotRunning = 0
|
||||
PluginStateStarting = 1 // unused by server
|
||||
PluginStateRunning = 2
|
||||
PluginStateFailedToStart = 3
|
||||
PluginStateFailedToStayRunning = 4
|
||||
PluginStateStopping = 5 // unused by server
|
||||
)
|
||||
|
||||
// PluginStatus provides a cluster-aware view of installed plugins.
|
||||
type PluginStatus struct {
|
||||
PluginId string `json:"plugin_id"`
|
||||
ClusterId string `json:"cluster_id"`
|
||||
PluginPath string `json:"plugin_path"`
|
||||
State int `json:"state"`
|
||||
Error string `json:"error"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type PluginStatuses []*PluginStatus
|
||||
40
vendor/github.com/mattermost/mattermost/server/public/model/plugin_valid.go
generated
vendored
Normal file
40
vendor/github.com/mattermost/mattermost/server/public/model/plugin_valid.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
MinIdLength = 3
|
||||
MaxIdLength = 190
|
||||
ValidIdRegex = `^[a-zA-Z0-9-_\.]+$`
|
||||
)
|
||||
|
||||
// ValidId constrains the set of valid plugin identifiers:
|
||||
//
|
||||
// ^[a-zA-Z0-9-_\.]+
|
||||
var validId *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
validId = regexp.MustCompile(ValidIdRegex)
|
||||
}
|
||||
|
||||
// IsValidPluginId verifies that the plugin id has a minimum length of 3, maximum length of 190, and
|
||||
// contains only alphanumeric characters, dashes, underscores and periods.
|
||||
//
|
||||
// These constraints are necessary since the plugin id is used as part of a filesystem path.
|
||||
func IsValidPluginId(id string) bool {
|
||||
if utf8.RuneCountInString(id) < MinIdLength {
|
||||
return false
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(id) > MaxIdLength {
|
||||
return false
|
||||
}
|
||||
|
||||
return validId.MatchString(id)
|
||||
}
|
||||
13
vendor/github.com/mattermost/mattermost/server/public/model/plugins_response.go
generated
vendored
Normal file
13
vendor/github.com/mattermost/mattermost/server/public/model/plugins_response.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type PluginInfo struct {
|
||||
Manifest
|
||||
}
|
||||
|
||||
type PluginsResponse struct {
|
||||
Active []*PluginInfo `json:"active"`
|
||||
Inactive []*PluginInfo `json:"inactive"`
|
||||
}
|
||||
907
vendor/github.com/mattermost/mattermost/server/public/model/post.go
generated
vendored
Normal file
907
vendor/github.com/mattermost/mattermost/server/public/model/post.go
generated
vendored
Normal file
@@ -0,0 +1,907 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/shared/markdown"
|
||||
)
|
||||
|
||||
const (
|
||||
PostSystemMessagePrefix = "system_"
|
||||
PostTypeDefault = ""
|
||||
PostTypeSlackAttachment = "slack_attachment"
|
||||
PostTypeSystemGeneric = "system_generic"
|
||||
PostTypeJoinLeave = "system_join_leave" // Deprecated, use PostJoinChannel or PostLeaveChannel instead
|
||||
PostTypeJoinChannel = "system_join_channel"
|
||||
PostTypeGuestJoinChannel = "system_guest_join_channel"
|
||||
PostTypeLeaveChannel = "system_leave_channel"
|
||||
PostTypeJoinTeam = "system_join_team"
|
||||
PostTypeLeaveTeam = "system_leave_team"
|
||||
PostTypeAutoResponder = "system_auto_responder"
|
||||
PostTypeAddRemove = "system_add_remove" // Deprecated, use PostAddToChannel or PostRemoveFromChannel instead
|
||||
PostTypeAddToChannel = "system_add_to_channel"
|
||||
PostTypeAddGuestToChannel = "system_add_guest_to_chan"
|
||||
PostTypeRemoveFromChannel = "system_remove_from_channel"
|
||||
PostTypeMoveChannel = "system_move_channel"
|
||||
PostTypeAddToTeam = "system_add_to_team"
|
||||
PostTypeRemoveFromTeam = "system_remove_from_team"
|
||||
PostTypeHeaderChange = "system_header_change"
|
||||
PostTypeDisplaynameChange = "system_displayname_change"
|
||||
PostTypeConvertChannel = "system_convert_channel"
|
||||
PostTypePurposeChange = "system_purpose_change"
|
||||
PostTypeChannelDeleted = "system_channel_deleted"
|
||||
PostTypeChannelRestored = "system_channel_restored"
|
||||
PostTypeEphemeral = "system_ephemeral"
|
||||
PostTypeChangeChannelPrivacy = "system_change_chan_privacy"
|
||||
PostTypeWrangler = "system_wrangler"
|
||||
PostTypeGMConvertedToChannel = "system_gm_to_channel"
|
||||
PostTypeAddBotTeamsChannels = "add_bot_teams_channels"
|
||||
PostTypeMe = "me"
|
||||
PostCustomTypePrefix = "custom_"
|
||||
PostTypeReminder = "reminder"
|
||||
|
||||
PostFileidsMaxRunes = 300
|
||||
PostFilenamesMaxRunes = 4000
|
||||
PostHashtagsMaxRunes = 1000
|
||||
PostMessageMaxRunesV1 = 4000
|
||||
PostMessageMaxBytesV2 = 65535 // Maximum size of a TEXT column in MySQL
|
||||
PostMessageMaxRunesV2 = PostMessageMaxBytesV2 / 4 // Assume a worst-case representation
|
||||
PostPropsMaxRunes = 800000
|
||||
PostPropsMaxUserRunes = PostPropsMaxRunes - 40000 // Leave some room for system / pre-save modifications
|
||||
|
||||
PropsAddChannelMember = "add_channel_member"
|
||||
|
||||
PostPropsAddedUserId = "addedUserId"
|
||||
PostPropsDeleteBy = "deleteBy"
|
||||
PostPropsOverrideIconURL = "override_icon_url"
|
||||
PostPropsOverrideIconEmoji = "override_icon_emoji"
|
||||
PostPropsOverrideUsername = "override_username"
|
||||
PostPropsFromWebhook = "from_webhook"
|
||||
PostPropsFromBot = "from_bot"
|
||||
PostPropsFromOAuthApp = "from_oauth_app"
|
||||
PostPropsWebhookDisplayName = "webhook_display_name"
|
||||
PostPropsMentionHighlightDisabled = "mentionHighlightDisabled"
|
||||
PostPropsGroupHighlightDisabled = "disable_group_highlight"
|
||||
PostPropsPreviewedPost = "previewed_post"
|
||||
|
||||
PostPriorityUrgent = "urgent"
|
||||
PostPropsRequestedAck = "requested_ack"
|
||||
PostPropsPersistentNotifications = "persistent_notifications"
|
||||
)
|
||||
|
||||
type Post struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
EditAt int64 `json:"edit_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
IsPinned bool `json:"is_pinned"`
|
||||
UserId string `json:"user_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
RootId string `json:"root_id"`
|
||||
OriginalId string `json:"original_id"`
|
||||
|
||||
Message string `json:"message"`
|
||||
// MessageSource will contain the message as submitted by the user if Message has been modified
|
||||
// by Mattermost for presentation (e.g if an image proxy is being used). It should be used to
|
||||
// populate edit boxes if present.
|
||||
MessageSource string `json:"message_source,omitempty"`
|
||||
|
||||
Type string `json:"type"`
|
||||
propsMu sync.RWMutex `db:"-"` // Unexported mutex used to guard Post.Props.
|
||||
Props StringInterface `json:"props"` // Deprecated: use GetProps()
|
||||
Hashtags string `json:"hashtags"`
|
||||
Filenames StringArray `json:"-"` // Deprecated, do not use this field any more
|
||||
FileIds StringArray `json:"file_ids,omitempty"`
|
||||
PendingPostId string `json:"pending_post_id"`
|
||||
HasReactions bool `json:"has_reactions,omitempty"`
|
||||
RemoteId *string `json:"remote_id,omitempty"`
|
||||
|
||||
// Transient data populated before sending a post to the client
|
||||
ReplyCount int64 `json:"reply_count"`
|
||||
LastReplyAt int64 `json:"last_reply_at"`
|
||||
Participants []*User `json:"participants"`
|
||||
IsFollowing *bool `json:"is_following,omitempty"` // for root posts in collapsed thread mode indicates if the current user is following this thread
|
||||
Metadata *PostMetadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
func (o *Post) Auditable() map[string]interface{} {
|
||||
var metaData map[string]any
|
||||
if o.Metadata != nil {
|
||||
metaData = o.Metadata.Auditable()
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"id": o.Id,
|
||||
"create_at": o.CreateAt,
|
||||
"update_at": o.UpdateAt,
|
||||
"edit_at": o.EditAt,
|
||||
"delete_at": o.DeleteAt,
|
||||
"is_pinned": o.IsPinned,
|
||||
"user_id": o.UserId,
|
||||
"channel_id": o.ChannelId,
|
||||
"root_id": o.RootId,
|
||||
"original_id": o.OriginalId,
|
||||
"type": o.Type,
|
||||
"props": o.GetProps(),
|
||||
"file_ids": o.FileIds,
|
||||
"pending_post_id": o.PendingPostId,
|
||||
"remote_id": o.RemoteId,
|
||||
"reply_count": o.ReplyCount,
|
||||
"last_reply_at": o.LastReplyAt,
|
||||
"is_following": o.IsFollowing,
|
||||
"metadata": metaData,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Post) LogClone() any {
|
||||
return o.Auditable()
|
||||
}
|
||||
|
||||
type PostEphemeral struct {
|
||||
UserID string `json:"user_id"`
|
||||
Post *Post `json:"post"`
|
||||
}
|
||||
|
||||
type PostPatch struct {
|
||||
IsPinned *bool `json:"is_pinned"`
|
||||
Message *string `json:"message"`
|
||||
Props *StringInterface `json:"props"`
|
||||
FileIds *StringArray `json:"file_ids"`
|
||||
HasReactions *bool `json:"has_reactions"`
|
||||
}
|
||||
|
||||
type PostReminder struct {
|
||||
TargetTime int64 `json:"target_time"`
|
||||
// These fields are only used internally for interacting with DB.
|
||||
PostId string `json:",omitempty"`
|
||||
UserId string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type PostPriority struct {
|
||||
Priority *string `json:"priority"`
|
||||
RequestedAck *bool `json:"requested_ack"`
|
||||
PersistentNotifications *bool `json:"persistent_notifications"`
|
||||
// These fields are only used internally for interacting with DB.
|
||||
PostId string `json:",omitempty"`
|
||||
ChannelId string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type PostPersistentNotifications struct {
|
||||
PostId string
|
||||
CreateAt int64
|
||||
LastSentAt int64
|
||||
DeleteAt int64
|
||||
SentCount int16
|
||||
}
|
||||
|
||||
type GetPersistentNotificationsPostsParams struct {
|
||||
MaxTime int64
|
||||
MaxSentCount int16
|
||||
PerPage int
|
||||
}
|
||||
|
||||
type MoveThreadParams struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
}
|
||||
|
||||
type SearchParameter struct {
|
||||
Terms *string `json:"terms"`
|
||||
IsOrSearch *bool `json:"is_or_search"`
|
||||
TimeZoneOffset *int `json:"time_zone_offset"`
|
||||
Page *int `json:"page"`
|
||||
PerPage *int `json:"per_page"`
|
||||
IncludeDeletedChannels *bool `json:"include_deleted_channels"`
|
||||
}
|
||||
|
||||
type AnalyticsPostCountsOptions struct {
|
||||
TeamId string
|
||||
BotsOnly bool
|
||||
YesterdayOnly bool
|
||||
}
|
||||
|
||||
func (o *PostPatch) WithRewrittenImageURLs(f func(string) string) *PostPatch {
|
||||
pCopy := *o //nolint:revive
|
||||
if pCopy.Message != nil {
|
||||
*pCopy.Message = RewriteImageURLs(*o.Message, f)
|
||||
}
|
||||
return &pCopy
|
||||
}
|
||||
|
||||
func (o *PostPatch) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"is_pinned": o.IsPinned,
|
||||
"props": o.Props,
|
||||
"file_ids": o.FileIds,
|
||||
"has_reactions": o.HasReactions,
|
||||
}
|
||||
}
|
||||
|
||||
type PostForExport struct {
|
||||
Post
|
||||
TeamName string
|
||||
ChannelName string
|
||||
Username string
|
||||
ReplyCount int
|
||||
}
|
||||
|
||||
type DirectPostForExport struct {
|
||||
Post
|
||||
User string
|
||||
ChannelMembers *[]string
|
||||
}
|
||||
|
||||
type ReplyForExport struct {
|
||||
Post
|
||||
Username string
|
||||
}
|
||||
|
||||
type PostForIndexing struct {
|
||||
Post
|
||||
TeamId string `json:"team_id"`
|
||||
ParentCreateAt *int64 `json:"parent_create_at"`
|
||||
}
|
||||
|
||||
type FileForIndexing struct {
|
||||
FileInfo
|
||||
ChannelId string `json:"channel_id"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// ShallowCopy is an utility function to shallow copy a Post to the given
|
||||
// destination without touching the internal RWMutex.
|
||||
func (o *Post) ShallowCopy(dst *Post) error {
|
||||
if dst == nil {
|
||||
return errors.New("dst cannot be nil")
|
||||
}
|
||||
o.propsMu.RLock()
|
||||
defer o.propsMu.RUnlock()
|
||||
dst.propsMu.Lock()
|
||||
defer dst.propsMu.Unlock()
|
||||
dst.Id = o.Id
|
||||
dst.CreateAt = o.CreateAt
|
||||
dst.UpdateAt = o.UpdateAt
|
||||
dst.EditAt = o.EditAt
|
||||
dst.DeleteAt = o.DeleteAt
|
||||
dst.IsPinned = o.IsPinned
|
||||
dst.UserId = o.UserId
|
||||
dst.ChannelId = o.ChannelId
|
||||
dst.RootId = o.RootId
|
||||
dst.OriginalId = o.OriginalId
|
||||
dst.Message = o.Message
|
||||
dst.MessageSource = o.MessageSource
|
||||
dst.Type = o.Type
|
||||
dst.Props = o.Props
|
||||
dst.Hashtags = o.Hashtags
|
||||
dst.Filenames = o.Filenames
|
||||
dst.FileIds = o.FileIds
|
||||
dst.PendingPostId = o.PendingPostId
|
||||
dst.HasReactions = o.HasReactions
|
||||
dst.ReplyCount = o.ReplyCount
|
||||
dst.Participants = o.Participants
|
||||
dst.LastReplyAt = o.LastReplyAt
|
||||
dst.Metadata = o.Metadata
|
||||
if o.IsFollowing != nil {
|
||||
dst.IsFollowing = NewBool(*o.IsFollowing)
|
||||
}
|
||||
dst.RemoteId = o.RemoteId
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clone shallowly copies the post and returns the copy.
|
||||
func (o *Post) Clone() *Post {
|
||||
pCopy := &Post{} //nolint:revive
|
||||
o.ShallowCopy(pCopy)
|
||||
return pCopy
|
||||
}
|
||||
|
||||
func (o *Post) ToJSON() (string, error) {
|
||||
pCopy := o.Clone() //nolint:revive
|
||||
pCopy.StripActionIntegrations()
|
||||
b, err := json.Marshal(pCopy)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func (o *Post) EncodeJSON(w io.Writer) error {
|
||||
o.StripActionIntegrations()
|
||||
return json.NewEncoder(w).Encode(o)
|
||||
}
|
||||
|
||||
type GetPostsSinceOptions struct {
|
||||
UserId string
|
||||
ChannelId string
|
||||
Time int64
|
||||
SkipFetchThreads bool
|
||||
CollapsedThreads bool
|
||||
CollapsedThreadsExtended bool
|
||||
SortAscending bool
|
||||
}
|
||||
|
||||
type GetPostsSinceForSyncCursor struct {
|
||||
LastPostUpdateAt int64
|
||||
LastPostUpdateID string
|
||||
LastPostCreateAt int64
|
||||
LastPostCreateID string
|
||||
}
|
||||
|
||||
func (c GetPostsSinceForSyncCursor) IsEmpty() bool {
|
||||
return c.LastPostCreateAt == 0 && c.LastPostCreateID == "" && c.LastPostUpdateAt == 0 && c.LastPostUpdateID == ""
|
||||
}
|
||||
|
||||
type GetPostsSinceForSyncOptions struct {
|
||||
ChannelId string
|
||||
ExcludeRemoteId string
|
||||
IncludeDeleted bool
|
||||
SinceCreateAt bool // determines whether the cursor will be based on CreateAt or UpdateAt
|
||||
}
|
||||
|
||||
type GetPostsOptions struct {
|
||||
UserId string
|
||||
ChannelId string
|
||||
PostId string
|
||||
Page int
|
||||
PerPage int
|
||||
SkipFetchThreads bool
|
||||
CollapsedThreads bool
|
||||
CollapsedThreadsExtended bool
|
||||
FromPost string // PostId after which to send the items
|
||||
FromCreateAt int64 // CreateAt after which to send the items
|
||||
Direction string // Only accepts up|down. Indicates the order in which to send the items.
|
||||
IncludeDeleted bool
|
||||
IncludePostPriority bool
|
||||
}
|
||||
|
||||
type PostCountOptions struct {
|
||||
// Only include posts on a specific team. "" for any team.
|
||||
TeamId string
|
||||
MustHaveFile bool
|
||||
MustHaveHashtag bool
|
||||
ExcludeDeleted bool
|
||||
ExcludeSystemPosts bool
|
||||
UsersPostsOnly bool
|
||||
// AllowFromCache looks up cache only when ExcludeDeleted and UsersPostsOnly are true and rest are falsy.
|
||||
AllowFromCache bool
|
||||
SincePostID string
|
||||
SinceUpdateAt int64
|
||||
}
|
||||
|
||||
func (o *Post) Etag() string {
|
||||
return Etag(o.Id, o.UpdateAt)
|
||||
}
|
||||
|
||||
func (o *Post) IsValid(maxPostSize int) *AppError {
|
||||
if !IsValidId(o.Id) {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if o.UpdateAt == 0 {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.UserId) {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.ChannelId) {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !(IsValidId(o.RootId) || o.RootId == "") {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.root_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !(len(o.OriginalId) == 26 || o.OriginalId == "") {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.original_id.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(o.Message) > maxPostSize {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.msg.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(o.Hashtags) > PostHashtagsMaxRunes {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.hashtags.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
switch o.Type {
|
||||
case
|
||||
PostTypeDefault,
|
||||
PostTypeSystemGeneric,
|
||||
PostTypeJoinLeave,
|
||||
PostTypeAutoResponder,
|
||||
PostTypeAddRemove,
|
||||
PostTypeJoinChannel,
|
||||
PostTypeGuestJoinChannel,
|
||||
PostTypeLeaveChannel,
|
||||
PostTypeJoinTeam,
|
||||
PostTypeLeaveTeam,
|
||||
PostTypeAddToChannel,
|
||||
PostTypeAddGuestToChannel,
|
||||
PostTypeRemoveFromChannel,
|
||||
PostTypeMoveChannel,
|
||||
PostTypeAddToTeam,
|
||||
PostTypeRemoveFromTeam,
|
||||
PostTypeSlackAttachment,
|
||||
PostTypeHeaderChange,
|
||||
PostTypePurposeChange,
|
||||
PostTypeDisplaynameChange,
|
||||
PostTypeConvertChannel,
|
||||
PostTypeChannelDeleted,
|
||||
PostTypeChannelRestored,
|
||||
PostTypeChangeChannelPrivacy,
|
||||
PostTypeAddBotTeamsChannels,
|
||||
PostTypeReminder,
|
||||
PostTypeMe,
|
||||
PostTypeWrangler,
|
||||
PostTypeGMConvertedToChannel:
|
||||
default:
|
||||
if !strings.HasPrefix(o.Type, PostCustomTypePrefix) {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.type.app_error", nil, "id="+o.Type, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(ArrayToJSON(o.Filenames)) > PostFilenamesMaxRunes {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.filenames.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(ArrayToJSON(o.FileIds)) > PostFileidsMaxRunes {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if utf8.RuneCountInString(StringInterfaceToJSON(o.GetProps())) > PostPropsMaxRunes {
|
||||
return NewAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Post) SanitizeProps() {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
membersToSanitize := []string{
|
||||
PropsAddChannelMember,
|
||||
}
|
||||
|
||||
for _, member := range membersToSanitize {
|
||||
if _, ok := o.GetProps()[member]; ok {
|
||||
o.DelProp(member)
|
||||
}
|
||||
}
|
||||
for _, p := range o.Participants {
|
||||
p.Sanitize(map[string]bool{})
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Post) ContainsIntegrationsReservedProps() []string {
|
||||
return containsIntegrationsReservedProps(o.GetProps())
|
||||
}
|
||||
|
||||
func (o *PostPatch) ContainsIntegrationsReservedProps() []string {
|
||||
if o == nil || o.Props == nil {
|
||||
return nil
|
||||
}
|
||||
return containsIntegrationsReservedProps(*o.Props)
|
||||
}
|
||||
|
||||
func containsIntegrationsReservedProps(props StringInterface) []string {
|
||||
foundProps := []string{}
|
||||
|
||||
if props != nil {
|
||||
reservedProps := []string{
|
||||
PostPropsFromWebhook,
|
||||
PostPropsOverrideUsername,
|
||||
PostPropsWebhookDisplayName,
|
||||
PostPropsOverrideIconURL,
|
||||
PostPropsOverrideIconEmoji,
|
||||
}
|
||||
|
||||
for _, key := range reservedProps {
|
||||
if _, ok := props[key]; ok {
|
||||
foundProps = append(foundProps, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return foundProps
|
||||
}
|
||||
|
||||
func (o *Post) PreSave() {
|
||||
if o.Id == "" {
|
||||
o.Id = NewId()
|
||||
}
|
||||
|
||||
o.OriginalId = ""
|
||||
|
||||
if o.CreateAt == 0 {
|
||||
o.CreateAt = GetMillis()
|
||||
}
|
||||
|
||||
o.UpdateAt = o.CreateAt
|
||||
o.PreCommit()
|
||||
}
|
||||
|
||||
func (o *Post) PreCommit() {
|
||||
if o.GetProps() == nil {
|
||||
o.SetProps(make(map[string]any))
|
||||
}
|
||||
|
||||
if o.Filenames == nil {
|
||||
o.Filenames = []string{}
|
||||
}
|
||||
|
||||
if o.FileIds == nil {
|
||||
o.FileIds = []string{}
|
||||
}
|
||||
|
||||
o.GenerateActionIds()
|
||||
|
||||
// There's a rare bug where the client sends up duplicate FileIds so protect against that
|
||||
o.FileIds = RemoveDuplicateStrings(o.FileIds)
|
||||
}
|
||||
|
||||
func (o *Post) MakeNonNil() {
|
||||
if o.GetProps() == nil {
|
||||
o.SetProps(make(map[string]any))
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Post) DelProp(key string) {
|
||||
o.propsMu.Lock()
|
||||
defer o.propsMu.Unlock()
|
||||
propsCopy := make(map[string]any, len(o.Props)-1)
|
||||
for k, v := range o.Props {
|
||||
propsCopy[k] = v
|
||||
}
|
||||
delete(propsCopy, key)
|
||||
o.Props = propsCopy
|
||||
}
|
||||
|
||||
func (o *Post) AddProp(key string, value any) {
|
||||
o.propsMu.Lock()
|
||||
defer o.propsMu.Unlock()
|
||||
propsCopy := make(map[string]any, len(o.Props)+1)
|
||||
for k, v := range o.Props {
|
||||
propsCopy[k] = v
|
||||
}
|
||||
propsCopy[key] = value
|
||||
o.Props = propsCopy
|
||||
}
|
||||
|
||||
func (o *Post) GetProps() StringInterface {
|
||||
o.propsMu.RLock()
|
||||
defer o.propsMu.RUnlock()
|
||||
return o.Props
|
||||
}
|
||||
|
||||
func (o *Post) SetProps(props StringInterface) {
|
||||
o.propsMu.Lock()
|
||||
defer o.propsMu.Unlock()
|
||||
o.Props = props
|
||||
}
|
||||
|
||||
func (o *Post) GetProp(key string) any {
|
||||
o.propsMu.RLock()
|
||||
defer o.propsMu.RUnlock()
|
||||
return o.Props[key]
|
||||
}
|
||||
|
||||
func (o *Post) IsSystemMessage() bool {
|
||||
return len(o.Type) >= len(PostSystemMessagePrefix) && o.Type[:len(PostSystemMessagePrefix)] == PostSystemMessagePrefix
|
||||
}
|
||||
|
||||
// IsRemote returns true if the post originated on a remote cluster.
|
||||
func (o *Post) IsRemote() bool {
|
||||
return o.RemoteId != nil && *o.RemoteId != ""
|
||||
}
|
||||
|
||||
// GetRemoteID safely returns the remoteID or empty string if not remote.
|
||||
func (o *Post) GetRemoteID() string {
|
||||
if o.RemoteId != nil {
|
||||
return *o.RemoteId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (o *Post) IsJoinLeaveMessage() bool {
|
||||
return o.Type == PostTypeJoinLeave ||
|
||||
o.Type == PostTypeAddRemove ||
|
||||
o.Type == PostTypeJoinChannel ||
|
||||
o.Type == PostTypeLeaveChannel ||
|
||||
o.Type == PostTypeJoinTeam ||
|
||||
o.Type == PostTypeLeaveTeam ||
|
||||
o.Type == PostTypeAddToChannel ||
|
||||
o.Type == PostTypeRemoveFromChannel ||
|
||||
o.Type == PostTypeAddToTeam ||
|
||||
o.Type == PostTypeRemoveFromTeam
|
||||
}
|
||||
|
||||
func (o *Post) Patch(patch *PostPatch) {
|
||||
if patch.IsPinned != nil {
|
||||
o.IsPinned = *patch.IsPinned
|
||||
}
|
||||
|
||||
if patch.Message != nil {
|
||||
o.Message = *patch.Message
|
||||
}
|
||||
|
||||
if patch.Props != nil {
|
||||
newProps := *patch.Props
|
||||
o.SetProps(newProps)
|
||||
}
|
||||
|
||||
if patch.FileIds != nil {
|
||||
o.FileIds = *patch.FileIds
|
||||
}
|
||||
|
||||
if patch.HasReactions != nil {
|
||||
o.HasReactions = *patch.HasReactions
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Post) ChannelMentions() []string {
|
||||
return ChannelMentions(o.Message)
|
||||
}
|
||||
|
||||
// DisableMentionHighlights disables a posts mention highlighting and returns the first channel mention that was present in the message.
|
||||
func (o *Post) DisableMentionHighlights() string {
|
||||
mention, hasMentions := findAtChannelMention(o.Message)
|
||||
if hasMentions {
|
||||
o.AddProp(PostPropsMentionHighlightDisabled, true)
|
||||
}
|
||||
return mention
|
||||
}
|
||||
|
||||
// DisableMentionHighlights disables mention highlighting for a post patch if required.
|
||||
func (o *PostPatch) DisableMentionHighlights() {
|
||||
if o.Message == nil {
|
||||
return
|
||||
}
|
||||
if _, hasMentions := findAtChannelMention(*o.Message); hasMentions {
|
||||
if o.Props == nil {
|
||||
o.Props = &StringInterface{}
|
||||
}
|
||||
(*o.Props)[PostPropsMentionHighlightDisabled] = true
|
||||
}
|
||||
}
|
||||
|
||||
func findAtChannelMention(message string) (mention string, found bool) {
|
||||
re := regexp.MustCompile(`(?i)\B@(channel|all|here)\b`)
|
||||
matched := re.FindStringSubmatch(message)
|
||||
if found = (len(matched) > 0); found {
|
||||
mention = strings.ToLower(matched[0])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Post) Attachments() []*SlackAttachment {
|
||||
if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok {
|
||||
return attachments
|
||||
}
|
||||
var ret []*SlackAttachment
|
||||
if attachments, ok := o.GetProp("attachments").([]any); ok {
|
||||
for _, attachment := range attachments {
|
||||
if enc, err := json.Marshal(attachment); err == nil {
|
||||
var decoded SlackAttachment
|
||||
if json.Unmarshal(enc, &decoded) == nil {
|
||||
// Ignoring nil actions
|
||||
i := 0
|
||||
for _, action := range decoded.Actions {
|
||||
if action != nil {
|
||||
decoded.Actions[i] = action
|
||||
i++
|
||||
}
|
||||
}
|
||||
decoded.Actions = decoded.Actions[:i]
|
||||
|
||||
// Ignoring nil fields
|
||||
i = 0
|
||||
for _, field := range decoded.Fields {
|
||||
if field != nil {
|
||||
decoded.Fields[i] = field
|
||||
i++
|
||||
}
|
||||
}
|
||||
decoded.Fields = decoded.Fields[:i]
|
||||
ret = append(ret, &decoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (o *Post) AttachmentsEqual(input *Post) bool {
|
||||
attachments := o.Attachments()
|
||||
inputAttachments := input.Attachments()
|
||||
|
||||
if len(attachments) != len(inputAttachments) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range attachments {
|
||||
if !attachments[i].Equals(inputAttachments[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var markdownDestinationEscaper = strings.NewReplacer(
|
||||
`\`, `\\`,
|
||||
`<`, `\<`,
|
||||
`>`, `\>`,
|
||||
`(`, `\(`,
|
||||
`)`, `\)`,
|
||||
)
|
||||
|
||||
// WithRewrittenImageURLs returns a new shallow copy of the post where the message has been
|
||||
// rewritten via RewriteImageURLs.
|
||||
func (o *Post) WithRewrittenImageURLs(f func(string) string) *Post {
|
||||
pCopy := o.Clone()
|
||||
pCopy.Message = RewriteImageURLs(o.Message, f)
|
||||
if pCopy.MessageSource == "" && pCopy.Message != o.Message {
|
||||
pCopy.MessageSource = o.Message
|
||||
}
|
||||
return pCopy
|
||||
}
|
||||
|
||||
// RewriteImageURLs takes a message and returns a copy that has all of the image URLs replaced
|
||||
// according to the function f. For each image URL, f will be invoked, and the resulting markdown
|
||||
// will contain the URL returned by that invocation instead.
|
||||
//
|
||||
// Image URLs are destination URLs used in inline images or reference definitions that are used
|
||||
// anywhere in the input markdown as an image.
|
||||
func RewriteImageURLs(message string, f func(string) string) string {
|
||||
if !strings.Contains(message, "![") {
|
||||
return message
|
||||
}
|
||||
|
||||
var ranges []markdown.Range
|
||||
|
||||
markdown.Inspect(message, func(blockOrInline any) bool {
|
||||
switch v := blockOrInline.(type) {
|
||||
case *markdown.ReferenceImage:
|
||||
ranges = append(ranges, v.ReferenceDefinition.RawDestination)
|
||||
case *markdown.InlineImage:
|
||||
ranges = append(ranges, v.RawDestination)
|
||||
default:
|
||||
return true
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if ranges == nil {
|
||||
return message
|
||||
}
|
||||
|
||||
sort.Slice(ranges, func(i, j int) bool {
|
||||
return ranges[i].Position < ranges[j].Position
|
||||
})
|
||||
|
||||
copyRanges := make([]markdown.Range, 0, len(ranges))
|
||||
urls := make([]string, 0, len(ranges))
|
||||
resultLength := len(message)
|
||||
|
||||
start := 0
|
||||
for i, r := range ranges {
|
||||
switch {
|
||||
case i == 0:
|
||||
case r.Position != ranges[i-1].Position:
|
||||
start = ranges[i-1].End
|
||||
default:
|
||||
continue
|
||||
}
|
||||
original := message[r.Position:r.End]
|
||||
replacement := markdownDestinationEscaper.Replace(f(markdown.Unescape(original)))
|
||||
resultLength += len(replacement) - len(original)
|
||||
copyRanges = append(copyRanges, markdown.Range{Position: start, End: r.Position})
|
||||
urls = append(urls, replacement)
|
||||
}
|
||||
|
||||
result := make([]byte, resultLength)
|
||||
|
||||
offset := 0
|
||||
for i, r := range copyRanges {
|
||||
offset += copy(result[offset:], message[r.Position:r.End])
|
||||
offset += copy(result[offset:], urls[i])
|
||||
}
|
||||
copy(result[offset:], message[ranges[len(ranges)-1].End:])
|
||||
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func (o *Post) IsFromOAuthBot() bool {
|
||||
props := o.GetProps()
|
||||
return props["from_webhook"] == "true" && props["override_username"] != ""
|
||||
}
|
||||
|
||||
func (o *Post) ToNilIfInvalid() *Post {
|
||||
if o.Id == "" {
|
||||
return nil
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Post) ForPlugin() *Post {
|
||||
p := o.Clone()
|
||||
p.Metadata = nil
|
||||
if p.Type == fmt.Sprintf("%sup_notification", PostCustomTypePrefix) {
|
||||
p.DelProp("requested_features")
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (o *Post) GetPreviewPost() *PreviewPost {
|
||||
for _, embed := range o.Metadata.Embeds {
|
||||
if embed.Type == PostEmbedPermalink {
|
||||
if previewPost, ok := embed.Data.(*PreviewPost); ok {
|
||||
return previewPost
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Post) GetPreviewedPostProp() string {
|
||||
if val, ok := o.GetProp(PostPropsPreviewedPost).(string); ok {
|
||||
return val
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (o *Post) GetPriority() *PostPriority {
|
||||
if o.Metadata == nil {
|
||||
return nil
|
||||
}
|
||||
return o.Metadata.Priority
|
||||
}
|
||||
|
||||
func (o *Post) GetPersistentNotification() *bool {
|
||||
priority := o.GetPriority()
|
||||
if priority == nil {
|
||||
return nil
|
||||
}
|
||||
return priority.PersistentNotifications
|
||||
}
|
||||
|
||||
func (o *Post) GetRequestedAck() *bool {
|
||||
priority := o.GetPriority()
|
||||
if priority == nil {
|
||||
return nil
|
||||
}
|
||||
return priority.RequestedAck
|
||||
}
|
||||
|
||||
func (o *Post) IsUrgent() bool {
|
||||
postPriority := o.GetPriority()
|
||||
if postPriority == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return *postPriority.Priority == PostPriorityUrgent
|
||||
}
|
||||
|
||||
func (o *Post) CleanPost() *Post {
|
||||
o.Id = ""
|
||||
o.CreateAt = 0
|
||||
o.UpdateAt = 0
|
||||
o.EditAt = 0
|
||||
return o
|
||||
}
|
||||
24
vendor/github.com/mattermost/mattermost/server/public/model/post_acknowledgement.go
generated
vendored
Normal file
24
vendor/github.com/mattermost/mattermost/server/public/model/post_acknowledgement.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import "net/http"
|
||||
|
||||
type PostAcknowledgement struct {
|
||||
UserId string `json:"user_id"`
|
||||
PostId string `json:"post_id"`
|
||||
AcknowledgedAt int64 `json:"acknowledged_at"`
|
||||
}
|
||||
|
||||
func (o *PostAcknowledgement) IsValid() *AppError {
|
||||
if !IsValidId(o.UserId) {
|
||||
return NewAppError("PostAcknowledgement.IsValid", "model.acknowledgement.is_valid.user_id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !IsValidId(o.PostId) {
|
||||
return NewAppError("PostAcknowledgement.IsValid", "model.acknowledgement.is_valid.post_id.app_error", nil, "post_id="+o.PostId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
33
vendor/github.com/mattermost/mattermost/server/public/model/post_embed.go
generated
vendored
Normal file
33
vendor/github.com/mattermost/mattermost/server/public/model/post_embed.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
const (
|
||||
PostEmbedImage PostEmbedType = "image"
|
||||
PostEmbedMessageAttachment PostEmbedType = "message_attachment"
|
||||
PostEmbedOpengraph PostEmbedType = "opengraph"
|
||||
PostEmbedLink PostEmbedType = "link"
|
||||
PostEmbedPermalink PostEmbedType = "permalink"
|
||||
PostEmbedBoards PostEmbedType = "boards"
|
||||
)
|
||||
|
||||
type PostEmbedType string
|
||||
|
||||
type PostEmbed struct {
|
||||
Type PostEmbedType `json:"type"`
|
||||
|
||||
// The URL of the embedded content. Used for image and OpenGraph embeds.
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// Any additional data for the embedded content. Only used for OpenGraph embeds.
|
||||
Data any `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (pe *PostEmbed) Auditable() map[string]any {
|
||||
// filter out embedded content.
|
||||
return map[string]any{
|
||||
"type": pe.Type,
|
||||
"url": pe.URL,
|
||||
}
|
||||
}
|
||||
15
vendor/github.com/mattermost/mattermost/server/public/model/post_info.go
generated
vendored
Normal file
15
vendor/github.com/mattermost/mattermost/server/public/model/post_info.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type PostInfo struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelType ChannelType `json:"channel_type"`
|
||||
ChannelDisplayName string `json:"channel_display_name"`
|
||||
HasJoinedChannel bool `json:"has_joined_channel"`
|
||||
TeamId string `json:"team_id"`
|
||||
TeamType string `json:"team_type"`
|
||||
TeamDisplayName string `json:"team_display_name"`
|
||||
HasJoinedTeam bool `json:"has_joined_team"`
|
||||
}
|
||||
228
vendor/github.com/mattermost/mattermost/server/public/model/post_list.go
generated
vendored
Normal file
228
vendor/github.com/mattermost/mattermost/server/public/model/post_list.go
generated
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type PostList struct {
|
||||
Order []string `json:"order"`
|
||||
Posts map[string]*Post `json:"posts"`
|
||||
NextPostId string `json:"next_post_id"`
|
||||
PrevPostId string `json:"prev_post_id"`
|
||||
// HasNext indicates whether there are more items to be fetched or not.
|
||||
HasNext bool `json:"has_next"`
|
||||
// If there are inaccessible posts, FirstInaccessiblePostTime is the time of the latest inaccessible post
|
||||
FirstInaccessiblePostTime int64 `json:"first_inaccessible_post_time"`
|
||||
}
|
||||
|
||||
func NewPostList() *PostList {
|
||||
return &PostList{
|
||||
Order: make([]string, 0),
|
||||
Posts: make(map[string]*Post),
|
||||
NextPostId: "",
|
||||
PrevPostId: "",
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PostList) Clone() *PostList {
|
||||
orderCopy := make([]string, len(o.Order))
|
||||
postsCopy := make(map[string]*Post)
|
||||
copy(orderCopy, o.Order)
|
||||
for k, v := range o.Posts {
|
||||
postsCopy[k] = v.Clone()
|
||||
}
|
||||
return &PostList{
|
||||
Order: orderCopy,
|
||||
Posts: postsCopy,
|
||||
NextPostId: o.NextPostId,
|
||||
PrevPostId: o.PrevPostId,
|
||||
HasNext: o.HasNext,
|
||||
FirstInaccessiblePostTime: o.FirstInaccessiblePostTime,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PostList) ForPlugin() *PostList {
|
||||
plCopy := o.Clone()
|
||||
for k, p := range plCopy.Posts {
|
||||
plCopy.Posts[k] = p.ForPlugin()
|
||||
}
|
||||
return plCopy
|
||||
}
|
||||
|
||||
func (o *PostList) ToSlice() []*Post {
|
||||
var posts []*Post
|
||||
|
||||
if l := len(o.Posts); l > 0 {
|
||||
posts = make([]*Post, 0, l)
|
||||
}
|
||||
|
||||
for _, id := range o.Order {
|
||||
posts = append(posts, o.Posts[id])
|
||||
}
|
||||
return posts
|
||||
}
|
||||
|
||||
func (o *PostList) WithRewrittenImageURLs(f func(string) string) *PostList {
|
||||
plCopy := *o
|
||||
plCopy.Posts = make(map[string]*Post)
|
||||
for id, post := range o.Posts {
|
||||
plCopy.Posts[id] = post.WithRewrittenImageURLs(f)
|
||||
}
|
||||
return &plCopy
|
||||
}
|
||||
|
||||
func (o *PostList) StripActionIntegrations() {
|
||||
posts := o.Posts
|
||||
o.Posts = make(map[string]*Post)
|
||||
for id, post := range posts {
|
||||
pcopy := post.Clone()
|
||||
pcopy.StripActionIntegrations()
|
||||
o.Posts[id] = pcopy
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PostList) ToJSON() (string, error) {
|
||||
plCopy := *o
|
||||
plCopy.StripActionIntegrations()
|
||||
b, err := json.Marshal(&plCopy)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func (o *PostList) EncodeJSON(w io.Writer) error {
|
||||
o.StripActionIntegrations()
|
||||
return json.NewEncoder(w).Encode(o)
|
||||
}
|
||||
|
||||
func (o *PostList) MakeNonNil() {
|
||||
if o.Order == nil {
|
||||
o.Order = make([]string, 0)
|
||||
}
|
||||
|
||||
if o.Posts == nil {
|
||||
o.Posts = make(map[string]*Post)
|
||||
}
|
||||
|
||||
for _, v := range o.Posts {
|
||||
v.MakeNonNil()
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PostList) AddOrder(id string) {
|
||||
if o.Order == nil {
|
||||
o.Order = make([]string, 0, 128)
|
||||
}
|
||||
|
||||
o.Order = append(o.Order, id)
|
||||
}
|
||||
|
||||
func (o *PostList) AddPost(post *Post) {
|
||||
if o.Posts == nil {
|
||||
o.Posts = make(map[string]*Post)
|
||||
}
|
||||
|
||||
o.Posts[post.Id] = post
|
||||
}
|
||||
|
||||
func (o *PostList) UniqueOrder() {
|
||||
keys := make(map[string]bool)
|
||||
order := []string{}
|
||||
for _, postId := range o.Order {
|
||||
if _, value := keys[postId]; !value {
|
||||
keys[postId] = true
|
||||
order = append(order, postId)
|
||||
}
|
||||
}
|
||||
|
||||
o.Order = order
|
||||
}
|
||||
|
||||
func (o *PostList) Extend(other *PostList) {
|
||||
for postId := range other.Posts {
|
||||
o.AddPost(other.Posts[postId])
|
||||
}
|
||||
|
||||
for _, postId := range other.Order {
|
||||
o.AddOrder(postId)
|
||||
}
|
||||
|
||||
o.UniqueOrder()
|
||||
}
|
||||
|
||||
func (o *PostList) SortByCreateAt() {
|
||||
sort.Slice(o.Order, func(i, j int) bool {
|
||||
return o.Posts[o.Order[i]].CreateAt > o.Posts[o.Order[j]].CreateAt
|
||||
})
|
||||
}
|
||||
|
||||
func (o *PostList) Etag() string {
|
||||
id := "0"
|
||||
var t int64
|
||||
|
||||
for _, v := range o.Posts {
|
||||
if v.UpdateAt > t {
|
||||
t = v.UpdateAt
|
||||
id = v.Id
|
||||
} else if v.UpdateAt == t && v.Id > id {
|
||||
t = v.UpdateAt
|
||||
id = v.Id
|
||||
}
|
||||
}
|
||||
|
||||
orderId := ""
|
||||
if len(o.Order) > 0 {
|
||||
orderId = o.Order[0]
|
||||
}
|
||||
|
||||
return Etag(orderId, id, t)
|
||||
}
|
||||
|
||||
func (o *PostList) IsChannelId(channelId string) bool {
|
||||
for _, v := range o.Posts {
|
||||
if v.ChannelId != channelId {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (o *PostList) BuildWranglerPostList() *WranglerPostList {
|
||||
wpl := &WranglerPostList{}
|
||||
|
||||
o.UniqueOrder()
|
||||
o.SortByCreateAt()
|
||||
posts := o.ToSlice()
|
||||
|
||||
if len(posts) == 0 {
|
||||
// Something was sorted wrong or an empty PostList was provided.
|
||||
return wpl
|
||||
}
|
||||
|
||||
// A separate ID key map to ensure no duplicates.
|
||||
idKeys := make(map[string]bool)
|
||||
|
||||
for i := range posts {
|
||||
p := posts[len(posts)-i-1]
|
||||
|
||||
// Add UserID to metadata if it's new.
|
||||
if _, ok := idKeys[p.UserId]; !ok {
|
||||
idKeys[p.UserId] = true
|
||||
wpl.ThreadUserIDs = append(wpl.ThreadUserIDs, p.UserId)
|
||||
}
|
||||
|
||||
wpl.FileAttachmentCount += int64(len(p.FileIds))
|
||||
|
||||
wpl.Posts = append(wpl.Posts, p)
|
||||
}
|
||||
|
||||
// Set metadata for earliest and latest posts
|
||||
wpl.EarlistPostTimestamp = wpl.RootPost().CreateAt
|
||||
wpl.LatestPostTimestamp = wpl.Posts[wpl.NumPosts()-1].CreateAt
|
||||
|
||||
return wpl
|
||||
}
|
||||
106
vendor/github.com/mattermost/mattermost/server/public/model/post_metadata.go
generated
vendored
Normal file
106
vendor/github.com/mattermost/mattermost/server/public/model/post_metadata.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type PostMetadata struct {
|
||||
// Embeds holds information required to render content embedded in the post. This includes the OpenGraph metadata
|
||||
// for links in the post.
|
||||
Embeds []*PostEmbed `json:"embeds,omitempty"`
|
||||
|
||||
// Emojis holds all custom emojis used in the post or used in reaction to the post.
|
||||
Emojis []*Emoji `json:"emojis,omitempty"`
|
||||
|
||||
// Files holds information about the file attachments on the post.
|
||||
Files []*FileInfo `json:"files,omitempty"`
|
||||
|
||||
// Images holds the dimensions of all external images in the post as a map of the image URL to its dimensions.
|
||||
// This includes image embeds (when the message contains a plaintext link to an image), Markdown images, images
|
||||
// contained in the OpenGraph metadata, and images contained in message attachments. It does not contain
|
||||
// the dimensions of any file attachments as those are stored in FileInfos.
|
||||
Images map[string]*PostImage `json:"images,omitempty"`
|
||||
|
||||
// Reactions holds reactions made to the post.
|
||||
Reactions []*Reaction `json:"reactions,omitempty"`
|
||||
|
||||
// Priority holds info about priority settings for the post.
|
||||
Priority *PostPriority `json:"priority,omitempty"`
|
||||
|
||||
// Acknowledgements holds acknowledgements made by users to the post
|
||||
Acknowledgements []*PostAcknowledgement `json:"acknowledgements,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PostMetadata) Auditable() map[string]any {
|
||||
embeds := make([]map[string]any, 0, len(p.Embeds))
|
||||
for _, pe := range p.Embeds {
|
||||
embeds = append(embeds, pe.Auditable())
|
||||
}
|
||||
if len(embeds) == 0 {
|
||||
embeds = nil
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"embeds": embeds,
|
||||
"emojis": p.Emojis,
|
||||
"files": p.Files,
|
||||
"images": p.Images,
|
||||
"reactions": p.Reactions,
|
||||
"priority": p.Priority,
|
||||
"acknowledgements": p.Acknowledgements,
|
||||
}
|
||||
}
|
||||
|
||||
type PostImage struct {
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
|
||||
// Format is the name of the image format as used by image/go such as "png", "gif", or "jpeg".
|
||||
Format string `json:"format"`
|
||||
|
||||
// FrameCount stores the number of frames in this image, if it is an animated gif. It will be 0 for other formats.
|
||||
FrameCount int `json:"frame_count"`
|
||||
}
|
||||
|
||||
// Copy does a deep copy
|
||||
func (p *PostMetadata) Copy() *PostMetadata {
|
||||
embedsCopy := make([]*PostEmbed, len(p.Embeds))
|
||||
copy(embedsCopy, p.Embeds)
|
||||
|
||||
emojisCopy := make([]*Emoji, len(p.Emojis))
|
||||
copy(emojisCopy, p.Emojis)
|
||||
|
||||
filesCopy := make([]*FileInfo, len(p.Files))
|
||||
copy(filesCopy, p.Files)
|
||||
|
||||
imagesCopy := map[string]*PostImage{}
|
||||
for k, v := range p.Images {
|
||||
imagesCopy[k] = v
|
||||
}
|
||||
|
||||
reactionsCopy := make([]*Reaction, len(p.Reactions))
|
||||
copy(reactionsCopy, p.Reactions)
|
||||
|
||||
acknowledgementsCopy := make([]*PostAcknowledgement, len(p.Acknowledgements))
|
||||
copy(acknowledgementsCopy, p.Acknowledgements)
|
||||
|
||||
var postPriorityCopy *PostPriority
|
||||
if p.Priority != nil {
|
||||
postPriorityCopy = &PostPriority{
|
||||
Priority: p.Priority.Priority,
|
||||
RequestedAck: p.Priority.RequestedAck,
|
||||
PersistentNotifications: p.Priority.PersistentNotifications,
|
||||
PostId: p.Priority.PostId,
|
||||
ChannelId: p.Priority.ChannelId,
|
||||
}
|
||||
}
|
||||
|
||||
return &PostMetadata{
|
||||
Embeds: embedsCopy,
|
||||
Emojis: emojisCopy,
|
||||
Files: filesCopy,
|
||||
Images: imagesCopy,
|
||||
Reactions: reactionsCopy,
|
||||
Priority: postPriorityCopy,
|
||||
Acknowledgements: acknowledgementsCopy,
|
||||
}
|
||||
}
|
||||
41
vendor/github.com/mattermost/mattermost/server/public/model/post_search_results.go
generated
vendored
Normal file
41
vendor/github.com/mattermost/mattermost/server/public/model/post_search_results.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
type PostSearchMatches map[string][]string
|
||||
|
||||
type PostSearchResults struct {
|
||||
*PostList
|
||||
Matches PostSearchMatches `json:"matches"`
|
||||
}
|
||||
|
||||
func MakePostSearchResults(posts *PostList, matches PostSearchMatches) *PostSearchResults {
|
||||
return &PostSearchResults{
|
||||
posts,
|
||||
matches,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PostSearchResults) ToJSON() (string, error) {
|
||||
psCopy := *o
|
||||
psCopy.PostList.StripActionIntegrations()
|
||||
b, err := json.Marshal(&psCopy)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func (o *PostSearchResults) EncodeJSON(w io.Writer) error {
|
||||
o.PostList.StripActionIntegrations()
|
||||
return json.NewEncoder(w).Encode(o)
|
||||
}
|
||||
|
||||
func (o *PostSearchResults) ForPlugin() *PostSearchResults {
|
||||
plCopy := *o
|
||||
plCopy.PostList = plCopy.PostList.ForPlugin()
|
||||
return &plCopy
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user